Skip to content

Commit 4399697

Browse files
authored
ipywidgets' Widget.comm field now uses Any() instead of Instance() (#80)
* Close #79: ipywidgets' Widget.comm field now uses Any() instead of Instance() * Avoid having to import traitlets
1 parent 12b0847 commit 4399697

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

shinywidgets/_shinywidgets.py

+23-8
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,16 @@ def init_shiny_widget(w: Widget):
6666
while hasattr(session, "_parent"):
6767
session = cast(Session, session._parent)
6868

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
7679

7780
# Get the initial state of the widget
7881
state, buffer_paths, buffers = _remove_buffers(w.get_state()) # type: ignore
@@ -136,7 +139,8 @@ def _():
136139
comm.handle_msg(msg)
137140

138141
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
140144
SESSIONS.remove(session) # type: ignore
141145

142146
session.on_ended(_restore_state)
@@ -316,6 +320,17 @@ def package_dir(package: str) -> str:
316320
return os.path.dirname(pkg_file)
317321

318322

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+
319334
# It doesn't, at the moment, seem feasible to establish a comm with statically rendered widgets,
320335
# and partially for this reason, it may not be sensible to provide an input-like API for them.
321336

0 commit comments

Comments
 (0)