6
6
in the Jupyter notebook front-end.
7
7
"""
8
8
import os
9
+ import typing
9
10
from contextlib import contextmanager
10
11
from collections .abc import Iterable
12
+ import warnings
11
13
from IPython import get_ipython
12
14
from ipykernel .comm import Comm
13
15
from traitlets import (
@@ -34,6 +36,9 @@ def envset(name, default):
34
36
PROTOCOL_VERSION_MAJOR = __protocol_version__ .split ('.' )[0 ]
35
37
CONTROL_PROTOCOL_VERSION_MAJOR = __control_protocol_version__ .split ('.' )[0 ]
36
38
JUPYTER_WIDGETS_ECHO = envset ('JUPYTER_WIDGETS_ECHO' , default = True )
39
+ # we keep a strong reference for every widget created, for a discussion on using weak references see:
40
+ # https://github.com/jupyter-widgets/ipywidgets/issues/1345
41
+ instances : typing .MutableMapping [str , "Widget" ] = {}
37
42
38
43
def _widget_to_json (x , obj ):
39
44
if isinstance (x , dict ):
@@ -50,8 +55,8 @@ def _json_to_widget(x, obj):
50
55
return {k : _json_to_widget (v , obj ) for k , v in x .items ()}
51
56
elif isinstance (x , (list , tuple )):
52
57
return [_json_to_widget (v , obj ) for v in x ]
53
- elif isinstance (x , str ) and x .startswith ('IPY_MODEL_' ) and x [10 :] in Widget . _active_widgets :
54
- return Widget . _active_widgets [x [10 :]]
58
+ elif isinstance (x , str ) and x .startswith ('IPY_MODEL_' ) and x [10 :] in instances :
59
+ return instances [x [10 :]]
55
60
else :
56
61
return x
57
62
@@ -259,10 +264,16 @@ def items(self):
259
264
for view_name , widget in sorted (vn .items ()):
260
265
yield (model_module , model_version , model_name , view_module , view_version , view_name ), widget
261
266
267
+
268
+
269
+ # a registry of widgets by module, version, and name so we can create a Python model from widgets
270
+ # that are constructed from the frontend.
271
+ registry = WidgetRegistry ()
272
+
262
273
def register (widget ):
263
274
"""A decorator registering a widget class in the widget registry."""
264
275
w = widget .class_traits ()
265
- Widget . _widget_types .register (w ['_model_module' ].default_value ,
276
+ registry .register (w ['_model_module' ].default_value ,
266
277
w ['_model_module_version' ].default_value ,
267
278
w ['_model_name' ].default_value ,
268
279
w ['_view_module' ].default_value ,
@@ -272,22 +283,46 @@ def register(widget):
272
283
return widget
273
284
274
285
286
+ class _staticproperty (object ):
287
+ def __init__ (self , fget ):
288
+ self .fget = fget
289
+
290
+ def __get__ (self , owner_self , owner_cls ):
291
+ assert owner_self is None
292
+ return self .fget ()
293
+
294
+
295
+
275
296
class Widget (LoggingHasTraits ):
276
297
#-------------------------------------------------------------------------
277
298
# Class attributes
278
299
#-------------------------------------------------------------------------
279
300
_widget_construction_callback = None
280
301
_control_comm = None
281
302
282
- # _active_widgets is a dictionary of all active widget objects
283
- _active_widgets = {}
303
+ @_staticproperty
304
+ def widgets ():
305
+ warnings .warn ("Widget.widgets is deprecated, use ipywidgets.widgets.widget.instances" , DeprecationWarning )
306
+ return instances
307
+
308
+ @_staticproperty
309
+ def _active_widgets ():
310
+ warnings .warn ("Widget._active_widgets is deprecated, use ipywidgets.widgets.widget.instances" , DeprecationWarning )
311
+ return instances
312
+
313
+ @_staticproperty
314
+ def _widget_types ():
315
+ warnings .warn ("Widget._widget_types is deprecated, use ipywidgets.widgets.widget.register" , DeprecationWarning )
316
+ return registry
284
317
285
- # _widget_types is a registry of widgets by module, version, and name:
286
- _widget_types = WidgetRegistry ()
318
+ @_staticproperty
319
+ def widget_types ():
320
+ warnings .warn ("Widget.widget_types is deprecated, use ipywidgets.widgets.widget.register" , DeprecationWarning )
321
+ return registry
287
322
288
323
@classmethod
289
324
def close_all (cls ):
290
- for widget in list (cls . _active_widgets .values ()):
325
+ for widget in list (instances .values ()):
291
326
widget .close ()
292
327
293
328
@staticmethod
@@ -329,7 +364,7 @@ def _handle_control_comm_msg(cls, msg):
329
364
if method == 'request_states' :
330
365
# Send back the full widgets state
331
366
cls .get_manager_state ()
332
- widgets = cls . _active_widgets .values ()
367
+ widgets = instances .values ()
333
368
full_state = {}
334
369
drop_defaults = False
335
370
for widget in widgets :
@@ -359,7 +394,7 @@ def handle_comm_opened(comm, msg):
359
394
state = data ['state' ]
360
395
361
396
# Find the widget class to instantiate in the registered widgets
362
- widget_class = Widget . _widget_types .get (state ['_model_module' ],
397
+ widget_class = register .get (state ['_model_module' ],
363
398
state ['_model_module_version' ],
364
399
state ['_model_name' ],
365
400
state ['_view_module' ],
@@ -380,7 +415,7 @@ def get_manager_state(drop_defaults=False, widgets=None):
380
415
"""
381
416
state = {}
382
417
if widgets is None :
383
- widgets = Widget . _active_widgets .values ()
418
+ widgets = instances .values ()
384
419
for widget in widgets :
385
420
state [widget .model_id ] = widget ._get_embed_state (drop_defaults = drop_defaults )
386
421
return {'version_major' : 2 , 'version_minor' : 0 , 'state' : state }
@@ -476,7 +511,7 @@ def _comm_changed(self, change):
476
511
self ._model_id = self .model_id
477
512
478
513
self .comm .on_msg (self ._handle_msg )
479
- Widget . _active_widgets [self .model_id ] = self
514
+ instances [self .model_id ] = self
480
515
481
516
@property
482
517
def model_id (self ):
@@ -496,7 +531,7 @@ def close(self):
496
531
When the comm is closed, all of the widget views are automatically
497
532
removed from the front-end."""
498
533
if self .comm is not None :
499
- Widget . _active_widgets .pop (self .model_id , None )
534
+ instances .pop (self .model_id , None )
500
535
self .comm .close ()
501
536
self .comm = None
502
537
self ._repr_mimebundle_ = None
0 commit comments