Skip to main content

tkipw

License: MIT PyPI - Python Version GitHub Release PyPI Version Downloads Status: Alpha CI

Run ipywidgets / anywidget on the desktop — no Jupyter Notebook, no browser tab.

tkipw is a small runtime that hosts ipywidgets and anywidget inside a real system WebView embedded in a Tkinter window, powered by tkwry.

Python → ipywidgets API → Comm (tkipw) → tkwry IPC → JS Widget Manager → DOM

Alpha — APIs and behavior may change. Not recommended for production yet.


📖 Overview

Jupyter widgets normally need a notebook kernel and a browser. tkipw drops both: your widgets run in the same process as your Python code and render in a native WebView that lives inside a Tk Frame (via tkwry's child-window embedding).

  • No notebook — plain python your_script.py
  • Real widgets — the official @jupyter-widgets/html-manager runs the same controls you use in Jupyter
  • anywidget — bundled front end (e.g. Plotly FigureWidget)
  • ipyleaflet — bundled live Leaflet widget module (Python ↔ map trait updates)
  • ipycanvas — bundled Canvas widget module (Python drawing commands ↔ WebView)
  • bqplot — bundled interactive plotting widgets (Python ↔ SVG figure updates)
  • ipympl — bundled interactive Matplotlib canvas (opt in with import ipympl)
  • Notebook-like displaydisplay(), clear_output(), Output, plt.show(), tracebacks, and logging all show up in an output area
  • One event loop — everything runs on Tk's mainloop

🔧 Requirements

  • Python 3.10+
  • tkwry (system WebView: WebView2 on Windows, WKWebView on macOS, WebKitGTK on Linux — see tkwry's platform notes)
  • ipywidgets 8.x

The bundled widget runtime is inlined into the shell HTML. The Playground's Monaco editor and standalone Altair / Bokeh documents load their JavaScript libraries from a CDN.

Bundled front-end dependencies

The widget front end is prebuilt from js/ with esbuild into src/tkipw/html/runtime.{js,css} and shipped inside the wheel (built in CI, not committed to the repo). It embeds:

  • Jupyter Widgets (@jupyter-widgets/*) and Lumino — BSD-3-Clause
  • anywidget, jupyter-leaflet, jQuery, Backbone.js — MIT
  • ipycanvas (and Rough.js) — BSD-3-Clause / MIT
  • bqplot / bqscales (and D3) — Apache-2.0 / ISC
  • ipympl / jupyter-matplotlib — BSD-3-Clause
  • Leaflet and its map plugins — BSD / MIT / ISC / Beerware
  • Font Awesome Free icon styles (pulled in by Jupyter Widgets; font binaries are stripped at build time) — MIT / CC BY 4.0 / SIL OFL 1.1

All are permissively licensed and redistributable; attributions are collected in NOTICE. Python runtime dependencies (tkwry, ipywidgets, comm, traitlets, markdown) are installed by pip as normal and are not vendored.


📦 Installation

From PyPI (prebuilt front end included — no npm / Node required):

pip install tkipw
pip install "tkipw[demo]"   # plotting, data, image, and 3D demos

From a source checkout (editable):

pip install -e .
pip install -e ".[demo]"

Rebuild the front end only when you change js/ (or after a fresh clone before the first editable run, if runtime.js is not present yet):

cd js && npm install && npm run build

🚀 Usage

from tkipw import App, display
import matplotlib.pyplot as plt

app = App()
plt.plot([1, 2, 3], [1, 4, 9])
plt.show()          # routed into the output area (inline mode — default)
app.run()

Pop-up windows (%matplotlib tk style for figures, and for any display()):

from tkipw import App, display

app = App(title="host", display_mode="window")
display(some_chart)   # opens a Tk pop-up (host root stays hidden)
app.run()

Interactive widgets work as usual:

from tkipw import App
import ipywidgets as widgets

app = App()
slider = widgets.IntSlider(description="n", value=10)
app.display(slider)
app.run()

import ipywidgets / import anywidget work unchanged.

  • app.display(...) — mount widgets in this App's WebView
  • display / clear_output / Output — notebook-style output under the cell
  • App(display_mode="inline"|"window") — output pane vs one Tk pop-up per display() (window mode hides the host root so only the pop-ups are visible)
  • plt.show() — follows the active App (PNG inline, or native TkAgg windows)

Import order: from tkipw import App before you create widgets, so they bind to tkipw's Comm backend instead of a DummyComm.

🔄 Multiple Apps & cleanup

Several Apps can be alive at once. The most recently used one (the one you last called display() / activate() on) receives newly created widget comms. destroy() cleans up that App, and when the last App closes, tkipw restores the process-wide patches it installed (Comm backend registry, IPython display bridge, logging handler, sys.excepthook).

a = App(title="A")
b = App(title="B")

a.display(widgets.Button(description="in A"))   # activates A → renders in A
b.display(widgets.Button(description="in B"))   # activates B → renders in B

a.destroy()
b.destroy()   # last one out tears down global patches

The monkey-patches are also individually reversible: uninstall_comm_backend(), uninstall_jupyter_support().


📁 Examples

pip install "tkipw[demo]"        # or: pip install -e ".[demo]"
python examples/playground.py    # inline: Monaco editor + stacked output
python examples/plotly_demo.py   # window: Plotly FigureWidget pop-up
python examples/ipyleaflet_demo.py # window: live ipyleaflet map pop-up
python examples/ipycanvas_demo.py  # window: live ipycanvas Canvas pop-up
python examples/bqplot_demo.py     # window: live bqplot Figure pop-up
python examples/ipympl_demo.py     # window: interactive Matplotlib (ipympl)
python examples/bokeh_demo.py    # window: Bokeh ``show(plot)`` pop-up
python examples/altair_demo.py   # window: Altair ``display(chart)`` pop-up
python examples/pillow_demo.py   # window: Pillow ``Image.show()`` pop-up
Script Mode Description
examples/playground.py inline Monaco multi-tab editor + stacked live output
examples/plotly_demo.py window Plotly FigureWidget in a Tk pop-up
examples/ipyleaflet_demo.py window Live ipyleaflet widget map in a Tk pop-up
examples/ipycanvas_demo.py window Live ipycanvas Canvas in a Tk pop-up
examples/bqplot_demo.py window Live bqplot Figure in a Tk pop-up
examples/ipympl_demo.py window Interactive Matplotlib (ipympl) in a Tk pop-up
examples/bokeh_demo.py window Bokeh show(plot) in a Tk pop-up
examples/altair_demo.py window Altair display(chart) in a Tk pop-up
examples/pillow_demo.py window Pillow Image.show() in a Tk pop-up

🖥️ Playground

An inline-mode IDE-like playground with a Monaco multi-tab editor on the left and stacked notebook-style output on the right:

python examples/playground.py

Samples (README.md / matplotlib / ipympl / pyvista / pandas / Folium / ipyleaflet / ipycanvas / bqplot / …) open as tabs. Running a .md or .markdown tab renders the file directly in the themed output pane; Python code can render the same content with IPython.display.Markdown. Run the active tab with the Run button or ⌘/Ctrl+Enter. While Python is running, the green play button becomes a red stop button; stopping cooperative Python execution reports the interruption in the output pane. The menu bar has New/Open/Save, Undo/Redo, Find/Replace, Minimap, Word Wrap, editor theme, and a View → Display Mode → Inline / Window selector. Inline results are stacked in the toggleable output pane; Window mode opens each display() in a separate Tk pop-up. Monaco loads from a CDN on first run.


🧩 Jupyter extensions

IPython.display.display(), tkipw.display() and App.display() all go through one transform gateway, so library-specific display fixes live in extensions:

from tkipw import register_extension

class MyExtension:
    name = "my-library"

    def setup(self):
        ...                 # initialise as a notebook front end

    def transform(self, obj):
        return obj          # adapt for the WebView if needed

register_extension(MyExtension())

Built-ins:

  • Matplotlib — follows the active App's display_mode by default: inline → PNG in the output area; window → native TkAgg figure windows (%matplotlib tk style). import matplotlib alone keeps that path. import ipympl switches to interactive WebView canvases (%matplotlib widget); App display_mode still chooses the inline pane vs pop-up. The Playground resets the backend from each tab's source so a matplotlib-only tab does not stay stuck on ipympl after an earlier run. Shortcuts: matplotlib_inline() / matplotlib_window() / matplotlib_widget().
  • Folium — pixel Map(width=…, height=…) becomes a fixed-size hosted map (preferred in window mode). Percentage sizes keep the notebook HTML.
  • ipyleaflet — bundled jupyter-leaflet module renders live widget maps; map/layer trait changes continue to flow over the tkipw Comm bridge.
  • ipycanvas — bundled ipycanvas module renders live Canvas widgets; drawing commands and pointer events flow over the Comm bridge.
  • bqplot — bundled bqplot + bqscales modules render interactive SVG figures; marks/scales/axes sync over the Comm bridge. Toolbar Save opens a native file dialog (desktop WebViews do not honor <a download>).
  • ipympl — bundled jupyter-matplotlib module for interactive Matplotlib zoom/pan toolbars in the WebView (activated by import ipympl).
  • PillowImage.show() → PNG via display() (inline pane or pop-up)
  • Altair — standalone Vega-Lite HTML hosted in a responsive iframe
  • Bokehshow() / displayed models → standalone HTML hosted in an iframe
  • PyVistahandle_plotter → show_trame → IPython.display. On macOS the trame / server backends are remapped to client, because native VTK OpenGL + WKWebView crash (SIGTRAP). Large offline-html srcdoc iframes are served over a loopback LocalHTMLHost for WebView compatibility.

🏗️ Architecture

  • Pythoncomm.create_commTkwryComm; official ipywidgets messages sent as JSON (+base64 buffers)
  • JS@jupyter-widgets/html-manager + window.ipc, with anywidget, jupyter-leaflet, ipycanvas, bqplot/bqscales, and jupyter-matplotlib bundled in
  • Bridge — a stack of active Apps; the top receives new comm traffic

🧪 Tests

pytest -m "not e2e"        # fast, display-free unit tests
TKIPW_E2E=1 pytest -m e2e  # real WebView: boot, comm, and extension DOM regression

CI runs the unit tests on Windows / macOS / Linux, plus the WebView E2E suite on Linux (Xvfb) and macOS (runtime/comm and extension display paths, split to avoid WebKitGTK hangs). See .github/workflows/ci.yml.


⚠️ Known limitations

  • Alpha — APIs may change
  • Widget coverage — standard ipywidgets controls + anywidget + ipyleaflet
    • ipycanvas + bqplot + ipympl; no kernel, update_display, or general dynamic third-party widget modules
  • PyVista on macOS — client-side rendering only (see extensions above)
  • Platform behavior — inherits tkwry's platform notes (macOS embedding, import order, Linux source build)

📝 License

MIT. The bundled JavaScript embeds third-party libraries (Jupyter Widgets and Lumino under BSD-3-Clause; anywidget, jQuery, and Backbone under MIT; Font Awesome Free icon styles under MIT / CC BY 4.0 / OFL 1.1) — all permissive and redistributable. See NOTICE for full attributions.

Built on tkwry.

See CHANGELOG.md for release history.


👨‍💻 Author

mashu3

Contributors

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tkipw-0.0.2.tar.gz (1.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tkipw-0.0.2-py3-none-any.whl (1.3 MB view details)

Uploaded Python 3

File details

Details for the file tkipw-0.0.2.tar.gz.

File metadata

  • Download URL: tkipw-0.0.2.tar.gz
  • Upload date:
  • Size: 1.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for tkipw-0.0.2.tar.gz
Algorithm Hash digest
SHA256 3314ba3d67a9c8920067133347995070550ff5b1e078a375d1423b771a2767bf
MD5 34ff63f01098394dc38a712593c368b3
BLAKE2b-256 c90dc1285a2bee25e9a8f829201fa88fd1ecc506c109ab949e0a9bd8b4d833c9

See more details on using hashes here.

Provenance

The following attestation bundles were made for tkipw-0.0.2.tar.gz:

Publisher: release.yml on mashu3/tkipw

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tkipw-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: tkipw-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 1.3 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for tkipw-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f8437b04faf1aa3afd43184dea6ab06de010663daff1d089b6dd46bad932b327
MD5 d78545d6b52738df4b93f0a9b9e690ec
BLAKE2b-256 922062257d2404356727be317e90494cac53aca676dc9d586812f47c101f74b6

See more details on using hashes here.

Provenance

The following attestation bundles were made for tkipw-0.0.2-py3-none-any.whl:

Publisher: release.yml on mashu3/tkipw

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.0.4

2 files

0.0.3

2 files

This release

0.0.2 This release

2 files

0.0.1

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page