transclusion of data with jinja2/templates¶
import pidgy.base, jinja2.meta, IPython, sys, traitlets, functools
import pidgy.base, jinja2.meta, IPython, sys, traitlets, functools
minify = lambda x: __import__('htmlmin').minify(x, False, True, True, True, True, True, True)
minify = lambda x: __import__('htmlmin').minify(x, False, True, True, True, True, True, True)
def active_types(shell=None):
shell = shell or IPython.get_ipython()
if shell:
object = list(shell.display_formatter.active_types)
object.insert(object.index('text/html'), object.pop(object.index('text/latex')))
return reversed(object)
return []
def active_types(shell=None):
shell = shell or IPython.get_ipython()
if shell:
object = list(shell.display_formatter.active_types)
object.insert(object.index('text/html'), object.pop(object.index('text/latex')))
return reversed(object)
return []
def environment(shell=None):
environment = __import__('nbconvert').exporters.TemplateExporter().environment
environment.loader.loaders.append(jinja2.FileSystemLoader('.'))
environment.display_manager = DisplayManager()
environment.finalize = Finalize(parent=shell or IPython.get_ipython())
return environment
def environment(shell=None):
environment = __import__('nbconvert').exporters.TemplateExporter().environment
environment.loader.loaders.append(jinja2.FileSystemLoader('.'))
environment.display_manager = DisplayManager()
environment.finalize = Finalize(parent=shell or IPython.get_ipython())
return environment
class MarkdownDisplay(pidgy.base.Display):
body = traitlets.Unicode()
vars = traitlets.Set()
template = traitlets.Any()
_display = traitlets.Any()
@traitlets.default('template')
def _default_template(self):
return self.environment.from_string(self.body)
@traitlets.default('vars')
def _default_vars(self):
return jinja2.meta.find_undeclared_variables(self.template.environment.parse(self.body))
def render(self, **kwargs):
return IPython.display.Markdown(self.template.render(**kwargs))
class MarkdownDisplay(pidgy.base.Display):
body = traitlets.Unicode()
vars = traitlets.Set()
template = traitlets.Any()
_display = traitlets.Any()
@traitlets.default('template')
def _default_template(self):
return self.environment.from_string(self.body)
@traitlets.default('vars')
def _default_vars(self):
return jinja2.meta.find_undeclared_variables(self.template.environment.parse(self.body))
def render(self, **kwargs):
return IPython.display.Markdown(self.template.render(**kwargs))
class DisplayManager(pidgy.base.Trait):
display = traitlets.Dict()
state = traitlets.Dict()
widgets = traitlets.List()
def pre_execute(self):
deleted = getattr(self.parent, '_last_parent', {}).get('metadata', {}).get('deletedCells', [])
for key, displays in self.display.items() if deleted else []:
self.display[key] = [
x for x in displays if x._display and x._display.display_id not in deleted
]
def append(self, object):
for key in object.vars:
self.display[key] = self.display.get(key, [])
self.display[key].append(object)
self.state[key] = self.parent.user_ns.get(key, None)
def pop(self, object):
for key, values in self.display.items():
self.display[key] = [x for x in values if x is not object]
def _post_execute_widget(self, object, change):
with object.hold_trait_notifications():
self.post_execute()
def post_execute(self):
if not self.enabled: return
update = {
x: self.parent.user_ns.get(x, None) for x in self.display
if isinteractive(self.parent.user_ns.get(x, None)) or
self.parent.user_ns.get(x, None) is not self.state.get(x, None)
}
for key, object in update.items():
if isinteractive(object) and object not in self.widgets:
object.observe(functools.partial(self._post_execute_widget, object))
self.widgets += [object]
self.state.update(update)
for object in set(
sum([self.display[x] for x in update], [])
):
try:
object.update(**self.state)
except Exception as e:
self.pop(object)
sys.stderr.writelines(str(self.state))
sys.stderr.writelines(str(e).splitlines())
class DisplayManager(pidgy.base.Trait):
display = traitlets.Dict()
state = traitlets.Dict()
widgets = traitlets.List()
def pre_execute(self):
deleted = getattr(self.parent, '_last_parent', {}).get('metadata', {}).get('deletedCells', [])
for key, displays in self.display.items() if deleted else []:
self.display[key] = [
x for x in displays if x._display and x._display.display_id not in deleted
]
def append(self, object):
for key in object.vars:
self.display[key] = self.display.get(key, [])
self.display[key].append(object)
self.state[key] = self.parent.user_ns.get(key, None)
def pop(self, object):
for key, values in self.display.items():
self.display[key] = [x for x in values if x is not object]
def _post_execute_widget(self, object, change):
with object.hold_trait_notifications():
self.post_execute()
def post_execute(self):
if not self.enabled: return
update = {
x: self.parent.user_ns.get(x, None) for x in self.display
if isinteractive(self.parent.user_ns.get(x, None)) or
self.parent.user_ns.get(x, None) is not self.state.get(x, None)
}
for key, object in update.items():
if isinteractive(object) and object not in self.widgets:
object.observe(functools.partial(self._post_execute_widget, object))
self.widgets += [object]
self.state.update(update)
for object in set(
sum([self.display[x] for x in update], [])
):
try:
object.update(**self.state)
except Exception as e:
self.pop(object)
sys.stderr.writelines(str(self.state))
sys.stderr.writelines(str(e).splitlines())
class Finalize(pidgy.base.Trait):
def normalize(self, key, object, metadata):
if key.startswith('image'):
if 'svg' in key: return minify(object)
width, height = metadata.get(key, {}).get('width'), metadata.get(key, {}).get('height')
if isinstance(object, bytes):
object = __import__('base64').b64encode(object).decode('utf-8')
object = F"""<img src="data:image/{key.partition('/')[2]};base64,{object}"/>"""
if key == 'text/html': object = minify(object)
return object
def __call__(self, object):
datum = self.parent.display_formatter.format(object)
data, metadata = datum if isinstance(datum, tuple) else (datum, {})
try: key = next(filter(data.__contains__, active_types(self.parent)))
except StopIteration: return str(object)
if key == 'text/plain': return str(object)
return self.normalize(key, data[key], metadata)
class Finalize(pidgy.base.Trait):
def normalize(self, key, object, metadata):
if key.startswith('image'):
if 'svg' in key: return minify(object)
width, height = metadata.get(key, {}).get('width'), metadata.get(key, {}).get('height')
if isinstance(object, bytes):
object = __import__('base64').b64encode(object).decode('utf-8')
object = F"""<img src="data:image/{key.partition('/')[2]};base64,{object}"/>"""
if key == 'text/html': object = minify(object)
return object
def __call__(self, object):
datum = self.parent.display_formatter.format(object)
data, metadata = datum if isinstance(datum, tuple) else (datum, {})
try: key = next(filter(data.__contains__, active_types(self.parent)))
except StopIteration: return str(object)
if key == 'text/plain': return str(object)
return self.normalize(key, data[key], metadata)
def iswidget(object):
if 'ipywidgets' in sys.modules:
if isinstance(object, __import__('ipywidgets').Widget):
return True
return False
def ispanel(object):
if 'param' in sys.modules:
if isinstance(object, __import__('param').Parameterized):
return True
return False
def isinteractive(object):
return iswidget(object) | ispanel(object)
def iswidget(object):
if 'ipywidgets' in sys.modules:
if isinstance(object, __import__('ipywidgets').Widget):
return True
return False
def ispanel(object):
if 'param' in sys.modules:
if isinstance(object, __import__('param').Parameterized):
return True
return False
def isinteractive(object):
return iswidget(object) | ispanel(object)