@@ -66,13 +66,16 @@ def init_shiny_widget(w: Widget):
66
66
while hasattr (session , "_parent" ):
67
67
session = cast (Session , session ._parent )
68
68
69
- # `Widget` has `comm = Instance('ipykernel.comm.Comm')` which means we'd get a
70
- # runtime error if we try to set this attribute to a different class, but
71
- # fortunately this hack provides a workaround.
72
- # TODO: find a better way to do this (maybe send a PR to ipywidgets?) or at least clean up after ourselves
73
- # https://github.com/jupyter-widgets/ipywidgets/blob/88cec8b/python/ipywidgets/ipywidgets/widgets/widget.py#L424
74
- old_comm_klass = copy .copy (Widget .comm .klass ) # type: ignore
75
- Widget .comm .klass = object # type: ignore
69
+ # Previous versions of ipywidgets (< 8.0.5) had
70
+ # `Widget.comm = Instance('ipykernel.comm.Comm')`
71
+ # which meant we'd get a runtime error when setting `Widget.comm = ShinyComm()`.
72
+ # In more recent versions, this is no longer necessary since they've (correctly)
73
+ # changed comm from an Instance() to Any().
74
+ # https://github.com/jupyter-widgets/ipywidgets/pull/3533/files#diff-522bb5e7695975cba0199c6a3d6df5be827035f4dc18ed6da22ac216b5615c77R482
75
+ old_comm_klass = None
76
+ if is_instance_of_class (Widget .comm , "Instance" , "traitlets.traitlets" ): # type: ignore
77
+ old_comm_klass = copy .copy (Widget .comm .klass ) # type: ignore
78
+ Widget .comm .klass = object # type: ignore
76
79
77
80
# Get the initial state of the widget
78
81
state , buffer_paths , buffers = _remove_buffers (w .get_state ()) # type: ignore
@@ -136,7 +139,8 @@ def _():
136
139
comm .handle_msg (msg )
137
140
138
141
def _restore_state ():
139
- Widget .comm .klass = old_comm_klass # type: ignore
142
+ if old_comm_klass is not None :
143
+ Widget .comm .klass = old_comm_klass # type: ignore
140
144
SESSIONS .remove (session ) # type: ignore
141
145
142
146
session .on_ended (_restore_state )
@@ -316,6 +320,17 @@ def package_dir(package: str) -> str:
316
320
return os .path .dirname (pkg_file )
317
321
318
322
323
+ def is_instance_of_class (
324
+ x : object , class_name : str , module_name : Optional [str ] = None
325
+ ) -> bool :
326
+ typ = type (x )
327
+ res = typ .__name__ == class_name
328
+ if module_name is None :
329
+ return res
330
+ else :
331
+ return res and typ .__module__ == module_name
332
+
333
+
319
334
# It doesn't, at the moment, seem feasible to establish a comm with statically rendered widgets,
320
335
# and partially for this reason, it may not be sensible to provide an input-like API for them.
321
336
0 commit comments