Once it “leaves the nest,” the only thing a kernel ever does with an output is, potentially, to update
it, replacing its data
and metadata
. It has no knowledge of where it’s going, as the other end of the ZMQ could be… anything.
comm
provides a two-way pipe to talk about any thing, one of which could be an agreed-upon structure of something in a client that should change when the kernel’s thoughts of it changes, and conversely should report to the kernel that something has changed in the client. This is, in a nutshell, what “A Jupyter Widget” is, which has triggered other features such as saving a whole notebook’s worth of state in the .ipynb
file.
And indeed, the HTML
widget is exactly a single DOM node container, inside of which could be anything, without any particular reference to the surrounding client UI.
There isn’t a lot of docs about re-implementing some of these things, as comm
is already implemented in the client, e.g. @jupyterlab/services
, along with the references in the other thread to various kernels that implement a CommManager
.
In that model:
- the client knows in advance it might get these kinds of messages
- a manager is created for each soon-to-be-kernel-owning thing (in this case a
NotebookPanel
)
- when the kernel becomes available
- it registers its named comm target
- it asks for any existing client/kernel shared objects
- if it finds any, it draws them on the page if their display object placeholders exist
- it manages an internal state of the model, in the case of
HTML
just value
(some raw HTML)
- when a user
execute
s code
- a live object is created in the kernel
- as part of its startup machinery, it sends a
comm_open
- if the user asks to display the object
- it sends a
display_data
message
- the client draws it in the right place
- is set up to observe (and update) the underlying model
As for reverse engineering the existing implementation:
While there is a spec for the wrapper format, the actual content inside them that corresponds to different widget classes like HTML are currently tied up in the python implementation. This broader discussion is on-going: tl;dr: it would be nice if there was a JSON schema which could be used directly by downstreams, either to do static codegen or dynamic instantation.
From live code opjects: here’s an example of instantiating live python objects, then generating backend classes. Here, “backend” means “running in a WebWorker in JS,” but it’s basically the same idea: “not python”.
From the wire: off-the-shelf tools such as wireshark
would work, but one can also load up jupyterlab-kernelspy or use the browsers’ built-in websocket message viewer, which have gotten much better of late.