From ca91f899045ee11bd77c005754f7ffc76295026a Mon Sep 17 00:00:00 2001 From: "Maarten A. Breddels" Date: Wed, 24 Aug 2022 11:53:42 +0200 Subject: [PATCH 1/8] fix: make .widget and .widget_types deprecated In #3122 we renamed .widget and .widget_types to ._active_widgets and ._widget_types. That breaks code, and we did not have a deprecation period. This PR makes the dict and registry non-members of the Widget class and puts in a backwards compatible way the deprecated these members. --- python/ipywidgets/ipywidgets/embed.py | 5 +- .../ipywidgets/ipywidgets/tests/test_embed.py | 3 +- .../ipywidgets/widgets/tests/test_widget.py | 18 +++++- .../ipywidgets/ipywidgets/widgets/widget.py | 61 +++++++++++++++---- 4 files changed, 69 insertions(+), 18 deletions(-) diff --git a/python/ipywidgets/ipywidgets/embed.py b/python/ipywidgets/ipywidgets/embed.py index 3b28a6ec2f..d9da8c8baa 100644 --- a/python/ipywidgets/ipywidgets/embed.py +++ b/python/ipywidgets/ipywidgets/embed.py @@ -12,6 +12,7 @@ import json import re +import ipywidgets.widgets.widget from .widgets import Widget, DOMWidget from .widgets.widget_link import Link from .widgets.docutils import doc_subst @@ -129,7 +130,7 @@ def _get_recursive_state(widget, store=None, drop_defaults=False): def add_resolved_links(store, drop_defaults): """Adds the state of any link models between two models in store""" - for widget_id, widget in Widget._active_widgets.items(): # go over all widgets + for widget_id, widget in ipywidgets.widgets.widget.instances.items(): # go over all widgets if isinstance(widget, Link) and widget_id not in store: if widget.source[0].model_id in store and widget.target[0].model_id in store: store[widget.model_id] = widget._get_embed_state(drop_defaults=drop_defaults) @@ -207,7 +208,7 @@ def embed_data(views, drop_defaults=True, state=None): view_specs: a list of widget view specs """ if views is None: - views = [w for w in Widget._active_widgets.values() if isinstance(w, DOMWidget)] + views = [w for w in ipywidgets.widgets.widget.instances.values() if isinstance(w, DOMWidget)] else: try: views[0] diff --git a/python/ipywidgets/ipywidgets/tests/test_embed.py b/python/ipywidgets/ipywidgets/tests/test_embed.py index cc2f772028..82bc66931a 100644 --- a/python/ipywidgets/ipywidgets/tests/test_embed.py +++ b/python/ipywidgets/ipywidgets/tests/test_embed.py @@ -9,6 +9,7 @@ import traitlets +import ipywidgets.widgets.widget from ..widgets import IntSlider, IntText, Text, Widget, jslink, HBox, widget_serialization from ..embed import embed_data, embed_snippet, embed_minimal_html, dependency_state @@ -29,7 +30,7 @@ class CaseWidget(Widget): class TestEmbed: def teardown(self): - for w in tuple(Widget._active_widgets.values()): + for w in tuple(ipywidgets.widgets.widget.instances.values()): w.close() def test_embed_data_simple(self): diff --git a/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py b/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py index 7a70b82c3b..322b40d6c3 100644 --- a/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py +++ b/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py @@ -7,6 +7,7 @@ from IPython.display import display from IPython.utils.capture import capture_output +from .. import widget from ..widget import Widget from ..widget_button import Button @@ -49,9 +50,22 @@ def test_close_all(): # create a couple of widgets widgets = [Button() for i in range(10)] - assert len(Widget._active_widgets) > 0, "expect active widgets" + assert len(widget.instances) > 0, "expect active widgets" # close all the widgets Widget.close_all() - assert len(Widget._active_widgets) == 0, "active widgets should be cleared" + assert len(widget.instances) == 0, "active widgets should be cleared" + + +def test_compatibility(): + button = Button() + assert button in widget.Widget.widgets.values() + assert widget.instances is widget.Widget.widgets + assert widget.instances is widget.Widget._active_widgets + Widget.close_all() + assert not widget.Widget.widgets + assert not widget.Widget._active_widgets + + assert widget.Widget.widget_types is widget.registry + assert widget.Widget._widget_types is widget.registry diff --git a/python/ipywidgets/ipywidgets/widgets/widget.py b/python/ipywidgets/ipywidgets/widgets/widget.py index 703ac64a6d..bb3e42f537 100644 --- a/python/ipywidgets/ipywidgets/widgets/widget.py +++ b/python/ipywidgets/ipywidgets/widgets/widget.py @@ -6,8 +6,10 @@ in the Jupyter notebook front-end. """ import os +import typing from contextlib import contextmanager from collections.abc import Iterable +import warnings from IPython import get_ipython from ipykernel.comm import Comm from traitlets import ( @@ -34,6 +36,9 @@ def envset(name, default): PROTOCOL_VERSION_MAJOR = __protocol_version__.split('.')[0] CONTROL_PROTOCOL_VERSION_MAJOR = __control_protocol_version__.split('.')[0] JUPYTER_WIDGETS_ECHO = envset('JUPYTER_WIDGETS_ECHO', default=True) +# we keep a strong reference for every widget created, for a discussion on using weak references see: +# https://github.com/jupyter-widgets/ipywidgets/issues/1345 +instances : typing.MutableMapping[str, "Widget"] = {} def _widget_to_json(x, obj): if isinstance(x, dict): @@ -50,8 +55,8 @@ def _json_to_widget(x, obj): return {k: _json_to_widget(v, obj) for k, v in x.items()} elif isinstance(x, (list, tuple)): return [_json_to_widget(v, obj) for v in x] - elif isinstance(x, str) and x.startswith('IPY_MODEL_') and x[10:] in Widget._active_widgets: - return Widget._active_widgets[x[10:]] + elif isinstance(x, str) and x.startswith('IPY_MODEL_') and x[10:] in instances: + return instances[x[10:]] else: return x @@ -259,10 +264,16 @@ def items(self): for view_name, widget in sorted(vn.items()): yield (model_module, model_version, model_name, view_module, view_version, view_name), widget + + +# a registry of widgets by module, version, and name so we can create a Python model from widgets +# that are constructed from the frontend. +registry = WidgetRegistry() + def register(widget): """A decorator registering a widget class in the widget registry.""" w = widget.class_traits() - Widget._widget_types.register(w['_model_module'].default_value, + registry.register(w['_model_module'].default_value, w['_model_module_version'].default_value, w['_model_name'].default_value, w['_view_module'].default_value, @@ -272,6 +283,16 @@ def register(widget): return widget +class _staticproperty(object): + def __init__(self, fget): + self.fget = fget + + def __get__(self, owner_self, owner_cls): + assert owner_self is None + return self.fget() + + + class Widget(LoggingHasTraits): #------------------------------------------------------------------------- # Class attributes @@ -279,15 +300,29 @@ class Widget(LoggingHasTraits): _widget_construction_callback = None _control_comm = None - # _active_widgets is a dictionary of all active widget objects - _active_widgets = {} + @_staticproperty + def widgets(): + warnings.warn("Widget.widgets is deprecated, use ipywidgets.widgets.widget.instances", DeprecationWarning) + return instances + + @_staticproperty + def _active_widgets(): + warnings.warn("Widget._active_widgets is deprecated, use ipywidgets.widgets.widget.instances", DeprecationWarning) + return instances + + @_staticproperty + def _widget_types(): + warnings.warn("Widget._widget_types is deprecated, use ipywidgets.widgets.widget.register", DeprecationWarning) + return registry - # _widget_types is a registry of widgets by module, version, and name: - _widget_types = WidgetRegistry() + @_staticproperty + def widget_types(): + warnings.warn("Widget.widget_types is deprecated, use ipywidgets.widgets.widget.register", DeprecationWarning) + return registry @classmethod def close_all(cls): - for widget in list(cls._active_widgets.values()): + for widget in list(instances.values()): widget.close() @staticmethod @@ -329,7 +364,7 @@ def _handle_control_comm_msg(cls, msg): if method == 'request_states': # Send back the full widgets state cls.get_manager_state() - widgets = cls._active_widgets.values() + widgets = instances.values() full_state = {} drop_defaults = False for widget in widgets: @@ -359,7 +394,7 @@ def handle_comm_opened(comm, msg): state = data['state'] # Find the widget class to instantiate in the registered widgets - widget_class = Widget._widget_types.get(state['_model_module'], + widget_class = register.get(state['_model_module'], state['_model_module_version'], state['_model_name'], state['_view_module'], @@ -380,7 +415,7 @@ def get_manager_state(drop_defaults=False, widgets=None): """ state = {} if widgets is None: - widgets = Widget._active_widgets.values() + widgets = instances.values() for widget in widgets: state[widget.model_id] = widget._get_embed_state(drop_defaults=drop_defaults) return {'version_major': 2, 'version_minor': 0, 'state': state} @@ -476,7 +511,7 @@ def _comm_changed(self, change): self._model_id = self.model_id self.comm.on_msg(self._handle_msg) - Widget._active_widgets[self.model_id] = self + instances[self.model_id] = self @property def model_id(self): @@ -496,7 +531,7 @@ def close(self): When the comm is closed, all of the widget views are automatically removed from the front-end.""" if self.comm is not None: - Widget._active_widgets.pop(self.model_id, None) + instances.pop(self.model_id, None) self.comm.close() self.comm = None self._repr_mimebundle_ = None From e7b941d86bb22d0d995c3f4c2c8512b40e3776fb Mon Sep 17 00:00:00 2001 From: Maarten Breddels Date: Tue, 30 Aug 2022 17:04:48 +0200 Subject: [PATCH 2/8] Update python/ipywidgets/ipywidgets/widgets/widget.py Co-authored-by: Jason Grout --- python/ipywidgets/ipywidgets/widgets/widget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ipywidgets/ipywidgets/widgets/widget.py b/python/ipywidgets/ipywidgets/widgets/widget.py index bb3e42f537..4bf741de69 100644 --- a/python/ipywidgets/ipywidgets/widgets/widget.py +++ b/python/ipywidgets/ipywidgets/widgets/widget.py @@ -312,7 +312,7 @@ def _active_widgets(): @_staticproperty def _widget_types(): - warnings.warn("Widget._widget_types is deprecated, use ipywidgets.widgets.widget.register", DeprecationWarning) + warnings.warn("Widget._widget_types is deprecated, use ipywidgets.widgets.widget.registry", DeprecationWarning) return registry @_staticproperty From 5134ea09616c2806991d2534c24355faceb246b1 Mon Sep 17 00:00:00 2001 From: Maarten Breddels Date: Tue, 30 Aug 2022 17:04:53 +0200 Subject: [PATCH 3/8] Update python/ipywidgets/ipywidgets/widgets/widget.py Co-authored-by: Jason Grout --- python/ipywidgets/ipywidgets/widgets/widget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ipywidgets/ipywidgets/widgets/widget.py b/python/ipywidgets/ipywidgets/widgets/widget.py index 4bf741de69..af09de7f53 100644 --- a/python/ipywidgets/ipywidgets/widgets/widget.py +++ b/python/ipywidgets/ipywidgets/widgets/widget.py @@ -317,7 +317,7 @@ def _widget_types(): @_staticproperty def widget_types(): - warnings.warn("Widget.widget_types is deprecated, use ipywidgets.widgets.widget.register", DeprecationWarning) + warnings.warn("Widget.widget_types is deprecated, use ipywidgets.widgets.widget.registry", DeprecationWarning) return registry @classmethod From 75c8f57774eb3f6cfd86d759c0396c91334a70d1 Mon Sep 17 00:00:00 2001 From: "Maarten A. Breddels" Date: Tue, 30 Aug 2022 17:08:39 +0200 Subject: [PATCH 4/8] rename to _instances --- python/ipywidgets/ipywidgets/embed.py | 4 ++-- .../ipywidgets/ipywidgets/tests/test_embed.py | 2 +- .../ipywidgets/widgets/tests/test_widget.py | 8 +++---- .../ipywidgets/ipywidgets/widgets/widget.py | 24 +++++++++---------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/python/ipywidgets/ipywidgets/embed.py b/python/ipywidgets/ipywidgets/embed.py index d9da8c8baa..0c17fb63c0 100644 --- a/python/ipywidgets/ipywidgets/embed.py +++ b/python/ipywidgets/ipywidgets/embed.py @@ -130,7 +130,7 @@ def _get_recursive_state(widget, store=None, drop_defaults=False): def add_resolved_links(store, drop_defaults): """Adds the state of any link models between two models in store""" - for widget_id, widget in ipywidgets.widgets.widget.instances.items(): # go over all widgets + for widget_id, widget in ipywidgets.widgets.widget._instances.items(): # go over all widgets if isinstance(widget, Link) and widget_id not in store: if widget.source[0].model_id in store and widget.target[0].model_id in store: store[widget.model_id] = widget._get_embed_state(drop_defaults=drop_defaults) @@ -208,7 +208,7 @@ def embed_data(views, drop_defaults=True, state=None): view_specs: a list of widget view specs """ if views is None: - views = [w for w in ipywidgets.widgets.widget.instances.values() if isinstance(w, DOMWidget)] + views = [w for w in ipywidgets.widgets.widget._instances.values() if isinstance(w, DOMWidget)] else: try: views[0] diff --git a/python/ipywidgets/ipywidgets/tests/test_embed.py b/python/ipywidgets/ipywidgets/tests/test_embed.py index 82bc66931a..9e8fda2bb5 100644 --- a/python/ipywidgets/ipywidgets/tests/test_embed.py +++ b/python/ipywidgets/ipywidgets/tests/test_embed.py @@ -30,7 +30,7 @@ class CaseWidget(Widget): class TestEmbed: def teardown(self): - for w in tuple(ipywidgets.widgets.widget.instances.values()): + for w in tuple(ipywidgets.widgets.widget._instances.values()): w.close() def test_embed_data_simple(self): diff --git a/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py b/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py index 322b40d6c3..0cd43a7ef4 100644 --- a/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py +++ b/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py @@ -50,19 +50,19 @@ def test_close_all(): # create a couple of widgets widgets = [Button() for i in range(10)] - assert len(widget.instances) > 0, "expect active widgets" + assert len(widget._instances) > 0, "expect active widgets" # close all the widgets Widget.close_all() - assert len(widget.instances) == 0, "active widgets should be cleared" + assert len(widget._instances) == 0, "active widgets should be cleared" def test_compatibility(): button = Button() assert button in widget.Widget.widgets.values() - assert widget.instances is widget.Widget.widgets - assert widget.instances is widget.Widget._active_widgets + assert widget._instances is widget.Widget.widgets + assert widget._instances is widget.Widget._active_widgets Widget.close_all() assert not widget.Widget.widgets assert not widget.Widget._active_widgets diff --git a/python/ipywidgets/ipywidgets/widgets/widget.py b/python/ipywidgets/ipywidgets/widgets/widget.py index af09de7f53..1cb1b5900c 100644 --- a/python/ipywidgets/ipywidgets/widgets/widget.py +++ b/python/ipywidgets/ipywidgets/widgets/widget.py @@ -38,7 +38,7 @@ def envset(name, default): JUPYTER_WIDGETS_ECHO = envset('JUPYTER_WIDGETS_ECHO', default=True) # we keep a strong reference for every widget created, for a discussion on using weak references see: # https://github.com/jupyter-widgets/ipywidgets/issues/1345 -instances : typing.MutableMapping[str, "Widget"] = {} +_instances : typing.MutableMapping[str, "Widget"] = {} def _widget_to_json(x, obj): if isinstance(x, dict): @@ -55,8 +55,8 @@ def _json_to_widget(x, obj): return {k: _json_to_widget(v, obj) for k, v in x.items()} elif isinstance(x, (list, tuple)): return [_json_to_widget(v, obj) for v in x] - elif isinstance(x, str) and x.startswith('IPY_MODEL_') and x[10:] in instances: - return instances[x[10:]] + elif isinstance(x, str) and x.startswith('IPY_MODEL_') and x[10:] in _instances: + return _instances[x[10:]] else: return x @@ -302,13 +302,13 @@ class Widget(LoggingHasTraits): @_staticproperty def widgets(): - warnings.warn("Widget.widgets is deprecated, use ipywidgets.widgets.widget.instances", DeprecationWarning) - return instances + warnings.warn("Widget.widgets is deprecated, use ipywidgets.widgets.widget._instances", DeprecationWarning) + return _instances @_staticproperty def _active_widgets(): - warnings.warn("Widget._active_widgets is deprecated, use ipywidgets.widgets.widget.instances", DeprecationWarning) - return instances + warnings.warn("Widget._active_widgets is deprecated, use ipywidgets.widgets.widget._instances", DeprecationWarning) + return _instances @_staticproperty def _widget_types(): @@ -322,7 +322,7 @@ def widget_types(): @classmethod def close_all(cls): - for widget in list(instances.values()): + for widget in list(_instances.values()): widget.close() @staticmethod @@ -364,7 +364,7 @@ def _handle_control_comm_msg(cls, msg): if method == 'request_states': # Send back the full widgets state cls.get_manager_state() - widgets = instances.values() + widgets = _instances.values() full_state = {} drop_defaults = False for widget in widgets: @@ -415,7 +415,7 @@ def get_manager_state(drop_defaults=False, widgets=None): """ state = {} if widgets is None: - widgets = instances.values() + widgets = _instances.values() for widget in widgets: state[widget.model_id] = widget._get_embed_state(drop_defaults=drop_defaults) return {'version_major': 2, 'version_minor': 0, 'state': state} @@ -511,7 +511,7 @@ def _comm_changed(self, change): self._model_id = self.model_id self.comm.on_msg(self._handle_msg) - instances[self.model_id] = self + _instances[self.model_id] = self @property def model_id(self): @@ -531,7 +531,7 @@ def close(self): When the comm is closed, all of the widget views are automatically removed from the front-end.""" if self.comm is not None: - instances.pop(self.model_id, None) + _instances.pop(self.model_id, None) self.comm.close() self.comm = None self._repr_mimebundle_ = None From e63740e32ade1bfc4091709d8323b417ff68b305 Mon Sep 17 00:00:00 2001 From: "Maarten A. Breddels" Date: Tue, 30 Aug 2022 17:10:22 +0200 Subject: [PATCH 5/8] rename to _registry --- .../ipywidgets/widgets/tests/test_widget.py | 4 ++-- python/ipywidgets/ipywidgets/widgets/widget.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py b/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py index 0cd43a7ef4..a7e35a8037 100644 --- a/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py +++ b/python/ipywidgets/ipywidgets/widgets/tests/test_widget.py @@ -67,5 +67,5 @@ def test_compatibility(): assert not widget.Widget.widgets assert not widget.Widget._active_widgets - assert widget.Widget.widget_types is widget.registry - assert widget.Widget._widget_types is widget.registry + assert widget.Widget.widget_types is widget._registry + assert widget.Widget._widget_types is widget._registry diff --git a/python/ipywidgets/ipywidgets/widgets/widget.py b/python/ipywidgets/ipywidgets/widgets/widget.py index 1cb1b5900c..69e444a579 100644 --- a/python/ipywidgets/ipywidgets/widgets/widget.py +++ b/python/ipywidgets/ipywidgets/widgets/widget.py @@ -268,12 +268,12 @@ def items(self): # a registry of widgets by module, version, and name so we can create a Python model from widgets # that are constructed from the frontend. -registry = WidgetRegistry() +_registry = WidgetRegistry() def register(widget): """A decorator registering a widget class in the widget registry.""" w = widget.class_traits() - registry.register(w['_model_module'].default_value, + _registry.register(w['_model_module'].default_value, w['_model_module_version'].default_value, w['_model_name'].default_value, w['_view_module'].default_value, @@ -312,13 +312,13 @@ def _active_widgets(): @_staticproperty def _widget_types(): - warnings.warn("Widget._widget_types is deprecated, use ipywidgets.widgets.widget.registry", DeprecationWarning) - return registry + warnings.warn("Widget._widget_types is deprecated, use ipywidgets.widgets.widget._registry", DeprecationWarning) + return _registry @_staticproperty def widget_types(): - warnings.warn("Widget.widget_types is deprecated, use ipywidgets.widgets.widget.registry", DeprecationWarning) - return registry + warnings.warn("Widget.widget_types is deprecated, use ipywidgets.widgets.widget._registry", DeprecationWarning) + return _registry @classmethod def close_all(cls): From 924f38374fc9b86570478c85db4cfa11f6ae9e19 Mon Sep 17 00:00:00 2001 From: "Maarten A. Breddels" Date: Tue, 6 Sep 2022 16:48:23 +0200 Subject: [PATCH 6/8] do not advertise private apis --- python/ipywidgets/ipywidgets/widgets/widget.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ipywidgets/ipywidgets/widgets/widget.py b/python/ipywidgets/ipywidgets/widgets/widget.py index 69e444a579..a4d574befb 100644 --- a/python/ipywidgets/ipywidgets/widgets/widget.py +++ b/python/ipywidgets/ipywidgets/widgets/widget.py @@ -302,22 +302,22 @@ class Widget(LoggingHasTraits): @_staticproperty def widgets(): - warnings.warn("Widget.widgets is deprecated, use ipywidgets.widgets.widget._instances", DeprecationWarning) + warnings.warn("Widget.widgets is deprecated.", DeprecationWarning) return _instances @_staticproperty def _active_widgets(): - warnings.warn("Widget._active_widgets is deprecated, use ipywidgets.widgets.widget._instances", DeprecationWarning) + warnings.warn("Widget._active_widgets is deprecated.", DeprecationWarning) return _instances @_staticproperty def _widget_types(): - warnings.warn("Widget._widget_types is deprecated, use ipywidgets.widgets.widget._registry", DeprecationWarning) + warnings.warn("Widget._widget_types is deprecated.", DeprecationWarning) return _registry @_staticproperty def widget_types(): - warnings.warn("Widget.widget_types is deprecated, use ipywidgets.widgets.widget._registry", DeprecationWarning) + warnings.warn("Widget.widget_types is deprecated.", DeprecationWarning) return _registry @classmethod From 25acec54f5776b631193c1ee842b488dd223bba9 Mon Sep 17 00:00:00 2001 From: Jason Grout Date: Tue, 6 Sep 2022 13:54:00 -0600 Subject: [PATCH 7/8] Add migration docs about deprecating .widgets and .widget_types --- docs/source/user_migration_guides.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/source/user_migration_guides.md b/docs/source/user_migration_guides.md index cc267cd513..a62fd9e61b 100644 --- a/docs/source/user_migration_guides.md +++ b/docs/source/user_migration_guides.md @@ -78,6 +78,10 @@ The previously deprecated traits `overflow_x` and `overflow_y` [have been removed](https://github.com/jupyter-widgets/ipywidgets/pull/2688). Please use the `overflow` trait instead. +#### `Widget.widgets` and `Widget.widget_types` attributes + +The `Widget` class attributes `.widgets` and `.widget_types` are now deprecated and relocated to internal module-level private variables, opening up these attribute names on the `Widget` class for future uses. + ### Deployments #### Embedded CDN From db41eabfaed80cce14f235a5be49d2789638e55c Mon Sep 17 00:00:00 2001 From: Jason Grout Date: Tue, 6 Sep 2022 16:42:45 -0600 Subject: [PATCH 8/8] Import internal references as relative imports --- python/ipywidgets/ipywidgets/embed.py | 7 +++---- python/ipywidgets/ipywidgets/tests/test_embed.py | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/python/ipywidgets/ipywidgets/embed.py b/python/ipywidgets/ipywidgets/embed.py index 0c17fb63c0..ca58880092 100644 --- a/python/ipywidgets/ipywidgets/embed.py +++ b/python/ipywidgets/ipywidgets/embed.py @@ -12,8 +12,7 @@ import json import re -import ipywidgets.widgets.widget -from .widgets import Widget, DOMWidget +from .widgets import Widget, DOMWidget, widget as widget_module from .widgets.widget_link import Link from .widgets.docutils import doc_subst from ._version import __html_manager_version__ @@ -130,7 +129,7 @@ def _get_recursive_state(widget, store=None, drop_defaults=False): def add_resolved_links(store, drop_defaults): """Adds the state of any link models between two models in store""" - for widget_id, widget in ipywidgets.widgets.widget._instances.items(): # go over all widgets + for widget_id, widget in widget_module._instances.items(): # go over all widgets if isinstance(widget, Link) and widget_id not in store: if widget.source[0].model_id in store and widget.target[0].model_id in store: store[widget.model_id] = widget._get_embed_state(drop_defaults=drop_defaults) @@ -208,7 +207,7 @@ def embed_data(views, drop_defaults=True, state=None): view_specs: a list of widget view specs """ if views is None: - views = [w for w in ipywidgets.widgets.widget._instances.values() if isinstance(w, DOMWidget)] + views = [w for w in widget_module._instances.values() if isinstance(w, DOMWidget)] else: try: views[0] diff --git a/python/ipywidgets/ipywidgets/tests/test_embed.py b/python/ipywidgets/ipywidgets/tests/test_embed.py index 9e8fda2bb5..a295442455 100644 --- a/python/ipywidgets/ipywidgets/tests/test_embed.py +++ b/python/ipywidgets/ipywidgets/tests/test_embed.py @@ -9,8 +9,7 @@ import traitlets -import ipywidgets.widgets.widget -from ..widgets import IntSlider, IntText, Text, Widget, jslink, HBox, widget_serialization +from ..widgets import IntSlider, IntText, Text, Widget, jslink, HBox, widget_serialization, widget as widget_module from ..embed import embed_data, embed_snippet, embed_minimal_html, dependency_state @@ -30,7 +29,7 @@ class CaseWidget(Widget): class TestEmbed: def teardown(self): - for w in tuple(ipywidgets.widgets.widget._instances.values()): + for w in tuple(widget_module._instances.values()): w.close() def test_embed_data_simple(self):