tkipw 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. tkipw-0.0.1/.gitignore +23 -0
  2. tkipw-0.0.1/LICENSE +21 -0
  3. tkipw-0.0.1/NOTICE +71 -0
  4. tkipw-0.0.1/PKG-INFO +330 -0
  5. tkipw-0.0.1/README.md +285 -0
  6. tkipw-0.0.1/examples/altair_demo.py +41 -0
  7. tkipw-0.0.1/examples/bokeh_demo.py +36 -0
  8. tkipw-0.0.1/examples/ipyleaflet_demo.py +33 -0
  9. tkipw-0.0.1/examples/pillow_demo.py +43 -0
  10. tkipw-0.0.1/examples/playground.py +2153 -0
  11. tkipw-0.0.1/examples/plotly_demo.py +42 -0
  12. tkipw-0.0.1/js/build.mjs +98 -0
  13. tkipw-0.0.1/js/package-lock.json +3977 -0
  14. tkipw-0.0.1/js/package.json +24 -0
  15. tkipw-0.0.1/js/src/index.js +408 -0
  16. tkipw-0.0.1/pyproject.toml +90 -0
  17. tkipw-0.0.1/src/tkipw/__init__.py +89 -0
  18. tkipw-0.0.1/src/tkipw/app.py +708 -0
  19. tkipw-0.0.1/src/tkipw/comm_backend.py +282 -0
  20. tkipw-0.0.1/src/tkipw/display_mode.py +462 -0
  21. tkipw-0.0.1/src/tkipw/extensions/__init__.py +19 -0
  22. tkipw-0.0.1/src/tkipw/extensions/altair.py +104 -0
  23. tkipw-0.0.1/src/tkipw/extensions/bokeh.py +192 -0
  24. tkipw-0.0.1/src/tkipw/extensions/folium.py +73 -0
  25. tkipw-0.0.1/src/tkipw/extensions/matplotlib.py +183 -0
  26. tkipw-0.0.1/src/tkipw/extensions/pillow.py +73 -0
  27. tkipw-0.0.1/src/tkipw/extensions/pyvista.py +185 -0
  28. tkipw-0.0.1/src/tkipw/html/runtime.css +9 -0
  29. tkipw-0.0.1/src/tkipw/html/runtime.js +259 -0
  30. tkipw-0.0.1/src/tkipw/html_host.py +221 -0
  31. tkipw-0.0.1/src/tkipw/jupyter.py +229 -0
  32. tkipw-0.0.1/src/tkipw/manager.py +22 -0
  33. tkipw-0.0.1/src/tkipw/output.py +397 -0
  34. tkipw-0.0.1/src/tkipw/protocol.py +34 -0
  35. tkipw-0.0.1/tests/conftest.py +102 -0
  36. tkipw-0.0.1/tests/e2e/__init__.py +1 -0
  37. tkipw-0.0.1/tests/e2e/conftest.py +30 -0
  38. tkipw-0.0.1/tests/e2e/helpers.py +85 -0
  39. tkipw-0.0.1/tests/e2e/test_extensions.py +295 -0
  40. tkipw-0.0.1/tests/e2e/test_webview.py +92 -0
  41. tkipw-0.0.1/tests/support/__init__.py +5 -0
  42. tkipw-0.0.1/tests/support/fakes.py +57 -0
  43. tkipw-0.0.1/tests/unit/test_display_mode.py +162 -0
  44. tkipw-0.0.1/tests/unit/test_extensions.py +304 -0
  45. tkipw-0.0.1/tests/unit/test_html_host.py +91 -0
  46. tkipw-0.0.1/tests/unit/test_jupyter.py +85 -0
  47. tkipw-0.0.1/tests/unit/test_lifecycle.py +107 -0
  48. tkipw-0.0.1/tests/unit/test_output.py +153 -0
  49. tkipw-0.0.1/tests/unit/test_playground.py +212 -0
  50. tkipw-0.0.1/tests/unit/test_protocol.py +162 -0
tkipw-0.0.1/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .venv/
5
+ dist/
6
+ build/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .mypy_cache/
10
+ .tox/
11
+ .hypothesis/
12
+ .ipynb_checkpoints/
13
+ .coverage
14
+ htmlcov/
15
+ coverage.xml
16
+ .DS_Store
17
+ js/node_modules/
18
+ *.log
19
+
20
+ # Built JS runtime bundle: produced by `npm run build` in js/, built in CI and
21
+ # bundled into the wheel/sdist. Not committed to the repo.
22
+ /src/tkipw/html/runtime.js
23
+ /src/tkipw/html/runtime.css
tkipw-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mashu3
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
tkipw-0.0.1/NOTICE ADDED
@@ -0,0 +1,71 @@
1
+ tkipw
2
+ Copyright (c) 2026 mashu3
3
+
4
+ This product includes software from third-party projects:
5
+
6
+ ipywidgets / @jupyter-widgets/*
7
+ Copyright (c) Jupyter Development Team
8
+ License: BSD-3-Clause
9
+ https://github.com/jupyter-widgets/ipywidgets
10
+
11
+ anywidget
12
+ Copyright (c) Trevor Manz
13
+ License: MIT
14
+ https://github.com/manzt/anywidget
15
+
16
+ tkwry
17
+ Copyright (c) mashu3
18
+ License: MIT
19
+ https://github.com/mashu3/tkwry
20
+
21
+ comm
22
+ Copyright (c) IPython Development Team
23
+ License: BSD-3-Clause
24
+ https://github.com/ipython/comm
25
+
26
+ Python-Markdown
27
+ Copyright 2007, 2008 The Python Markdown Project
28
+ Copyright 2004, 2005, 2006 Yuri Takhteyev
29
+ Copyright 2004 Manfred Stienstra
30
+ License: BSD-3-Clause
31
+ https://github.com/Python-Markdown/markdown
32
+
33
+ ipyleaflet / jupyter-leaflet
34
+ Copyright (c) Project Jupyter Contributors
35
+ License: MIT
36
+ https://github.com/jupyter-widgets/ipyleaflet
37
+
38
+ ------------------------------------------------------------------------
39
+
40
+ The prebuilt front-end bundle (tkipw/html/runtime.js and runtime.css, produced
41
+ from js/ with esbuild) additionally embeds code from the following projects:
42
+
43
+ Lumino (@lumino/*)
44
+ Copyright (c) Project Jupyter Contributors
45
+ License: BSD-3-Clause
46
+ https://github.com/jupyterlab/lumino
47
+
48
+ jQuery
49
+ Copyright (c) OpenJS Foundation and other contributors
50
+ License: MIT
51
+ https://github.com/jquery/jquery
52
+
53
+ Backbone.js
54
+ Copyright (c) Jeremy Ashkenas, DocumentCloud and Investigative Reporters &
55
+ Editors
56
+ License: MIT
57
+ https://github.com/jashkenas/backbone
58
+
59
+ Font Awesome Free (icon styles bundled via @jupyter-widgets; font binaries are
60
+ stripped from the build)
61
+ Copyright (c) Fonticons, Inc.
62
+ License: CSS/JS under MIT; icon graphics under CC BY 4.0; fonts under
63
+ SIL OFL 1.1
64
+ https://github.com/FortAwesome/Font-Awesome
65
+
66
+ Leaflet and the Leaflet plugins bundled by jupyter-leaflet
67
+ Copyright (c) Vladimir Agafonkin, CloudMade, Project Jupyter, and the
68
+ respective plugin contributors
69
+ Licenses: BSD-2-Clause, BSD-3-Clause, MIT, ISC, and Beerware
70
+ https://github.com/Leaflet/Leaflet
71
+ https://github.com/jupyter-widgets/ipyleaflet
tkipw-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,330 @@
1
+ Metadata-Version: 2.4
2
+ Name: tkipw
3
+ Version: 0.0.1
4
+ Summary: ipywidgets / anywidget desktop runtime on tkwry (no Jupyter Notebook)
5
+ Author: mashu3
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ License-File: NOTICE
9
+ Keywords: anywidget,ipywidgets,tkinter,tkwry,webview
10
+ Requires-Python: >=3.10
11
+ Requires-Dist: comm>=0.2
12
+ Requires-Dist: ipywidgets<9,>=8.0
13
+ Requires-Dist: markdown>=3.5
14
+ Requires-Dist: tkwry>=0.1.0
15
+ Requires-Dist: traitlets>=5.0
16
+ Provides-Extra: anywidget
17
+ Requires-Dist: anywidget>=0.9; extra == 'anywidget'
18
+ Provides-Extra: demo
19
+ Requires-Dist: altair>=5.0; extra == 'demo'
20
+ Requires-Dist: anywidget>=0.9; extra == 'demo'
21
+ Requires-Dist: bokeh>=3.0; extra == 'demo'
22
+ Requires-Dist: folium>=0.14; extra == 'demo'
23
+ Requires-Dist: ipyleaflet<0.21,>=0.20; extra == 'demo'
24
+ Requires-Dist: matplotlib>=3.7; extra == 'demo'
25
+ Requires-Dist: numpy>=1.24; extra == 'demo'
26
+ Requires-Dist: pandas>=2.0; extra == 'demo'
27
+ Requires-Dist: pillow>=10.0; extra == 'demo'
28
+ Requires-Dist: plotly>=5.0; extra == 'demo'
29
+ Requires-Dist: pyvista[jupyter]>=0.44; extra == 'demo'
30
+ Provides-Extra: dev
31
+ Requires-Dist: altair>=5.0; extra == 'dev'
32
+ Requires-Dist: anywidget>=0.9; extra == 'dev'
33
+ Requires-Dist: bokeh>=3.0; extra == 'dev'
34
+ Requires-Dist: folium>=0.14; extra == 'dev'
35
+ Requires-Dist: ipyleaflet<0.21,>=0.20; extra == 'dev'
36
+ Requires-Dist: matplotlib>=3.7; extra == 'dev'
37
+ Requires-Dist: numpy>=1.24; extra == 'dev'
38
+ Requires-Dist: pandas>=2.0; extra == 'dev'
39
+ Requires-Dist: pillow>=10.0; extra == 'dev'
40
+ Requires-Dist: plotly>=5.0; extra == 'dev'
41
+ Requires-Dist: pytest>=7.0; extra == 'dev'
42
+ Requires-Dist: pyvista[jupyter]>=0.44; extra == 'dev'
43
+ Requires-Dist: ruff>=0.9; extra == 'dev'
44
+ Description-Content-Type: text/markdown
45
+
46
+ # tkipw
47
+
48
+ [![License: MIT](https://img.shields.io/pypi/l/tkipw)](https://opensource.org/licenses/MIT)
49
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/tkipw)](https://pypi.org/project/tkipw)
50
+ [![GitHub Release](https://img.shields.io/github/v/release/mashu3/tkipw?color=orange)](https://github.com/mashu3/tkipw/releases)
51
+ [![PyPI Version](https://img.shields.io/pypi/v/tkipw?color=yellow)](https://pypi.org/project/tkipw/)
52
+ [![Downloads](https://static.pepy.tech/badge/tkipw)](https://pepy.tech/project/tkipw)
53
+ [![Status: Alpha](https://img.shields.io/badge/status-alpha-red)](https://github.com/mashu3/tkipw)
54
+ [![CI](https://github.com/mashu3/tkipw/actions/workflows/ci.yml/badge.svg)](https://github.com/mashu3/tkipw/actions/workflows/ci.yml)
55
+
56
+ **Run ipywidgets / anywidget on the desktop โ€” no Jupyter Notebook, no browser tab.**
57
+
58
+ tkipw is a small runtime that hosts [ipywidgets](https://github.com/jupyter-widgets/ipywidgets) and [anywidget](https://github.com/manzt/anywidget) inside a real system WebView embedded in a Tkinter window, powered by [**tkwry**](https://github.com/mashu3/tkwry).
59
+
60
+ ```
61
+ Python โ†’ ipywidgets API โ†’ Comm (tkipw) โ†’ tkwry IPC โ†’ JS Widget Manager โ†’ DOM
62
+ ```
63
+
64
+ > **Alpha** โ€” APIs and behavior may change. Not recommended for production yet.
65
+
66
+ ---
67
+
68
+ ## ๐Ÿ“– Overview
69
+
70
+ Jupyter widgets normally need a notebook kernel and a browser. tkipw drops both:
71
+ your widgets run in the same process as your Python code and render in a native
72
+ WebView that lives *inside* a Tk `Frame` (via tkwry's child-window embedding).
73
+
74
+ * **No notebook** โ€” plain `python your_script.py`
75
+ * **Real widgets** โ€” the official `@jupyter-widgets/html-manager` runs the same controls you use in Jupyter
76
+ * **anywidget** โ€” bundled front end (e.g. Plotly `FigureWidget`)
77
+ * **ipyleaflet** โ€” bundled live Leaflet widget module (Python โ†” map trait updates)
78
+ * **Notebook-like display** โ€” `display()`, `clear_output()`, `Output`, `plt.show()`, tracebacks, and `logging` all show up in an output area
79
+ * **One event loop** โ€” everything runs on Tk's `mainloop`
80
+
81
+ ---
82
+
83
+ ## ๐Ÿ”ง Requirements
84
+
85
+ * Python 3.10+
86
+ * [tkwry](https://github.com/mashu3/tkwry) (system WebView: WebView2 on Windows, WKWebView on macOS, WebKitGTK on Linux โ€” see tkwry's platform notes)
87
+ * `ipywidgets>=8,<9`
88
+
89
+ The bundled widget runtime is inlined into the shell HTML. The Playground's
90
+ Monaco editor and standalone Altair / Bokeh documents load their JavaScript
91
+ libraries from a CDN.
92
+
93
+ ### Bundled front-end dependencies
94
+
95
+ The widget front end is prebuilt from `js/` with esbuild into
96
+ `src/tkipw/html/runtime.{js,css}` and shipped inside the wheel (built in CI, not
97
+ committed to the repo). It embeds:
98
+
99
+ * **Jupyter Widgets** (`@jupyter-widgets/*`) and **Lumino** โ€” BSD-3-Clause
100
+ * **anywidget**, **jupyter-leaflet**, **jQuery**, **Backbone.js** โ€” MIT
101
+ * **Leaflet** and its map plugins โ€” BSD / MIT / ISC / Beerware
102
+ * **Font Awesome Free** icon styles (pulled in by Jupyter Widgets; font binaries
103
+ are stripped at build time) โ€” MIT / CC BY 4.0 / SIL OFL 1.1
104
+
105
+ All are permissively licensed and redistributable; attributions are collected in
106
+ [`NOTICE`](NOTICE). Python runtime dependencies (`tkwry`, `ipywidgets`, `comm`,
107
+ `traitlets`, `markdown`) are installed by pip as normal and are not vendored.
108
+
109
+ ---
110
+
111
+ ## ๐Ÿ“ฆ Installation
112
+
113
+ ```bash
114
+ pip install -e .
115
+ pip install -e ".[demo]" # plotting, data, image, and 3D demos
116
+ ```
117
+
118
+ Rebuild the front end only if you change `js/`:
119
+
120
+ ```bash
121
+ cd js && npm install && npm run build
122
+ ```
123
+
124
+ ---
125
+
126
+ ## ๐Ÿš€ Usage
127
+
128
+ ```python
129
+ from tkipw import App, display
130
+ import matplotlib.pyplot as plt
131
+
132
+ app = App()
133
+ plt.plot([1, 2, 3], [1, 4, 9])
134
+ plt.show() # routed into the output area (inline mode โ€” default)
135
+ app.run()
136
+ ```
137
+
138
+ Pop-up windows (``%matplotlib tk`` style for figures, and for any `display()`):
139
+
140
+ ```python
141
+ from tkipw import App, display
142
+
143
+ app = App(title="host", display_mode="window")
144
+ display(some_chart) # opens a Tk pop-up (host root stays hidden)
145
+ app.run()
146
+ ```
147
+
148
+ Interactive widgets work as usual:
149
+
150
+ ```python
151
+ from tkipw import App
152
+ import ipywidgets as widgets
153
+
154
+ app = App()
155
+ slider = widgets.IntSlider(description="n", value=10)
156
+ app.display(slider)
157
+ app.run()
158
+ ```
159
+
160
+ `import ipywidgets` / `import anywidget` work unchanged.
161
+
162
+ * `app.display(...)` โ€” mount widgets in **this** App's WebView
163
+ * `display` / `clear_output` / `Output` โ€” notebook-style output under the cell
164
+ * `App(display_mode="inline"|"window")` โ€” output pane vs one Tk pop-up per `display()`
165
+ (window mode hides the host root so only the pop-ups are visible)
166
+ * `plt.show()` โ€” follows the active App (PNG inline, or native TkAgg windows)
167
+
168
+ > **Import order:** `from tkipw import App` before you create widgets, so they
169
+ > bind to tkipw's Comm backend instead of a `DummyComm`.
170
+
171
+ ### ๐Ÿ”„ Multiple Apps & cleanup
172
+
173
+ Several `App`s can be alive at once. The most recently used one (the one you
174
+ last called `display()` / `activate()` on) receives newly created widget comms.
175
+ `destroy()` cleans up that App, and when the **last** App closes, tkipw restores
176
+ the process-wide patches it installed (Comm backend registry, IPython display
177
+ bridge, logging handler, `sys.excepthook`).
178
+
179
+ ```python
180
+ a = App(title="A")
181
+ b = App(title="B")
182
+
183
+ a.display(widgets.Button(description="in A")) # activates A โ†’ renders in A
184
+ b.display(widgets.Button(description="in B")) # activates B โ†’ renders in B
185
+
186
+ a.destroy()
187
+ b.destroy() # last one out tears down global patches
188
+ ```
189
+
190
+ The monkey-patches are also individually reversible:
191
+ `uninstall_comm_backend()`, `uninstall_jupyter_support()`.
192
+
193
+ ---
194
+
195
+ ## ๐Ÿ“ Examples
196
+
197
+ ```bash
198
+ pip install -e ".[demo]"
199
+ python examples/playground.py # inline: Monaco editor + stacked output
200
+ python examples/plotly_demo.py # window: Plotly FigureWidget pop-up
201
+ python examples/ipyleaflet_demo.py # window: live ipyleaflet map pop-up
202
+ python examples/bokeh_demo.py # window: Bokeh ``show(plot)`` pop-up
203
+ python examples/altair_demo.py # window: Altair ``display(chart)`` pop-up
204
+ python examples/pillow_demo.py # window: Pillow ``Image.show()`` pop-up
205
+ ```
206
+
207
+ | Script | Mode | Description |
208
+ | ------ | ---- | ----------- |
209
+ | [`examples/playground.py`](examples/playground.py) | inline | Monaco multi-tab editor + stacked live output |
210
+ | [`examples/plotly_demo.py`](examples/plotly_demo.py) | window | Plotly `FigureWidget` in a Tk pop-up |
211
+ | [`examples/ipyleaflet_demo.py`](examples/ipyleaflet_demo.py) | window | Live ipyleaflet widget map in a Tk pop-up |
212
+ | [`examples/bokeh_demo.py`](examples/bokeh_demo.py) | window | Bokeh `show(plot)` in a Tk pop-up |
213
+ | [`examples/altair_demo.py`](examples/altair_demo.py) | window | Altair `display(chart)` in a Tk pop-up |
214
+ | [`examples/pillow_demo.py`](examples/pillow_demo.py) | window | Pillow `Image.show()` in a Tk pop-up |
215
+
216
+ ---
217
+
218
+ ## ๐Ÿ–ฅ๏ธ Playground
219
+
220
+ An **inline-mode** IDE-like playground with a Monaco multi-tab editor on the left
221
+ and stacked notebook-style output on the right:
222
+
223
+ ```bash
224
+ python examples/playground.py
225
+ ```
226
+
227
+ Samples (`README.md` / matplotlib / pyvista / pandas / Folium / ipyleaflet / โ€ฆ) open as
228
+ tabs. Running a `.md` or `.markdown` tab renders the file directly in the
229
+ themed output pane; Python code can render the same content with
230
+ `IPython.display.Markdown`. Run the active tab with the **Run** button or
231
+ โŒ˜/Ctrl+Enter. While Python is running, the green play button becomes a red stop
232
+ button; stopping cooperative Python execution reports the interruption in the
233
+ output pane. The menu bar has
234
+ New/Open/Save, Undo/Redo, Find/Replace, Minimap, Word Wrap, editor theme, and a
235
+ **View โ†’ Display Mode โ†’ Inline / Window** selector. Inline results are stacked
236
+ in the toggleable output pane; Window mode opens each `display()` in a separate
237
+ Tk pop-up. Monaco loads from a CDN on first run.
238
+
239
+ ---
240
+
241
+ ## ๐Ÿงฉ Jupyter extensions
242
+
243
+ `IPython.display.display()`, `tkipw.display()` and `App.display()` all go through
244
+ one transform gateway, so library-specific display fixes live in extensions:
245
+
246
+ ```python
247
+ from tkipw import register_extension
248
+
249
+ class MyExtension:
250
+ name = "my-library"
251
+
252
+ def setup(self):
253
+ ... # initialise as a notebook front end
254
+
255
+ def transform(self, obj):
256
+ return obj # adapt for the WebView if needed
257
+
258
+ register_extension(MyExtension())
259
+ ```
260
+
261
+ Built-ins:
262
+
263
+ * **Matplotlib** โ€” follows the active App's ``display_mode``: ``inline`` โ†’ PNG in the output
264
+ area; ``window`` โ†’ native TkAgg figure windows (``%matplotlib tk`` style).
265
+ Shortcuts: ``matplotlib_inline()`` / ``matplotlib_window()``.
266
+ * **Folium** โ€” pixel ``Map(width=โ€ฆ, height=โ€ฆ)`` becomes a fixed-size hosted
267
+ map (preferred in window mode). Percentage sizes keep the notebook HTML.
268
+ * **ipyleaflet** โ€” bundled `jupyter-leaflet` module renders live widget maps;
269
+ map/layer trait changes continue to flow over the tkipw Comm bridge.
270
+ * **Pillow** โ€” `Image.show()` โ†’ PNG via ``display()`` (inline pane or pop-up)
271
+ * **Altair** โ€” standalone Vega-Lite HTML hosted in a responsive iframe
272
+ * **Bokeh** โ€” `show()` / displayed models โ†’ standalone HTML hosted in an iframe
273
+ * **PyVista** โ€” `handle_plotter โ†’ show_trame โ†’ IPython.display`. On macOS the
274
+ `trame` / `server` backends are remapped to `client`, because native VTK
275
+ OpenGL + WKWebView crash (SIGTRAP). Large offline-`html` `srcdoc` iframes are
276
+ served over a loopback `LocalHTMLHost` for WebView compatibility.
277
+
278
+ ---
279
+
280
+ ## ๐Ÿ—๏ธ Architecture
281
+
282
+ * **Python** โ€” `comm.create_comm` โ†’ `TkwryComm`; official ipywidgets messages sent as JSON (+base64 buffers)
283
+ * **JS** โ€” `@jupyter-widgets/html-manager` + `window.ipc`, with anywidget and
284
+ jupyter-leaflet bundled in
285
+ * **Bridge** โ€” a stack of active `App`s; the top receives new comm traffic
286
+
287
+ ---
288
+
289
+ ## ๐Ÿงช Tests
290
+
291
+ ```bash
292
+ pytest -m "not e2e" # fast, display-free unit tests
293
+ TKIPW_E2E=1 pytest -m e2e # real WebView: boot, comm, and extension DOM regression
294
+ ```
295
+
296
+ CI runs the unit tests on Windows / macOS / Linux, plus the WebView E2E suite
297
+ on Linux (Xvfb) and macOS (runtime/comm and extension display paths, split to
298
+ avoid WebKitGTK hangs). See [`.github/workflows/ci.yml`](.github/workflows/ci.yml).
299
+
300
+ ---
301
+
302
+ ## โš ๏ธ Known limitations
303
+
304
+ * **Alpha** โ€” APIs may change
305
+ * **Widget coverage** โ€” standard ipywidgets 8 controls + anywidget + ipyleaflet;
306
+ no kernel, `update_display`, or general dynamic third-party widget modules
307
+ (bqplot, ipycanvas, โ€ฆ)
308
+ * **PyVista on macOS** โ€” client-side rendering only (see extensions above)
309
+ * **Platform behavior** โ€” inherits tkwry's platform notes (macOS embedding, import order, Linux source build)
310
+
311
+ ---
312
+
313
+ ## ๐Ÿ“ License
314
+
315
+ MIT. The bundled JavaScript embeds third-party libraries (Jupyter Widgets and
316
+ Lumino under BSD-3-Clause; anywidget, jQuery, and Backbone under MIT; Font
317
+ Awesome Free icon styles under MIT / CC BY 4.0 / OFL 1.1) โ€” all permissive and
318
+ redistributable. See [`NOTICE`](NOTICE) for full attributions.
319
+
320
+ Built on [tkwry](https://github.com/mashu3/tkwry).
321
+
322
+ ---
323
+
324
+ ## ๐Ÿ‘จโ€๐Ÿ’ป Author
325
+
326
+ [mashu3](https://github.com/mashu3)
327
+
328
+ ## Contributors
329
+
330
+ [![Contributors](https://contrib.rocks/image?repo=mashu3/tkipw)](https://github.com/mashu3/tkipw/graphs/contributors)