Skip to content

Commit 96381ac

Browse files
committed
upgrade to latest version of IDOM
1 parent 4389d46 commit 96381ac

File tree

9 files changed

+954
-962
lines changed

9 files changed

+954
-962
lines changed

idom_jupyter/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from ._version import version_info # noqa
22
from ._version import __version__ # noqa
33

4+
from . import jupyter_server_extension
45
from .widget import LayoutWidget, widgetize, run, set_jupyter_server_base_url
56
from .ipython_extension import load_ipython_extension, unload_ipython_extension
67

@@ -12,6 +13,7 @@
1213
"load_ipython_extension",
1314
"unload_ipython_extension",
1415
"set_jupyter_server_base_url",
16+
"jupyter_server_extension"
1517
]
1618

1719

idom_jupyter/ipython_extension.py

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from functools import partial
22

3-
from idom.config import IDOM_CLIENT_IMPORT_SOURCE_URL
4-
from idom.core.component import AbstractComponent
3+
from idom.core.component import Component
54
from IPython import get_ipython
5+
from IPython.core.interactiveshell import InteractiveShell
66
from IPython.display import display
77

88
from .widget import LayoutWidget
@@ -12,16 +12,13 @@
1212
_POST_RUN_CELL_HOOK = None
1313

1414

15-
def load_ipython_extension(ipython):
15+
def load_ipython_extension(ipython: InteractiveShell) -> None:
1616
global _POST_RUN_CELL_HOOK, _EXTENSION_LOADED
1717
if not _EXTENSION_LOADED:
18-
# allow client to determine build location
19-
IDOM_CLIENT_IMPORT_SOURCE_URL.set("./")
20-
2118
_POST_RUN_CELL_HOOK = partial(_post_run_cell, ipython)
2219
ipython.events.register("post_run_cell", _POST_RUN_CELL_HOOK)
2320
ipython.display_formatter.ipython_display_formatter.for_type(
24-
AbstractComponent, lambda element: ({}, {})
21+
Component, lambda component: ({}, {})
2522
)
2623
_EXTENSION_LOADED = True
2724

@@ -33,8 +30,8 @@ def unload_ipython_extension(ipython):
3330
_EXTENSION_LOADED = False
3431

3532

36-
def _post_run_cell(ipython, result):
37-
if isinstance(result.result, AbstractComponent):
33+
def _post_run_cell(ipython: InteractiveShell, result):
34+
if isinstance(result.result, Component):
3835
display(LayoutWidget(result.result))
3936

4037

idom_jupyter/jupyter_server_extension.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
from urllib.parse import urljoin
22

3+
from appdirs import user_data_dir
34
from notebook.notebookapp import NotebookApp
4-
from idom.config import IDOM_CLIENT_BUILD_DIR, IDOM_CLIENT_IMPORT_SOURCE_URL
5+
from idom.config import IDOM_WED_MODULES_DIR
56
from tornado.web import StaticFileHandler
67
from tornado.web import Application
78

89

9-
import_source_url_prefix = "_idom_web_modules"
10+
IDOM_WED_MODULES_DIR.current = user_data_dir("idom-jupyter", "idom-team")
1011

1112

1213
def _load_jupyter_server_extension(notebook_app: NotebookApp):
1314
web_app: Application = notebook_app.web_app
1415
base_url = web_app.settings["base_url"]
15-
route_pattern = urljoin(base_url, rf"{import_source_url_prefix}/(.*)")
16+
route_pattern = urljoin(base_url, rf"_idom_web_modules/(.*)")
1617
web_app.add_handlers(
1718
host_pattern=".*$",
1819
host_handlers=[
1920
(
2021
route_pattern,
2122
StaticFileHandler,
22-
{"path": str(IDOM_CLIENT_BUILD_DIR.get().absolute())},
23+
{"path": str(IDOM_WED_MODULES_DIR.current.absolute())},
2324
),
2425
],
2526
)

idom_jupyter/widget.py

+18-20
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
1+
from __future__ import annotations
2+
13
import asyncio
24
from functools import wraps
35
from threading import Thread
46
from queue import Queue as SyncQueue
7+
from idom.core.proto import ComponentType
58

69
import ipywidgets as widgets
710
from IPython.display import display as ipython_display
811
from traitlets import Unicode
9-
from idom import Module
10-
from idom.config import IDOM_CLIENT_IMPORT_SOURCE_URL
1112
from idom.core.layout import Layout, LayoutEvent, LayoutUpdate
12-
13-
from .jupyter_server_extension import import_source_url_prefix
13+
from idom.core.dispatcher import VdomJsonPatch, render_json_patch
1414

1515

1616
_JUPYTER_SERVER_BASE_URL = ""
17-
IDOM_CLIENT_IMPORT_SOURCE_URL.set(f"./{import_source_url_prefix}")
1817

1918

2019
def set_jupyter_server_base_url(base_url):
@@ -62,29 +61,26 @@ class LayoutWidget(widgets.DOMWidget):
6261
_model_module_version = Unicode("^0.4.0").tag(sync=True)
6362

6463
_jupyter_server_base_url = Unicode().tag(sync=True)
65-
_client_module_url = Unicode(default_value=Module("idom-client-react").url).tag(
66-
sync=True
67-
)
6864

69-
def __init__(self, element):
65+
def __init__(self, component: ComponentType):
7066
super().__init__(_jupyter_server_base_url=_JUPYTER_SERVER_BASE_URL)
7167
self._idom_model = {}
7268
self._idom_views = set()
73-
self._idom_layout = Layout(element)
69+
self._idom_layout = Layout(component)
7470
self._idom_loop = _spawn_threaded_event_loop(self._idom_layout_render_loop())
75-
self.on_msg(self._idom_on_msg)
71+
self.on_msg(lambda _, *args, **kwargs: self._idom_on_msg(*args, **kwargs))
7672

77-
@staticmethod
7873
def _idom_on_msg(self, message, buffers):
7974
m_type = message.get("type")
8075
if m_type == "client-ready":
8176
v_id = message["viewID"]
8277
self._idom_views.add(v_id)
83-
update = LayoutUpdate.create_from({}, self._idom_model)
84-
self.send({"viewID": v_id, "data": update})
78+
update = LayoutUpdate("", None, self._idom_model)
79+
diff = VdomJsonPatch.create_from(update)
80+
self.send({"viewID": v_id, "data": diff})
8581
elif m_type == "dom-event":
8682
asyncio.run_coroutine_threadsafe(
87-
self._idom_layout.dispatch(LayoutEvent(**message["data"])),
83+
self._idom_layout.deliver(LayoutEvent(**message["data"])),
8884
loop=self._idom_loop,
8985
)
9086
elif m_type == "client-removed":
@@ -93,13 +89,15 @@ def _idom_on_msg(self, message, buffers):
9389
self._idom_views.remove(message["viewID"])
9490

9591
async def _idom_layout_render_loop(self):
96-
async with self._idom_layout:
92+
with self._idom_layout:
9793
while True:
98-
update = await self._idom_layout.render()
99-
100-
self._idom_model = update.apply_to(self._idom_model)
94+
diff = await render_json_patch(self._idom_layout)
95+
self._idom_model = diff.apply_to(self._idom_model)
10196
for v_id in self._idom_views:
102-
self.send({"viewID": v_id, "data": update})
97+
self.send({"viewID": v_id, "data": diff})
98+
99+
def __repr__(self) -> str:
100+
return f"LayoutWidget({self._idom_layout})"
103101

104102

105103
def _spawn_threaded_event_loop(coro):

js/lib/widget.js

+33-35
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var widgets = require("@jupyter-widgets/base");
2+
var idomClientReact = require("idom-client-react");
23
var _ = require("lodash");
34

45
var IdomModel = widgets.DOMWidgetModel.extend({
@@ -9,7 +10,6 @@ var IdomModel = widgets.DOMWidgetModel.extend({
910
_view_module: "idom-client-jupyter",
1011
_model_module_version: "0.4.0",
1112
_view_module_version: "0.4.0",
12-
_jupyter_server_base_url: null,
1313
}),
1414
});
1515

@@ -28,49 +28,47 @@ class IdomView extends widgets.DOMWidgetView {
2828
super(options);
2929
this.render = this.render.bind(this);
3030
this.remove = this.remove.bind(this);
31-
this.clientModulePromise = eval(
32-
`import('${
33-
jupyterServerBaseUrl + this.model.attributes._client_module_url
34-
}')`
35-
);
3631
}
3732

3833
render() {
3934
this.viewID = _nextViewID.id;
4035
_nextViewID.id++;
4136

42-
this.clientModulePromise.then((idomClientReact) => {
43-
var saveUpdateHook = (updateHook) => {
44-
this.model.on("msg:custom", (msg, buffers) => {
45-
if (msg.viewID == this.viewID) {
46-
updateHook(...msg.data);
47-
}
48-
});
49-
this.model.send({
50-
type: "client-ready",
51-
viewID: this.viewID,
52-
data: null,
53-
});
54-
};
37+
var saveUpdateHook = (updateHook) => {
38+
this.model.on("msg:custom", (msg, buffers) => {
39+
if (msg.viewID == this.viewID) {
40+
updateHook(...msg.data);
41+
}
42+
});
43+
this.send({
44+
type: "client-ready",
45+
viewID: this.viewID,
46+
data: null,
47+
});
48+
};
5549

56-
var sendEvent = (event) => {
57-
this.model.send({
58-
type: "dom-event",
59-
viewID: this.viewID,
60-
data: event,
61-
});
62-
};
50+
var sendEvent = (event) => {
51+
this.send({
52+
type: "dom-event",
53+
viewID: this.viewID,
54+
data: event,
55+
});
56+
};
6357

64-
idomClientReact.mountLayout(
65-
this.el,
66-
saveUpdateHook,
67-
sendEvent,
68-
concatAndResolveUrl(
69-
this.model.attributes._jupyter_server_base_url ||
70-
jupyterServerBaseUrl,
71-
"_idom_web_modules"
72-
)
58+
const importSourceBaseUrl = concatAndResolveUrl(
59+
this.model.attributes._jupyter_server_base_url || jupyterServerBaseUrl,
60+
"_idom_web_modules"
61+
);
62+
var loadImportSource = (source, sourceType) => {
63+
return import( /* webpackIgnore: true */
64+
sourceType == "NAME" ? `${importSourceBaseUrl}/${source}` : source
7365
);
66+
};
67+
68+
idomClientReact.mountLayout(this.el, {
69+
saveUpdateHook,
70+
sendEvent,
71+
loadImportSource,
7472
});
7573
}
7674

js/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
},
3939
"dependencies": {
4040
"@jupyter-widgets/base": "^1.1 || ^2 || ^3 || ^4",
41+
"idom-client-react": "^0.8.5",
4142
"lodash": "^4.17.4",
4243
"react": "^17.0.1",
4344
"react-dom": "^17.0.1"

0 commit comments

Comments
 (0)