Skip to content

Commit 5289093

Browse files
fix: avoid using a global force_load widget
1 parent 2638b7b commit 5289093

File tree

4 files changed

+46
-11
lines changed

4 files changed

+46
-11
lines changed

ipyvue/ForceLoad.py

-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,3 @@ class ForceLoad(DOMWidget):
77
_model_name = Unicode("ForceLoadModel").tag(sync=True)
88
_model_module = Unicode("jupyter-vue").tag(sync=True)
99
_model_module_version = Unicode(semver).tag(sync=True)
10-
11-
12-
force_load_instance = ForceLoad()

ipyvue/VueTemplateWidget.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import os
2-
from traitlets import Any, Unicode, List, Dict, Union, Instance
2+
from traitlets import Any, Unicode, List, Dict, Union, Instance, default
33
from ipywidgets import DOMWidget
44
from ipywidgets.widgets.widget import widget_serialization
55

66
from .Template import Template, get_template
77
from ._version import semver
8-
from .ForceLoad import force_load_instance
8+
from .ForceLoad import ForceLoad
9+
from .util import singleton
910
import inspect
1011
from importlib import import_module
1112

@@ -94,12 +95,15 @@ class VueTemplate(DOMWidget, Events):
9495
"to_json": _class_to_json,
9596
}
9697

97-
# Force the loading of jupyter-vue before dependent extensions when in a static
98-
# context (embed, voila)
99-
_jupyter_vue = Any(force_load_instance, read_only=True).tag(
98+
# see VueWidget
99+
_jupyter_vue = Instance(ForceLoad, read_only=True).tag(
100100
sync=True, **widget_serialization
101101
)
102102

103+
@default("_jupyter_vue")
104+
def _default_jupyter_vue(self):
105+
return singleton(ForceLoad)
106+
103107
_model_name = Unicode("VueTemplateModel").tag(sync=True)
104108

105109
_view_name = Unicode("VueView").tag(sync=True)

ipyvue/VueWidget.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
from traitlets import Unicode, Instance, Union, List, Any, Dict
1+
from traitlets import Unicode, Instance, Union, List, Any, Dict, default
22
from ipywidgets import DOMWidget
33
from ipywidgets.widgets.widget import widget_serialization, CallbackDispatcher
4+
45
from ._version import semver
5-
from .ForceLoad import force_load_instance
6+
from .ForceLoad import ForceLoad
7+
from .util import singleton
68

79

810
class ClassList:
@@ -113,10 +115,18 @@ class VueWidget(DOMWidget, Events):
113115

114116
# Force the loading of jupyter-vue before dependent extensions when in a static
115117
# context (embed, voila)
116-
_jupyter_vue = Any(force_load_instance, read_only=True).tag(
118+
# this happens when e.g. jupyter-vuedraggable requires jupyter-vue, but it is not
119+
# loaded yet (via a widget creation). This does not trigger the library loading
120+
# via the widget manager, but straight through requirejs
121+
122+
_jupyter_vue = Instance(ForceLoad, read_only=True).tag(
117123
sync=True, **widget_serialization
118124
)
119125

126+
@default("_jupyter_vue")
127+
def _default_jupyter_vue(self):
128+
return singleton(ForceLoad)
129+
120130
_model_name = Unicode("VueModel").tag(sync=True)
121131

122132
_view_name = Unicode("VueView").tag(sync=True)

ipyvue/util.py

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from ipywidgets import Widget
2+
import threading
3+
4+
5+
lock = threading.Lock()
6+
7+
8+
def singleton(WidgetClass, **kwargs):
9+
# find a 'shared' instance (singleton) to avoid creating
10+
# too many widgets. In contexts where self.widgets is not
11+
# a global dict, this allows different users/context to
12+
# have a singleton without sharing the widget
13+
with lock:
14+
if hasattr(Widget, "widgets"):
15+
# pre 8.0
16+
all_widgets = Widget.widgets
17+
if hasattr(Widget, "widgets"):
18+
all_widgets = Widget._widgets
19+
else:
20+
21+
for widget in all_widgets.values():
22+
if isinstance(widget, WidgetClass):
23+
return widget
24+
return WidgetClass(**kwargs)

0 commit comments

Comments
 (0)