nextpytk 0.3.0__tar.gz → 0.4.0__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.
@@ -1,9 +1,35 @@
1
- # nextpytk — Flask-style Decorator API for Tkinter
2
-
3
- nextpytk wraps Tkinter in Python decorators, inspired by Flask.
4
- Widget registration and layout are decoupled via dependency injection.
5
- All widgets expose a JSON schema for AI/LLM consumption.
6
- Uses ttk widgets where available (Button, Entry, Checkbutton, Radiobutton, Scale, Spinbox, Notebook).
1
+ Metadata-Version: 2.4
2
+ Name: nextpytk
3
+ Version: 0.4.0
4
+ Summary: Accessible, declarative Tkinter applications from ordinary Python functions.
5
+ Project-URL: Homepage, https://github.com/nishimotz/nextpytk
6
+ Project-URL: Repository, https://github.com/nishimotz/nextpytk
7
+ Project-URL: Issues, https://github.com/nishimotz/nextpytk/issues
8
+ Project-URL: Changelog, https://github.com/nishimotz/nextpytk/blob/main/ROADMAP.md
9
+ Author: Takuya Nishimoto
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: accessibility,declarative-ui,gui,tkinter,ttk
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
20
+ Classifier: Topic :: Software Development :: User Interfaces
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.13
23
+ Description-Content-Type: text/markdown
24
+
25
+ # nextpytk
26
+
27
+ Accessible, declarative Tkinter applications from ordinary Python functions.
28
+
29
+ Register widgets as plain Python functions, declare layout separately, and
30
+ keep roles/descriptions in one place. The decorator style is Flask-inspired;
31
+ `schema()` exports the same structure for agents and tools.
32
+ Uses ttk widgets where available.
7
33
 
8
34
  ---
9
35
 
@@ -173,19 +199,25 @@ app.run(layout=b.build())
173
199
  | Decorator | Widget | Callback receives | Returns |
174
200
  |-----------|--------|-------------------|---------|
175
201
  | `@app.label(name, font=..., anchor=..., justify=..., padding=...)` | tk.Label | — | `str` or `dict` |
176
- | `@app.status(name)` | tk.Label (role=status) | — | `str` or `dict` |
202
+ | `@app.status(name)` | tk.Label (`role=status` metadata) | — | `str` or `dict` |
177
203
  | `@app.message(name, width=..., auto_width=...)` | tk.Label (auto-wrap) | — | `str` or `dict` |
178
204
  | `@app.button(name, label=..., enabled_if=...)` | ttk.Button | entry values `dict` | `dict` |
179
205
  | `@app.job(name)` | async callable | entry values `dict` | `dict` |
180
206
  | `@app.entry(name, placeholder=..., show=...)` | ttk.Entry | `str` | `dict` |
181
207
  | `@app.checkbutton(name, text=...)` | ttk.Checkbutton | `bool` | `dict` |
182
208
  | `@app.radiobutton(name, text=..., value=..., group=...)` | ttk.Radiobutton | selected value `str` | `dict` |
209
+ | `@app.combobox(name, values=..., readonly=...)` | ttk.Combobox | selected value `str` | `dict` |
210
+ | `@app.menubar(name)` | tk.Menu (window menubar) | — | menu item list |
183
211
  | `@app.text(name, width=..., height=...)` | tk.Text | full content `str` | `dict` |
184
212
  | `@app.scale(name, from_=..., to=..., orient=...)` | ttk.Scale | value `str` | `dict` |
185
213
  | `@app.spinbox(name, from_=..., to=..., values=...)` | ttk.Spinbox | value `str` | `dict` |
186
214
  | `@app.listbox(name, items=..., selectmode=...)` | tk.Listbox | selected item `str` | `dict` |
187
215
  | `@app.canvas(name, width=..., height=...)` | tk.Canvas | — | — |
188
216
 
217
+ `@app.status` sets schema / accessible `role="status"` metadata. It is **not** an ARIA live region yet (planned for a later release). Prefer it for operation feedback labels; use `@app.label` for static or high-frequency mirror text.
218
+
219
+ `app.run(stages=..., tabposition=...)` and `@app.stages` provide state-driven screen switching (one visible stage at a time). Theme helpers (`apply_theme`, `tokens`, layout chrome) ship in the package root — see `examples/header_demo.py`.
220
+
189
221
  Label options:
190
222
  - `font`: e.g. `font=("TkDefaultFont", 18, "bold")`
191
223
  - `anchor`: e.g. `anchor="e"` (right-aligned)
@@ -234,6 +266,20 @@ Output is JSON-compatible and can serve as LLM Function Calling definitions.
234
266
 
235
267
  ---
236
268
 
269
+ ## Layout debug
270
+
271
+ After widgets are built, `app.debug_layout()` returns JSON-compatible geometry
272
+ and pack/grid info for every registered widget (useful for clipping, minsize,
273
+ and layout regressions; also handy to hand to an agent).
274
+
275
+ ```python
276
+ app.run(layout=["msg", "go"]) # or build via tests / custom runner
277
+ print(app.debug_layout())
278
+ # → {"title": "...", "sections": [{"widgets": [{"name": "msg", "geometry": ..., ...}, ...]}]}
279
+ ```
280
+
281
+ ---
282
+
237
283
  ## Async-Native (asyncio + Tkinter)
238
284
 
239
285
  `app.run_async()` runs the app on an asyncio event loop, cooperatively scheduled
@@ -257,7 +303,9 @@ uv run python examples/grid_temp.py # temperature converter
257
303
  uv run python examples/task_panel.py # multi-button panel
258
304
  uv run python examples/multiscreen.py # order app with screens
259
305
  uv run python examples/widget_gallery.py # all widget types
260
- uv run python examples/disk_usage_flat_viewer.py # ncdu-style viewer (sync)
306
+ uv run python examples/header_demo.py # Layout.header / .status chrome
307
+ uv run python examples/combobox_demo.py # ttk.Combobox
308
+ uv run python examples/menubar_demo.py # menubar
261
309
  uv run python examples/disk_usage_flat_async.py # ncdu-style viewer (async)
262
310
  ```
263
311
 
@@ -265,7 +313,7 @@ uv run python examples/disk_usage_flat_async.py # ncdu-style viewer (async
265
313
 
266
314
  ## Requirements
267
315
 
268
- - Python 3.14 by default (`PYTHON=...` override supported)
316
+ - Python 3.13+ (`requires-python`; examples default to 3.14 via `Makefile` `PYTHON=...`)
269
317
  - Tkinter support in your Python build
270
318
  - No other dependencies
271
319
 
@@ -1,20 +1,11 @@
1
- Metadata-Version: 2.4
2
- Name: nextpytk
3
- Version: 0.3.0
4
- Summary: Flask-style decorator API for tkinter GUI: schema-driven, A11y-first, agent-compatible.
5
- Project-URL: Homepage, https://github.com/nishimotz/nextpytk
6
- Author: Takuya Nishimoto
7
- License: MIT
8
- License-File: LICENSE
9
- Requires-Python: >=3.13
10
- Description-Content-Type: text/markdown
11
-
12
- # nextpytk — Flask-style Decorator API for Tkinter
13
-
14
- nextpytk wraps Tkinter in Python decorators, inspired by Flask.
15
- Widget registration and layout are decoupled via dependency injection.
16
- All widgets expose a JSON schema for AI/LLM consumption.
17
- Uses ttk widgets where available (Button, Entry, Checkbutton, Radiobutton, Scale, Spinbox, Notebook).
1
+ # nextpytk
2
+
3
+ Accessible, declarative Tkinter applications from ordinary Python functions.
4
+
5
+ Register widgets as plain Python functions, declare layout separately, and
6
+ keep roles/descriptions in one place. The decorator style is Flask-inspired;
7
+ `schema()` exports the same structure for agents and tools.
8
+ Uses ttk widgets where available.
18
9
 
19
10
  ---
20
11
 
@@ -184,19 +175,25 @@ app.run(layout=b.build())
184
175
  | Decorator | Widget | Callback receives | Returns |
185
176
  |-----------|--------|-------------------|---------|
186
177
  | `@app.label(name, font=..., anchor=..., justify=..., padding=...)` | tk.Label | — | `str` or `dict` |
187
- | `@app.status(name)` | tk.Label (role=status) | — | `str` or `dict` |
178
+ | `@app.status(name)` | tk.Label (`role=status` metadata) | — | `str` or `dict` |
188
179
  | `@app.message(name, width=..., auto_width=...)` | tk.Label (auto-wrap) | — | `str` or `dict` |
189
180
  | `@app.button(name, label=..., enabled_if=...)` | ttk.Button | entry values `dict` | `dict` |
190
181
  | `@app.job(name)` | async callable | entry values `dict` | `dict` |
191
182
  | `@app.entry(name, placeholder=..., show=...)` | ttk.Entry | `str` | `dict` |
192
183
  | `@app.checkbutton(name, text=...)` | ttk.Checkbutton | `bool` | `dict` |
193
184
  | `@app.radiobutton(name, text=..., value=..., group=...)` | ttk.Radiobutton | selected value `str` | `dict` |
185
+ | `@app.combobox(name, values=..., readonly=...)` | ttk.Combobox | selected value `str` | `dict` |
186
+ | `@app.menubar(name)` | tk.Menu (window menubar) | — | menu item list |
194
187
  | `@app.text(name, width=..., height=...)` | tk.Text | full content `str` | `dict` |
195
188
  | `@app.scale(name, from_=..., to=..., orient=...)` | ttk.Scale | value `str` | `dict` |
196
189
  | `@app.spinbox(name, from_=..., to=..., values=...)` | ttk.Spinbox | value `str` | `dict` |
197
190
  | `@app.listbox(name, items=..., selectmode=...)` | tk.Listbox | selected item `str` | `dict` |
198
191
  | `@app.canvas(name, width=..., height=...)` | tk.Canvas | — | — |
199
192
 
193
+ `@app.status` sets schema / accessible `role="status"` metadata. It is **not** an ARIA live region yet (planned for a later release). Prefer it for operation feedback labels; use `@app.label` for static or high-frequency mirror text.
194
+
195
+ `app.run(stages=..., tabposition=...)` and `@app.stages` provide state-driven screen switching (one visible stage at a time). Theme helpers (`apply_theme`, `tokens`, layout chrome) ship in the package root — see `examples/header_demo.py`.
196
+
200
197
  Label options:
201
198
  - `font`: e.g. `font=("TkDefaultFont", 18, "bold")`
202
199
  - `anchor`: e.g. `anchor="e"` (right-aligned)
@@ -245,6 +242,20 @@ Output is JSON-compatible and can serve as LLM Function Calling definitions.
245
242
 
246
243
  ---
247
244
 
245
+ ## Layout debug
246
+
247
+ After widgets are built, `app.debug_layout()` returns JSON-compatible geometry
248
+ and pack/grid info for every registered widget (useful for clipping, minsize,
249
+ and layout regressions; also handy to hand to an agent).
250
+
251
+ ```python
252
+ app.run(layout=["msg", "go"]) # or build via tests / custom runner
253
+ print(app.debug_layout())
254
+ # → {"title": "...", "sections": [{"widgets": [{"name": "msg", "geometry": ..., ...}, ...]}]}
255
+ ```
256
+
257
+ ---
258
+
248
259
  ## Async-Native (asyncio + Tkinter)
249
260
 
250
261
  `app.run_async()` runs the app on an asyncio event loop, cooperatively scheduled
@@ -268,7 +279,9 @@ uv run python examples/grid_temp.py # temperature converter
268
279
  uv run python examples/task_panel.py # multi-button panel
269
280
  uv run python examples/multiscreen.py # order app with screens
270
281
  uv run python examples/widget_gallery.py # all widget types
271
- uv run python examples/disk_usage_flat_viewer.py # ncdu-style viewer (sync)
282
+ uv run python examples/header_demo.py # Layout.header / .status chrome
283
+ uv run python examples/combobox_demo.py # ttk.Combobox
284
+ uv run python examples/menubar_demo.py # menubar
272
285
  uv run python examples/disk_usage_flat_async.py # ncdu-style viewer (async)
273
286
  ```
274
287
 
@@ -276,7 +289,7 @@ uv run python examples/disk_usage_flat_async.py # ncdu-style viewer (async
276
289
 
277
290
  ## Requirements
278
291
 
279
- - Python 3.14 by default (`PYTHON=...` override supported)
292
+ - Python 3.13+ (`requires-python`; examples default to 3.14 via `Makefile` `PYTHON=...`)
280
293
  - Tkinter support in your Python build
281
294
  - No other dependencies
282
295
 
@@ -1,57 +1,58 @@
1
1
  # ROADMAP — nextpytk
2
2
 
3
- ## Snapshot (v0.3.0)
3
+ ## Snapshot (v0.4.0)
4
4
 
5
5
  ### Implemented widgets (`@app.*`)
6
6
 
7
7
  | kind | Notes |
8
8
  |------|-------|
9
- | `label` / `status` / `message` | Display / word-wrap |
9
+ | `label` / `status` / `message` | Display / word-wrap. `status` sets `role=status` metadata (not a live region yet) |
10
10
  | `button` / `entry` | ttk, `state=` support |
11
11
  | `checkbutton` / `radiobutton` / `scale` / `spinbox` | ttk |
12
- | `text` / `listbox` / `canvas` | tk (Text: tags, paired sync pending) |
12
+ | `combobox` | ttk.Combobox (`readonly`, `values`) |
13
+ | `menubar` | Window menubar with cascades / `enabled_if` |
14
+ | `text` / `listbox` / `canvas` | tk (Text: tags, readonly, paired y-scroll sync) |
13
15
  | `treeview` | Multi-column (`show="headings"`) |
14
16
  | `paned` | `ttk.Panedwindow` + `with app.pane(...)` |
15
17
  | `progressbar` | `state[key]` / `{name}_running` for determinate/indeterminate |
16
18
  | `bind` | Global shortcuts (annotates matching button) |
17
19
 
18
- Infrastructure: `Layout` (pack/grid), `@app.multiview`, `run` / `run_async` / `spawn` / `@app.job`, `schema()`, builder registry, a11y choke point `_apply_a11y`.
20
+ Infrastructure: `Layout` (pack/grid, `.header()` / `.status()` chrome), `@app.multiview`, `@app.stages` / `run(stages=..., tabposition=...)`, `run` / `run_async` / `spawn` / `@app.job`, `schema()`, `debug_layout()`, builder registry, a11y choke point `_apply_a11y`.
19
21
 
20
- ---
22
+ Theme: `tokens` + `apply_theme` / layout helpers (contrast + 44px target-size regressions).
21
23
 
22
- ## Near term (v0.3.x)
24
+ PyPI: Trusted Publishing on `v*` tag push (`.github/workflows/publish.yml`).
23
25
 
24
- ### Type hints
26
+ ### Examples
25
27
 
26
- - [ ] TypedDict / Protocol for decorator arguments (Pyright/mypy completion)
27
- - [ ] Literal types for tkinter constants (`tk.LEFT`, `tk.RIGHT`, `tk.NSEW`, etc.)
28
- - [ ] Fluent API equivalent to `_GridBuilder.columnconfigure`
28
+ - `disk_usage_flat_async.py` — async ncdu-style viewer (`run_async` + `spawn`)
29
+ - `combobox_demo.py`, `menubar_demo.py`, `header_demo.py`, `text_sync_demo.py`
29
30
 
30
- ### Widget expansion
31
+ ---
31
32
 
32
- - [ ] `@app.combobox` / `@app.menubar`
33
- - [ ] Per-widget `bind` (`<<ListboxSelect>>`, `<Double-1>`, etc. — separate from global `bind`)
34
- - [ ] listbox callback value design: pass selection index instead of display string (unify with `treeview`)
35
- - [ ] `@app.text` enhancements — `tag_config`, read-only, paired sync scroll
33
+ ## Near term (post-0.4)
36
34
 
37
35
  ### A11y
38
36
 
37
+ - [ ] `@app.status` live-region behavior (ARIA `aria-live` equivalent / WCAG 4.1.3)
39
38
  - [ ] Tk 9.1 `tk accessible set_acc_*` real-device verification (9.1b0 + NVDA)
40
39
  - [ ] Role vocabulary mapping to Tk side
41
40
  - [ ] Automatic `emit_selection_change` (leverage `apply_state` knowing which widgets changed)
42
41
 
42
+ ### Type hints
43
+
44
+ - [ ] Further TypedDict / Protocol coverage for decorator arguments
45
+ - [ ] Fluent API equivalent to `_GridBuilder.columnconfigure`
46
+
47
+ ### Widget expansion
48
+
49
+ - [ ] Per-widget `bind` (`<<ListboxSelect>>`, `<Double-1>`, etc. — separate from global `bind`)
50
+ - [ ] listbox callback value design: pass selection index instead of display string (unify with `treeview`)
51
+
43
52
  ### Layout DSL
44
53
 
45
54
  - [ ] Nested frames (`Layout` inside `Layout`)
46
55
  - [ ] Global default for `padx`/`pady`
47
- - [ ] `Layout.paired(..., sync_yscroll=True)` — left/right text sync
48
-
49
- ### Public runtime API
50
-
51
- - [x] `build_widgets()`, `widget()`, `widget_kind()`, `widget_specs()`
52
- - [x] `apply_state()`, `sync()` — reusable from custom runners
53
- - [x] `app.run(multiview="...")` entry point
54
- - [x] `register_widget_builder()` — public API for custom kinds
55
56
 
56
57
  ### Agent / LLM integration
57
58
 
@@ -68,14 +69,6 @@ Infrastructure: `Layout` (pack/grid), `@app.multiview`, `run` / `run_async` / `s
68
69
  - [ ] `Layout.style("my_button", background=..., font=...)` style definitions
69
70
  - [ ] Theme switching (`ttk.Style().theme_use(...)`)
70
71
 
71
- ### Async job integration
72
-
73
- - [x] `app.run_async()` + `app.spawn()` — async event loop coexisting with Tk
74
- - [x] `app.spawn(asyncio.to_thread(...))` for non-blocking background jobs
75
- - [x] Sync example: `disk_usage_flat_viewer.py`
76
- - [x] Async example: `disk_usage_flat_async.py` (`app.run_async()` + `app.spawn()`)
77
- - [x] `@app.job(name)` — register async callbacks as @app decorators
78
-
79
72
  ### Declarative components
80
73
 
81
74
  - [ ] `@app.component` decorator (React-like reuse, replacing `Layout`)
@@ -85,3 +78,12 @@ Infrastructure: `Layout` (pack/grid), `@app.multiview`, `run` / `run_async` / `s
85
78
 
86
79
  - [x] Headless execution tests (`tests/` — withdrawn root, build/apply_state/callback drive)
87
80
  - [ ] WidgetSpec unit tests
81
+
82
+ ---
83
+
84
+ ## Earlier snapshots
85
+
86
+ ### v0.3.0
87
+
88
+ Builder registry, headless tests, a11y wiring (`_apply_a11y`), error policy, bugfixes.
89
+ `run_async` / `spawn` / `@app.job`, public runtime API (`build_widgets`, `apply_state`, `register_widget_builder`, …).
@@ -0,0 +1,49 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.18.0"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "nextpytk"
7
+ version = "0.4.0"
8
+ description = "Accessible, declarative Tkinter applications from ordinary Python functions."
9
+ readme = "README.md"
10
+ requires-python = ">=3.13"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Takuya Nishimoto" }]
13
+ keywords = ["tkinter", "ttk", "gui", "accessibility", "declarative-ui"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Programming Language :: Python :: 3.14",
21
+ "Topic :: Software Development :: User Interfaces",
22
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
23
+ "Typing :: Typed",
24
+ ]
25
+ dependencies = []
26
+
27
+ [project.urls]
28
+ Homepage = "https://github.com/nishimotz/nextpytk"
29
+ Repository = "https://github.com/nishimotz/nextpytk"
30
+ Issues = "https://github.com/nishimotz/nextpytk/issues"
31
+ Changelog = "https://github.com/nishimotz/nextpytk/blob/main/ROADMAP.md"
32
+
33
+ [tool.hatch.build.targets.wheel]
34
+ packages = ["src/nextpytk"]
35
+
36
+ [tool.hatch.build.targets.sdist]
37
+ include = ["src/nextpytk", "README.md", "ROADMAP.md"]
38
+
39
+ [tool.uv]
40
+ package = true
41
+
42
+ [dependency-groups]
43
+ dev = [
44
+ "pyright>=1.1.409",
45
+ "pytest>=8.0",
46
+ ]
47
+
48
+ [tool.pytest.ini_options]
49
+ testpaths = ["tests"]
@@ -0,0 +1,42 @@
1
+ """nextpytk: accessible, declarative Tkinter apps from ordinary Python functions."""
2
+
3
+ from nextpytk.app import TkApp
4
+ from nextpytk.layout import Layout, LayoutBuilder
5
+ from nextpytk import types
6
+ from nextpytk.widgets import WidgetSpec
7
+ from nextpytk.theme import (
8
+ apply_theme,
9
+ configure_window,
10
+ content_frame,
11
+ divider,
12
+ heading,
13
+ field_row,
14
+ window_header,
15
+ data_list,
16
+ add_row,
17
+ clear_rows,
18
+ status_bar,
19
+ button,
20
+ )
21
+ from nextpytk import tokens
22
+
23
+ __all__ = [
24
+ "TkApp",
25
+ "Layout",
26
+ "LayoutBuilder",
27
+ "WidgetSpec",
28
+ "types",
29
+ "apply_theme",
30
+ "configure_window",
31
+ "content_frame",
32
+ "divider",
33
+ "heading",
34
+ "field_row",
35
+ "window_header",
36
+ "data_list",
37
+ "add_row",
38
+ "clear_rows",
39
+ "status_bar",
40
+ "button",
41
+ "tokens",
42
+ ]