Skip to content

Python

Terminal window
npm install @kadal/deck-python
src/main.tsx
registerLazyRenderer("python", () => import("@kadal/deck-python").then((m) => m.pythonRenderer));
ticker.py
def deck_mount(host, props):
return Ticker(host, props) # with deck_update(props) and deck_destroy()
import { deckPython } from "@kadal/deck-python/build";
<Island
framework="python"
load={() => import("./ticker.py?raw").then((m) => deckPython(m.default))}
props={{ data }}
/>

A Python island is source text. Python has no build step: CPython compiled to WebAssembly reads source at runtime, as on a server. So the island is handed a string, ?raw is the whole pipeline, and the renderer runs it.

  • destroy is reserved. PyProxy.destroy() is the proxy’s own lifetime method and shadows a Python method of the same name — the island’s teardown would silently never run. The agreement is therefore deck_mount / deck_update / deck_destroy.
  • Proxies are freed by hand, in both directions; garbage collection can’t cross the boundary, and a leak lives in WebAssembly memory where no browser tool shows it.
  • getattr(js.window, "x", None). Pyodide raises AttributeError where JavaScript gives undefined.

One interpreter is shared and not torn down when the last island leaves — about six megabytes is too much to pay twice — but each island runs in its own namespace, so two islands defining deck_mount stay two islands. It is the only renderer that needs the network: the Pyodide URL is pinned, because an interpreter that changes under a deck is a talk that breaks on stage. Expect a Python island to start a few seconds after the others — that is the download.