Kernel
wybthon.kernel¶
kernel
¶
Batched DOM command buffer and rendering backends.
This module is the single point of contact between Wybthon's renderer and the real DOM. Instead of calling DOM APIs directly (each call crosses the Python-to-JS bridge in Pyodide), the reconciler and prop appliers emit compact operations into a buffer. At well-defined commit points (end of a render, end of an effect flush) the whole buffer is serialized once and handed to a small JavaScript kernel that applies every operation natively. A mount of a 1,000-row table becomes one bridge crossing instead of tens of thousands.
Core concepts:
- Node handles. DOM nodes are referred to by integer ids allocated
on the Python side. The kernel keeps an
id -> Noderegistry, so noJsProxyobjects flow through the hot path. - Ops. Each operation is a small tuple,
(opcode, ...args), serialized as a JSON array. See theOP_*constants. - Backends.
BrowserBackenddrives the real DOM through the embedded JS kernel.PythonBackendis a reference interpreter that applies the same ops to any DOM-like stub document; it backs the unit tests and the stubbed benchmark so both exercise the exact protocol the browser sees. - Events. Event delegation lives in the kernel: one native listener
per event type walks the ancestor chain natively and calls into
Python once for the matching bubbling route with a JSON payload. See
wybthon.eventsfor the Python half.
Application code never imports this module directly; it's plumbing for
the reconciler, wybthon.props, and wybthon.events.
Classes:
| Name | Description |
|---|---|
BrowserBackend |
Backend that drives the real DOM through the embedded JS kernel. |
PythonBackend |
Reference op interpreter over a DOM-like stub document. |
Functions:
| Name | Description |
|---|---|
commit |
Flush all queued ops to the backend in one crossing. |
set_backend |
Install a rendering backend (tests pass a |
reset |
Test helper: clear the op buffer, id counters, and template registry. |
BrowserBackend
¶
Backend that drives the real DOM through the embedded JS kernel.
Created automatically on first use inside Pyodide. Every apply
serializes the op list to JSON and makes exactly one call across
the bridge.
Methods:
| Name | Description |
|---|---|
apply |
Serialize |
get_node |
Return the raw DOM node registered under |
adopt |
Return an existing handle or register the node under |
query |
Return the canonical handle of a selector match, or None. |
supports_html |
The browser can always parse template HTML. |
set_dispatcher |
Install the Python event dispatcher as the kernel's callback proxy. |
current_event |
Return the native event currently being dispatched, or |
PythonBackend
¶
PythonBackend(document: Any)
Reference op interpreter over a DOM-like stub document.
Mirrors the JS kernel's semantics against plain Python objects that
quack like DOM nodes (the test suite's StubNode and the benchmark
runner's _Node). Unit tests and the stubbed benchmark run the real
wire protocol through this class, so protocol bugs surface without
a browser.
Methods:
| Name | Description |
|---|---|
apply |
Interpret a batch of ops against the stub document. |
get_node |
Return the stub node registered under |
adopt |
Return an existing handle or register this stub node. |
query |
Return the canonical handle of a selector match, or None. |
supports_html |
Whether the stub document parses |
set_dispatcher |
Install the Python event dispatcher used by |
current_event |
Return the raw event passed to the in-flight |
roots |
Return the registered delegation roots (test helper). |
dispatch |
Simulate a bubbling native event dispatch for tests. |
query
¶
Return the canonical handle of a selector match, or None.
set_dispatcher
¶
Install the Python event dispatcher used by dispatch.
current_event
¶
current_event() -> Any
Return the raw event passed to the in-flight dispatch, or None.
dispatch
¶
dispatch(event_type: str, target: Any, raw_event: Any = None, payload: Optional[dict] = None) -> None
Simulate a bubbling native event dispatch for tests.
Walks the stub-node ancestor chain from target, invoking the
Python dispatcher for every registered (node, event_type)
handler, exactly like the JS kernel's root listener.
template_id
¶
Return the template id for html, registering it on first use.
The registration op travels in the same batch as the clone that needs it, so no extra bridge crossing occurs.
commit
¶
Flush all queued ops to the backend in one crossing.
No-op when the buffer is empty. Safe to call at any time; the
renderer calls it at the end of render, at the end of every
effect flush, and before any synchronous DOM read.
get_node
¶
Return the raw DOM node for node_id, committing pending ops first.
query
¶
Resolve a CSS selector to a node id, or None when nothing matches.
Commits pending ops first so the selector can match nodes created earlier in the same logical update.
supports_html
¶
supports_html() -> bool
Return whether the backend can parse templates (OP_REGISTER_TPL).
current_event
¶
current_event() -> Any
Return the native event being dispatched right now, or None.
Only valid synchronously inside an event handler; used as the
escape hatch behind DomEvent.raw.
set_event_dispatcher
¶
Install the Python-side event dispatcher (called by wybthon.events).
What's in this module¶
kernel is the single point of contact between the renderer and the
real DOM. The reconciler, prop appliers, and event system emit compact
ops (JSON-serializable tuples against integer node ids) into a buffer;
commit() hands the whole buffer to the active backend in one
Python-to-JS bridge crossing. Application code never imports this
module; it matters when you're writing tests against the stub backend
or debugging the wire protocol.
| Name | Description |
|---|---|
commit |
Flush every queued op to the backend in one crossing (no-op when empty). |
BrowserBackend |
Drives the real DOM through the embedded JS kernel; created automatically in Pyodide. |
PythonBackend |
Reference interpreter applying the same ops to a DOM-like stub document (used by the unit tests and the stubbed benchmark). |
set_backend |
Install a backend (tests pass a PythonBackend). |
reset |
Test helper: clear the op buffer, id counters, and template registry, optionally installing a backend. |
Wire protocol¶
Each op is a JSON array whose first element is the opcode. Node ids are
allocated on the Python side, so no JsProxy objects flow through the
hot path; None anchors mean "append".
| Op | Payload | Effect |
|---|---|---|
CREATE_ELEMENT |
id, tag |
document.createElement |
CREATE_ELEMENT_NS |
id, namespace, tag |
document.createElementNS (SVG, MathML) |
CREATE_TEXT |
id, text |
document.createTextNode |
CREATE_COMMENT |
id |
Empty comment marker (fragment and hole anchors) |
REGISTER_TPL |
tpl_id, html |
Parse a skeleton once via <template> |
CLONE_TPL |
first_id, count, tpl_id |
Clone the proto; assign a dense id block in pre-order |
INSERT |
parent_id, id, anchor_id |
insertBefore (None anchor appends) |
REMOVE |
id |
Detach from the parent |
MOVE_RANGE |
parent_id, first_id, last_id, anchor_id |
Move a contiguous mounted range |
REMOVE_RANGE |
first_id, last_id |
Detach a contiguous mounted range |
HOLE_TEXT |
id, text |
Reuse a hole anchor as a visible text node |
RELEASE_TPL |
tpl_id |
Evict a native template prototype |
SET_TEXT |
id, text |
nodeValue assignment |
SET_ATTR |
id, name, value |
setAttribute, or removeAttribute when value is None |
SET_PROP |
id, name, value |
DOM property assignment (value, checked, selectedValues, innerHTML) |
SET_STYLE |
id, decls |
style.setProperty / removeProperty per kebab-case declaration |
LISTEN / UNLISTEN |
id, event_type[, options] |
Delegated bookkeeping or direct native options; unlisten omits options |
RELEASE |
[ids] |
Drop registry entries and listener sets for a retired subtree |
ROOT / UNROOT |
id |
Start or stop delegating events from this container instead of document |
Events travel the other way: the JS kernel installs one native listener per event type on each render root, walks the ancestor chain natively, and calls the Python dispatcher once for the matching bubbling route with a small JSON payload (see events).
from wybthon import kernel
# In a CPython test, install the stub backend over any DOM-like document
# (the test suite's conftest does this for you).
kernel.reset(kernel.PythonBackend(stub_document))
See also¶
- Reconciler: emits the ops
- Template:
REGISTER_TPLandCLONE_TPLin practice - Events: the Python half of delegation
- Concepts: Virtual DOM
- Guides: Testing