1919
2020from base64 import standard_b64encode
2121
22- from .utils import deprecation , _get_frame
23-
2422from .._version import __protocol_version__ , __control_protocol_version__ , __jupyter_widgets_base_version__
2523
2624import inspect
@@ -43,29 +41,24 @@ def envset(name, default):
4341JUPYTER_WIDGETS_ECHO = envset ('JUPYTER_WIDGETS_ECHO' , default = True )
4442# for a discussion on using weak references see:
4543# https://github.com/jupyter-widgets/ipywidgets/issues/1345
46- _instances : typing .MutableMapping [str , "Widget" ] = {}
4744
4845def enable_weakreference ():
49- """Use a WeakValueDictionary instead of a standard dictionary to map
50- `comm_id` to `widget` for every widget instance.
46+ """Use a WeakValueDictionary to store references to Widget instances.
5147
52- By default widgets are mapped using a standard dictionary. Use this feature
53- to permit widget garbage collection.
48+ A strong reference must be kept to widgets.
5449 """
55- global _instances
56- if not isinstance (_instances , weakref .WeakValueDictionary ):
57- _instances = weakref .WeakValueDictionary (_instances )
50+ if not isinstance (Widget ._instances , weakref .WeakValueDictionary ):
51+ Widget ._instances = weakref .WeakValueDictionary (Widget ._instances )
5852
5953def disable_weakreference ():
60- """Use a Dictionary to map `comm_id` to `widget` for every widget instance .
61-
62- Note: this is the default setting and maintains a strong reference to the
63- the widget preventing automatic garbage collection. If the close method
64- is called, the widget will remove itself enabling garbage collection .
54+ """Use a standard dictionary to store references to Widget instances (default behavior) .
55+
56+ Note: this is the default setting and maintains a strong reference to the
57+ the widget preventing automatic garbage collection. When the widget is closed
58+ it can be garbage collected .
6559 """
66- global _instances
67- if isinstance (_instances , weakref .WeakValueDictionary ):
68- _instances = dict (_instances )
60+ if isinstance (Widget ._instances , weakref .WeakValueDictionary ):
61+ Widget ._instances = dict (Widget ._instances )
6962
7063def _widget_to_json (x , obj ):
7164 if isinstance (x , Widget ):
@@ -82,8 +75,8 @@ def _json_to_widget(x, obj):
8275 return {k : _json_to_widget (v , obj ) for k , v in x .items ()}
8376 elif isinstance (x , (list , tuple )):
8477 return [_json_to_widget (v , obj ) for v in x ]
85- elif isinstance (x , str ) and x .startswith (' IPY_MODEL_' ) and x [10 :] in _instances :
86- return _instances [x [10 :]]
78+ elif isinstance (x , str ) and x .startswith (" IPY_MODEL_" ) and x [10 :] in Widget . _instances :
79+ return Widget . _instances [x [10 :]]
8780 else :
8881 return x
8982
@@ -314,50 +307,12 @@ class Widget(LoggingHasTraits):
314307 #-------------------------------------------------------------------------
315308 _widget_construction_callback = None
316309 _control_comm = None
317-
318- @_staticproperty
319- def widgets ():
320- # Because this is a static attribute, it will be accessed when initializing this class. In that case, since a user
321- # did not explicitly try to use this attribute, we do not want to throw a deprecation warning.
322- # So we check if the thing calling this static property is one of the known initialization functions in traitlets.
323- frame = _get_frame (2 )
324- if not (frame .f_code .co_filename == TRAITLETS_FILE and (frame .f_code .co_name in ('getmembers' , 'setup_instance' , 'setup_class' ))):
325- deprecation ("Widget.widgets is deprecated." )
326- return _instances
327-
328- @_staticproperty
329- def _active_widgets ():
330- # Because this is a static attribute, it will be accessed when initializing this class. In that case, since a user
331- # did not explicitly try to use this attribute, we do not want to throw a deprecation warning.
332- # So we check if the thing calling this static property is one of the known initialization functions in traitlets.
333- frame = _get_frame (2 )
334- if not (frame .f_code .co_filename == TRAITLETS_FILE and (frame .f_code .co_name in ('getmembers' , 'setup_instance' , 'setup_class' ))):
335- deprecation ("Widget._active_widgets is deprecated." )
336- return _instances
337-
338- @_staticproperty
339- def _widget_types ():
340- # Because this is a static attribute, it will be accessed when initializing this class. In that case, since a user
341- # did not explicitly try to use this attribute, we do not want to throw a deprecation warning.
342- # So we check if the thing calling this static property is one of the known initialization functions in traitlets.
343- frame = _get_frame (2 )
344- if not (frame .f_code .co_filename == TRAITLETS_FILE and (frame .f_code .co_name in ('getmembers' , 'setup_instance' , 'setup_class' ))):
345- deprecation ("Widget._widget_types is deprecated." )
346- return _registry
347-
348- @_staticproperty
349- def widget_types ():
350- # Because this is a static attribute, it will be accessed when initializing this class. In that case, since a user
351- # did not explicitly try to use this attribute, we do not want to throw a deprecation warning.
352- # So we check if the thing calling this static property is one of the known initialization functions in traitlets.
353- frame = _get_frame (2 )
354- if not (frame .f_code .co_filename == TRAITLETS_FILE and (frame .f_code .co_name in ('getmembers' , 'setup_instance' , 'setup_class' ))):
355- deprecation ("Widget.widget_types is deprecated." )
356- return _registry
310+
311+ _instances : typing .ClassVar [typing .MutableMapping [str , "Widget" ]] = {}
357312
358313 @classmethod
359314 def close_all (cls ):
360- for widget in list (_instances .values ()):
315+ for widget in list (Widget . _instances .values ()):
361316 widget .close ()
362317
363318 @staticmethod
@@ -399,7 +354,7 @@ def _handle_control_comm_msg(cls, msg):
399354 if method == 'request_states' :
400355 # Send back the full widgets state
401356 cls .get_manager_state ()
402- widgets = _instances .values ()
357+ widgets = cls . _instances .values ()
403358 full_state = {}
404359 drop_defaults = False
405360 for widget in widgets :
@@ -440,8 +395,8 @@ def handle_comm_opened(comm, msg):
440395 _put_buffers (state , data ['buffer_paths' ], msg ['buffers' ])
441396 widget .set_state (state )
442397
443- @staticmethod
444- def get_manager_state (drop_defaults = False , widgets = None ):
398+ @classmethod
399+ def get_manager_state (cls , drop_defaults = False , widgets = None ):
445400 """Returns the full state for a widget manager for embedding
446401
447402 :param drop_defaults: when True, it will not include default value
@@ -450,7 +405,7 @@ def get_manager_state(drop_defaults=False, widgets=None):
450405 """
451406 state = {}
452407 if widgets is None :
453- widgets = _instances .values ()
408+ widgets = cls . _instances .values ()
454409 for widget in widgets :
455410 state [widget .model_id ] = widget ._get_embed_state (drop_defaults = drop_defaults )
456411 return {'version_major' : 2 , 'version_minor' : 0 , 'state' : state }
@@ -561,14 +516,11 @@ def _comm_changed(self, change):
561516 if change ['old' ]:
562517 change ['old' ].on_msg (None )
563518 change ['old' ].close ()
564- # On python shutdown _instances can be None
565- if isinstance (_instances , dict ):
566- _instances .pop (change ['old' ].comm_id , None )
519+ self ._instances .pop (change ['old' ].comm_id , None )
567520 if change ['new' ]:
568- if isinstance (_instances , dict ):
569- _instances [change ["new" ].comm_id ] = self
570- self ._model_id = change ["new" ].comm_id
571-
521+ self ._instances [change ["new" ].comm_id ] = self
522+ self ._model_id = change ["new" ].comm_id
523+
572524 # prevent memory leaks by using a weak reference to self.
573525 ref = weakref .ref (self )
574526 def _handle_msg (msg ):
0 commit comments