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.
- tkipw-0.0.1/.gitignore +23 -0
- tkipw-0.0.1/LICENSE +21 -0
- tkipw-0.0.1/NOTICE +71 -0
- tkipw-0.0.1/PKG-INFO +330 -0
- tkipw-0.0.1/README.md +285 -0
- tkipw-0.0.1/examples/altair_demo.py +41 -0
- tkipw-0.0.1/examples/bokeh_demo.py +36 -0
- tkipw-0.0.1/examples/ipyleaflet_demo.py +33 -0
- tkipw-0.0.1/examples/pillow_demo.py +43 -0
- tkipw-0.0.1/examples/playground.py +2153 -0
- tkipw-0.0.1/examples/plotly_demo.py +42 -0
- tkipw-0.0.1/js/build.mjs +98 -0
- tkipw-0.0.1/js/package-lock.json +3977 -0
- tkipw-0.0.1/js/package.json +24 -0
- tkipw-0.0.1/js/src/index.js +408 -0
- tkipw-0.0.1/pyproject.toml +90 -0
- tkipw-0.0.1/src/tkipw/__init__.py +89 -0
- tkipw-0.0.1/src/tkipw/app.py +708 -0
- tkipw-0.0.1/src/tkipw/comm_backend.py +282 -0
- tkipw-0.0.1/src/tkipw/display_mode.py +462 -0
- tkipw-0.0.1/src/tkipw/extensions/__init__.py +19 -0
- tkipw-0.0.1/src/tkipw/extensions/altair.py +104 -0
- tkipw-0.0.1/src/tkipw/extensions/bokeh.py +192 -0
- tkipw-0.0.1/src/tkipw/extensions/folium.py +73 -0
- tkipw-0.0.1/src/tkipw/extensions/matplotlib.py +183 -0
- tkipw-0.0.1/src/tkipw/extensions/pillow.py +73 -0
- tkipw-0.0.1/src/tkipw/extensions/pyvista.py +185 -0
- tkipw-0.0.1/src/tkipw/html/runtime.css +9 -0
- tkipw-0.0.1/src/tkipw/html/runtime.js +259 -0
- tkipw-0.0.1/src/tkipw/html_host.py +221 -0
- tkipw-0.0.1/src/tkipw/jupyter.py +229 -0
- tkipw-0.0.1/src/tkipw/manager.py +22 -0
- tkipw-0.0.1/src/tkipw/output.py +397 -0
- tkipw-0.0.1/src/tkipw/protocol.py +34 -0
- tkipw-0.0.1/tests/conftest.py +102 -0
- tkipw-0.0.1/tests/e2e/__init__.py +1 -0
- tkipw-0.0.1/tests/e2e/conftest.py +30 -0
- tkipw-0.0.1/tests/e2e/helpers.py +85 -0
- tkipw-0.0.1/tests/e2e/test_extensions.py +295 -0
- tkipw-0.0.1/tests/e2e/test_webview.py +92 -0
- tkipw-0.0.1/tests/support/__init__.py +5 -0
- tkipw-0.0.1/tests/support/fakes.py +57 -0
- tkipw-0.0.1/tests/unit/test_display_mode.py +162 -0
- tkipw-0.0.1/tests/unit/test_extensions.py +304 -0
- tkipw-0.0.1/tests/unit/test_html_host.py +91 -0
- tkipw-0.0.1/tests/unit/test_jupyter.py +85 -0
- tkipw-0.0.1/tests/unit/test_lifecycle.py +107 -0
- tkipw-0.0.1/tests/unit/test_output.py +153 -0
- tkipw-0.0.1/tests/unit/test_playground.py +212 -0
- 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
|
+
[](https://opensource.org/licenses/MIT)
|
|
49
|
+
[](https://pypi.org/project/tkipw)
|
|
50
|
+
[](https://github.com/mashu3/tkipw/releases)
|
|
51
|
+
[](https://pypi.org/project/tkipw/)
|
|
52
|
+
[](https://pepy.tech/project/tkipw)
|
|
53
|
+
[](https://github.com/mashu3/tkipw)
|
|
54
|
+
[](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
|
+
[](https://github.com/mashu3/tkipw/graphs/contributors)
|