-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
59 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,45 @@ | ||
"""AnyWidget base class for custom Jupyter widgets.""" | ||
|
||
from __future__ import annotations | ||
|
||
from typing import Any | ||
from typing import Any, Callable | ||
|
||
import ipywidgets | ||
import traitlets.traitlets as t | ||
import traitlets | ||
|
||
from ._file_contents import FileContents | ||
from ._descriptor import MimeBundleDescriptor | ||
from ._util import ( | ||
_ANYWIDGET_ID_KEY, | ||
_CSS_KEY, | ||
_DEFAULT_ESM, | ||
_ESM_KEY, | ||
enable_custom_widget_manager_once, | ||
in_colab, | ||
repr_mimebundle, | ||
try_file_contents, | ||
) | ||
from ._version import _ANYWIDGET_SEMVER_VERSION | ||
from .experimental import _collect_anywidget_commands, _register_anywidget_commands | ||
|
||
|
||
class AnyWidget(ipywidgets.DOMWidget): # type: ignore [misc] | ||
class AnyWidget(traitlets.HasTraits): # type: ignore [misc] | ||
"""Main AnyWidget base class.""" | ||
|
||
_model_name = t.Unicode("AnyModel").tag(sync=True) | ||
_model_module = t.Unicode("anywidget").tag(sync=True) | ||
_model_module_version = t.Unicode(_ANYWIDGET_SEMVER_VERSION).tag(sync=True) | ||
|
||
_view_name = t.Unicode("AnyView").tag(sync=True) | ||
_view_module = t.Unicode("anywidget").tag(sync=True) | ||
_view_module_version = t.Unicode(_ANYWIDGET_SEMVER_VERSION).tag(sync=True) | ||
_repr_mimebundle_: MimeBundleDescriptor | ||
|
||
def __init__(self, *args: Any, **kwargs: Any) -> None: | ||
if in_colab(): | ||
enable_custom_widget_manager_once() | ||
|
||
anywidget_traits = {} | ||
for key in (_ESM_KEY, _CSS_KEY): | ||
if hasattr(self, key) and not self.has_trait(key): | ||
value = getattr(self, key) | ||
anywidget_traits[key] = t.Unicode(str(value)).tag(sync=True) | ||
if isinstance(value, FileContents): | ||
value.changed.connect( | ||
lambda new_contents, key=key: setattr(self, key, new_contents) | ||
) | ||
|
||
# show default _esm if not defined | ||
if not hasattr(self, _ESM_KEY): | ||
anywidget_traits[_ESM_KEY] = t.Unicode(_DEFAULT_ESM).tag(sync=True) | ||
|
||
# TODO: a better way to uniquely identify this subclasses? | ||
# We use the fully-qualified name to get an id which we | ||
# can use to update CSS if necessary. | ||
anywidget_traits[_ANYWIDGET_ID_KEY] = t.Unicode( | ||
f"{self.__class__.__module__}.{self.__class__.__name__}" | ||
).tag(sync=True) | ||
|
||
self.add_traits(**anywidget_traits) | ||
super().__init__(*args, **kwargs) | ||
_register_anywidget_commands(self) | ||
# Access _repr_mimebundle_ descriptor to trigger comm initialization | ||
self._repr_mimebundle_ # noqa: B018 | ||
|
||
def __init_subclass__(cls, **kwargs: dict) -> None: | ||
"""Coerces _esm and _css to FileContents if they are files.""" | ||
"""Create the _repr_mimebundle_ descriptor and register anywidget commands.""" | ||
super().__init_subclass__(**kwargs) | ||
for key in (_ESM_KEY, _CSS_KEY) & cls.__dict__.keys(): | ||
# TODO: Upgrate to := when we drop Python 3.7 | ||
file_contents = try_file_contents(getattr(cls, key)) | ||
if file_contents: | ||
setattr(cls, key, file_contents) | ||
extra_state = { | ||
key: getattr(cls, key) for key in (_ESM_KEY, _CSS_KEY) & cls.__dict__.keys() | ||
} | ||
cls._repr_mimebundle_ = MimeBundleDescriptor(**extra_state) | ||
_collect_anywidget_commands(cls) | ||
|
||
def _repr_mimebundle_(self, **kwargs: dict) -> tuple[dict, dict] | None: | ||
plaintext = repr(self) | ||
if len(plaintext) > 110: | ||
plaintext = plaintext[:110] + "…" | ||
if self._view_name is None: | ||
return None # type: ignore[unreachable] | ||
return repr_mimebundle(model_id=self.model_id, repr_text=plaintext) | ||
def send(self, msg: Any, buffers: list[memoryview] | None = None) -> None: | ||
"""Send a message to the frontend.""" | ||
self._repr_mimebundle_.send(content=msg, buffers=buffers) | ||
|
||
def on_msg( | ||
self, callback: Callable[[Any, str | list | dict, list[bytes]], None] | ||
) -> None: | ||
"""Register a message handler.""" | ||
self._repr_mimebundle_.register_callback(callback) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters