You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

139 lines
4.9 KiB

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']