Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: avoid using a global force_load widget #56

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions ipyvue/ForceLoad.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,3 @@ class ForceLoad(DOMWidget):
_model_name = Unicode("ForceLoadModel").tag(sync=True)
_model_module = Unicode("jupyter-vue").tag(sync=True)
_model_module_version = Unicode(semver).tag(sync=True)


force_load_instance = ForceLoad()
14 changes: 9 additions & 5 deletions ipyvue/VueTemplateWidget.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import os
from traitlets import Any, Unicode, List, Dict, Union, Instance
from traitlets import Any, Unicode, List, Dict, Union, Instance, default
from ipywidgets import DOMWidget
from ipywidgets.widgets.widget import widget_serialization

from .Template import Template, get_template
from ._version import semver
from .ForceLoad import force_load_instance
from .ForceLoad import ForceLoad
from .util import singleton
import inspect
from importlib import import_module

Expand Down Expand Up @@ -94,12 +95,15 @@ class VueTemplate(DOMWidget, Events):
"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(
# see VueWidget
_jupyter_vue = Instance(ForceLoad, read_only=True).tag(
sync=True, **widget_serialization
)

@default("_jupyter_vue")
def _default_jupyter_vue(self):
return singleton(ForceLoad)

_model_name = Unicode("VueTemplateModel").tag(sync=True)

_view_name = Unicode("VueView").tag(sync=True)
Expand Down
19 changes: 14 additions & 5 deletions ipyvue/VueWidget.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from traitlets import Unicode, Instance, Union, List, Any, Dict
from ipywidgets import DOMWidget
from ipywidgets.widgets.widget_layout import Layout
from ipywidgets.widgets.widget import widget_serialization, CallbackDispatcher
from ipywidgets.widgets.trait_types import InstanceDict
from ipywidgets.widgets.widget import CallbackDispatcher, widget_serialization
from ipywidgets.widgets.widget_layout import Layout
from traitlets import Any, Dict, Instance, List, Unicode, Union, default

from ._version import semver
from .ForceLoad import force_load_instance
from .ForceLoad import ForceLoad
from .util import singleton


class ClassList:
Expand Down Expand Up @@ -138,10 +139,18 @@ class VueWidget(DOMWidget, Events):

# 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(
# this happens when e.g. jupyter-vuedraggable requires jupyter-vue, but it is not
# loaded yet (via a widget creation). This does not trigger the library loading
# via the widget manager, but straight through requirejs

_jupyter_vue = Instance(ForceLoad, read_only=True).tag(
sync=True, **widget_serialization
)

@default("_jupyter_vue")
def _default_jupyter_vue(self):
return singleton(ForceLoad)

_model_name = Unicode("VueModel").tag(sync=True)

_view_name = Unicode("VueView").tag(sync=True)
Expand Down
24 changes: 24 additions & 0 deletions ipyvue/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from ipywidgets import Widget
import threading


lock = threading.Lock()


def singleton(WidgetClass, **kwargs):
# find a 'shared' instance (singleton) to avoid creating
# too many widgets. In contexts where self.widgets is not
# a global dict, this allows different users/context to
# have a singleton without sharing the widget
with lock:
if hasattr(Widget, "widgets"):
# pre 8.0
all_widgets = Widget.widgets
if hasattr(Widget, "widgets"):
all_widgets = Widget._widgets
else:

for widget in all_widgets.values():
if isinstance(widget, WidgetClass):
return widget
return WidgetClass(**kwargs)
1 change: 1 addition & 0 deletions js/src/VueModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ VueModel.serializers = {
...DOMWidgetModel.serializers,
children: { deserialize: unpack_models },
v_slots: { deserialize: unpack_models },
_jupyter_vue: { deserialize: unpack_models },
};
1 change: 1 addition & 0 deletions js/src/VueTemplateModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ VueTemplateModel.serializers = {
template: { deserialize: unpack_models },
components: { deserialize: unpack_models },
_component_instances: { deserialize: unpack_models },
_jupyter_vue: { deserialize: unpack_models },
};