from traitlets import Any, Unicode, List, Dict from ipywidgets import DOMWidget from ipywidgets.widgets.widget import widget_serialization from ._version import semver from .ForceLoad import force_load_instance import inspect from importlib import import_module OBJECT_REF = 'objectRef' FUNCTION_REF = 'functionRef' class Events(object): def __init__(self, **kwargs): self.on_msg(self._handle_event) self.events = [item[4:] for item in dir(self) if item.startswith("vue_")] def _handle_event(self, _, content, buffers): def resolve_ref(value): if isinstance(value, dict): if OBJECT_REF in value.keys(): obj = getattr(self, value[OBJECT_REF]) for path_item in value.get('path', []): obj = obj[path_item] return obj if FUNCTION_REF in value.keys(): fn = getattr(self, value[FUNCTION_REF]) args = value.get('args', []) kwargs = value.get('kwargs', {}) return fn(*args, **kwargs) return value if 'create_widget' in content.keys(): module_name = content['create_widget'][0] class_name = content['create_widget'][1] props = {k: resolve_ref(v) for k, v in content['props'].items()} module = import_module(module_name) widget = getattr(module, class_name)(**props, model_id=content['id']) self._component_instances = [*self._component_instances, widget] elif 'update_ref' in content.keys(): widget = DOMWidget.widgets[content['id']] prop = content['prop'] obj = resolve_ref(content['update_ref']) setattr(widget, prop, obj) elif 'destroy_widget' in content.keys(): self._component_instances = [w for w in self._component_instances if w.model_id != content['destroy_widget']] elif 'event' in content.keys(): event = content.get("event", "") data = content.get("data", {}) getattr(self, 'vue_' + event)(data) def _value_to_json(x, obj): if inspect.isclass(x): return { 'class': [x.__module__, x.__name__], 'props': x.class_trait_names() } return widget_serialization['to_json'](x, obj) def _class_to_json(x, obj): if not x: return widget_serialization['to_json'](x, obj) return {k: _value_to_json(v, obj) for k, v in x.items()} def as_refs(name, data): def to_ref_structure(obj, path): if isinstance(obj, list): return [to_ref_structure(item, [*path, index]) for index, item in enumerate(obj)] if isinstance(obj, dict): return {k: to_ref_structure(v, [*path, k]) for k, v in obj.items()} # add object id to detect a new object in the same structure return {OBJECT_REF: name, 'path': path, 'id': id(obj)} return to_ref_structure(data, []) class VueTemplate(DOMWidget, Events): class_component_serialization = { 'from_json': widget_serialization['to_json'], 'to_json': _class_to_json } # Force the loading of jupyter-vue before dependent extensions when in a static context (embed, # voila) _jupyter_vue = Any(force_load_instance, read_only=True).tag(sync=True, **widget_serialization) _model_name = Unicode('VueTemplateModel').tag(sync=True) _view_name = Unicode('VueView').tag(sync=True) _view_module = Unicode('jupyter-vue').tag(sync=True) _model_module = Unicode('jupyter-vue').tag(sync=True) _view_module_version = Unicode(semver).tag(sync=True) _model_module_version = Unicode(semver).tag(sync=True) template = Unicode(None, allow_none=True).tag(sync=True) css = Unicode(None, allow_none=True).tag(sync=True) methods = Unicode(None, allow_none=True).tag(sync=True) data = Unicode(None, allow_none=True).tag(sync=True) events = List(Unicode(), default_value=None, allow_none=True).tag(sync=True) components = Dict(default_value=None, allow_none=True).tag( sync=True, **class_component_serialization) _component_instances = List().tag(sync=True, **widget_serialization) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) sync_ref_traitlets = [v for k, v in self.traits().items() if 'sync_ref' in v.metadata.keys()] def create_ref_and_observe(traitlet): data = traitlet.get(self) ref_name = traitlet.name + '_ref' self.add_traits(**{ref_name: Any(as_refs(traitlet.name, data)).tag(sync=True)}) def on_ref_source_change(change): setattr(self, ref_name, as_refs(traitlet.name, change['new'])) self.observe(on_ref_source_change, traitlet.name) for traitlet in sync_ref_traitlets: create_ref_and_observe(traitlet) __all__ = ['VueTemplate']