guile 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.
- guile-0.4.0/PKG-INFO +157 -0
- guile-0.4.0/README.md +125 -0
- guile-0.4.0/guile/__init__.py +606 -0
- guile-0.4.0/guile/_app.py +273 -0
- guile-0.4.0/guile/_app_win32.py +892 -0
- guile-0.4.0/guile/_nodes.py +114 -0
- guile-0.4.0/guile/_template.py +585 -0
- guile-0.4.0/guile/py.typed +0 -0
- guile-0.4.0/guile/state.py +103 -0
- guile-0.4.0/guile/ui.py +1694 -0
- guile-0.4.0/guile.egg-info/PKG-INFO +157 -0
- guile-0.4.0/guile.egg-info/SOURCES.txt +15 -0
- guile-0.4.0/guile.egg-info/dependency_links.txt +1 -0
- guile-0.4.0/guile.egg-info/requires.txt +10 -0
- guile-0.4.0/guile.egg-info/top_level.txt +1 -0
- guile-0.4.0/pyproject.toml +60 -0
- guile-0.4.0/setup.cfg +4 -0
guile-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: guile
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: A lightweight Python framework for building native desktop apps.
|
|
5
|
+
Author-email: Andres Patrignani <andrespatrignani@ksu.edu>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://andpatrig.github.io/guile
|
|
8
|
+
Project-URL: Repository, https://github.com/andpatrig/guile
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/andpatrig/guile/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/andpatrig/guile/releases
|
|
11
|
+
Keywords: gui,desktop,app,pywebview,reactive
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
20
|
+
Classifier: Intended Audience :: Science/Research
|
|
21
|
+
Classifier: Intended Audience :: Developers
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
Requires-Dist: pywebview>=5.0
|
|
25
|
+
Requires-Dist: matplotlib>=3.5
|
|
26
|
+
Provides-Extra: science
|
|
27
|
+
Requires-Dist: numpy>=1.21; extra == "science"
|
|
28
|
+
Requires-Dist: pandas>=1.3; extra == "science"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: build; extra == "dev"
|
|
31
|
+
Requires-Dist: twine; extra == "dev"
|
|
32
|
+
|
|
33
|
+
# gui**le**
|
|
34
|
+
|
|
35
|
+
A lightweight Python framework for building desktop apps.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Philosophy
|
|
40
|
+
|
|
41
|
+
Guile started as a personal tool for building lab and research apps — the kind of quick internal dashboards, data explorers, and parameter tools that are too specific to justify a full web stack, but too interactive for a script. The goal was always to stay out of the way: write Python top to bottom, get a native window with a clean interface, nothing more.
|
|
42
|
+
|
|
43
|
+
Inspired by the early design of the Julia language — which set out to take the best of Python, R, and MATLAB rather than compromise between them — guile tries to do the same for Python GUIs. In that spirit: guile has the syntax of Streamlit, the single-process simplicity of Tkinter, and the visual polish of a modern web app, without requiring you to write HTML, CSS, or JavaScript.
|
|
44
|
+
|
|
45
|
+
It is not trying to compete with NiceGUI, PyQt, or Dash. It is the right tool for a simple lab, company, or personal project — and deliberately nothing more.
|
|
46
|
+
|
|
47
|
+
**A few specific choices that shape how guile feels:**
|
|
48
|
+
|
|
49
|
+
- **No full-page refresh.** When state changes, only the parts of the UI that actually changed are updated. Text stays in inputs, sliders don't jump, focus is never lost. This is different from Streamlit, which re-executes the whole script and redraws the page on every interaction.
|
|
50
|
+
|
|
51
|
+
- **No nesting hell.** Layout is written top to bottom using `with` blocks, not by nesting constructors inside constructors. `with gui.card():` followed by indented widget calls reads the same way the finished UI looks — no inside-out tree building, no closing parentheses to track.
|
|
52
|
+
|
|
53
|
+
- **No server.** The app runs as a single Python process and opens a native OS window. There is no local HTTP server, no port to bind, no browser tab to manage. This also means packaging with PyInstaller produces a self-contained executable with no runtime dependencies for the end user.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install pywebview
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Copy the `guile/` folder into your project. No further setup.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Quick start
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
import guile as gui
|
|
71
|
+
|
|
72
|
+
count = gui.state(0)
|
|
73
|
+
|
|
74
|
+
@gui.app("Counter", width=400, height=300)
|
|
75
|
+
def ui():
|
|
76
|
+
with gui.col(align="center", justify="center", style="height:100vh"):
|
|
77
|
+
with gui.card(gap=14):
|
|
78
|
+
gui.title("Counter")
|
|
79
|
+
with gui.row(gap=16, align="center", justify="center"):
|
|
80
|
+
gui.button("−", variant="secondary",
|
|
81
|
+
on_click=lambda: count.update(lambda x: x - 1))
|
|
82
|
+
gui.text(count, size="2xl", bold=True,
|
|
83
|
+
style="min-width:64px;text-align:center")
|
|
84
|
+
gui.button("+",
|
|
85
|
+
on_click=lambda: count.update(lambda x: x + 1))
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## How it works
|
|
91
|
+
|
|
92
|
+
- `gui.state(value)` — a reactive value; setting it re-renders the UI automatically
|
|
93
|
+
- `with gui.card():` / `with gui.col():` / `with gui.row():` — layout containers; everything indented goes inside
|
|
94
|
+
- `gui.button()`, `gui.slider()`, `gui.input()`, `gui.table()` — widgets that take `on_click=` or return their current value
|
|
95
|
+
- `gui.figure(fig)` — embed a matplotlib figure inline
|
|
96
|
+
- `gui.leaflet(center, markers=...)` — embed an interactive map
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Examples
|
|
101
|
+
|
|
102
|
+
| File | What it shows |
|
|
103
|
+
|------|--------------|
|
|
104
|
+
| `01_counter.py` | State, buttons, badges |
|
|
105
|
+
| `02_todo.py` | Lists, dynamic rendering, checkboxes |
|
|
106
|
+
| `03_settings.py` | Sliders, selects, form layout |
|
|
107
|
+
| `04_geo_data.py` | Matplotlib figure + Leaflet map |
|
|
108
|
+
| `05_data_tools.py` | Table, date picker, file picker |
|
|
109
|
+
| `06_soil_water.py` | Sliders driving a live chart |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Dependencies
|
|
114
|
+
|
|
115
|
+
| Package | Purpose |
|
|
116
|
+
|---------|---------|
|
|
117
|
+
| `pywebview` | Native window |
|
|
118
|
+
| `matplotlib` | Only if you use `gui.figure()` |
|
|
119
|
+
| `numpy` | Only if your app uses it |
|
|
120
|
+
|
|
121
|
+
Everything else is Python standard library.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Files
|
|
126
|
+
|
|
127
|
+
| File | Role |
|
|
128
|
+
|------|------|
|
|
129
|
+
| `state.py` | Reactive value class |
|
|
130
|
+
| `ui.py` | Render engine + all widgets |
|
|
131
|
+
| `_app.py` | Window lifecycle, pywebview bridge |
|
|
132
|
+
| `_template.py` | Embedded HTML/CSS/JS |
|
|
133
|
+
| `__init__.py` | Public API (`gui.*`) |
|
|
134
|
+
|
|
135
|
+
See `ARCHITECTURE.md` for a deeper explanation of how the files connect.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
## Versions
|
|
141
|
+
|
|
142
|
+
v0.1.0
|
|
143
|
+
First release including docs, reference, and 27 widgets. AP on 22 May 2026
|
|
144
|
+
|
|
145
|
+
v0.2.0
|
|
146
|
+
Added max_height argument to gui.scroll() widget
|
|
147
|
+
Replaced onchange for onblur in gui.multiselect() widget
|
|
148
|
+
|
|
149
|
+
v0.3.0
|
|
150
|
+
Added notify and modal widgets
|
|
151
|
+
Created new examples and improved existing examples
|
|
152
|
+
|
|
153
|
+
v0.4.0
|
|
154
|
+
Added tabs
|
|
155
|
+
Fixed the datetime-local input to display in 24-hour format by setting lang="en-GB"
|
|
156
|
+
|
|
157
|
+
MIT License
|
guile-0.4.0/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# gui**le**
|
|
2
|
+
|
|
3
|
+
A lightweight Python framework for building desktop apps.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Philosophy
|
|
8
|
+
|
|
9
|
+
Guile started as a personal tool for building lab and research apps — the kind of quick internal dashboards, data explorers, and parameter tools that are too specific to justify a full web stack, but too interactive for a script. The goal was always to stay out of the way: write Python top to bottom, get a native window with a clean interface, nothing more.
|
|
10
|
+
|
|
11
|
+
Inspired by the early design of the Julia language — which set out to take the best of Python, R, and MATLAB rather than compromise between them — guile tries to do the same for Python GUIs. In that spirit: guile has the syntax of Streamlit, the single-process simplicity of Tkinter, and the visual polish of a modern web app, without requiring you to write HTML, CSS, or JavaScript.
|
|
12
|
+
|
|
13
|
+
It is not trying to compete with NiceGUI, PyQt, or Dash. It is the right tool for a simple lab, company, or personal project — and deliberately nothing more.
|
|
14
|
+
|
|
15
|
+
**A few specific choices that shape how guile feels:**
|
|
16
|
+
|
|
17
|
+
- **No full-page refresh.** When state changes, only the parts of the UI that actually changed are updated. Text stays in inputs, sliders don't jump, focus is never lost. This is different from Streamlit, which re-executes the whole script and redraws the page on every interaction.
|
|
18
|
+
|
|
19
|
+
- **No nesting hell.** Layout is written top to bottom using `with` blocks, not by nesting constructors inside constructors. `with gui.card():` followed by indented widget calls reads the same way the finished UI looks — no inside-out tree building, no closing parentheses to track.
|
|
20
|
+
|
|
21
|
+
- **No server.** The app runs as a single Python process and opens a native OS window. There is no local HTTP server, no port to bind, no browser tab to manage. This also means packaging with PyInstaller produces a self-contained executable with no runtime dependencies for the end user.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install pywebview
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Copy the `guile/` folder into your project. No further setup.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Quick start
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import guile as gui
|
|
39
|
+
|
|
40
|
+
count = gui.state(0)
|
|
41
|
+
|
|
42
|
+
@gui.app("Counter", width=400, height=300)
|
|
43
|
+
def ui():
|
|
44
|
+
with gui.col(align="center", justify="center", style="height:100vh"):
|
|
45
|
+
with gui.card(gap=14):
|
|
46
|
+
gui.title("Counter")
|
|
47
|
+
with gui.row(gap=16, align="center", justify="center"):
|
|
48
|
+
gui.button("−", variant="secondary",
|
|
49
|
+
on_click=lambda: count.update(lambda x: x - 1))
|
|
50
|
+
gui.text(count, size="2xl", bold=True,
|
|
51
|
+
style="min-width:64px;text-align:center")
|
|
52
|
+
gui.button("+",
|
|
53
|
+
on_click=lambda: count.update(lambda x: x + 1))
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## How it works
|
|
59
|
+
|
|
60
|
+
- `gui.state(value)` — a reactive value; setting it re-renders the UI automatically
|
|
61
|
+
- `with gui.card():` / `with gui.col():` / `with gui.row():` — layout containers; everything indented goes inside
|
|
62
|
+
- `gui.button()`, `gui.slider()`, `gui.input()`, `gui.table()` — widgets that take `on_click=` or return their current value
|
|
63
|
+
- `gui.figure(fig)` — embed a matplotlib figure inline
|
|
64
|
+
- `gui.leaflet(center, markers=...)` — embed an interactive map
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Examples
|
|
69
|
+
|
|
70
|
+
| File | What it shows |
|
|
71
|
+
|------|--------------|
|
|
72
|
+
| `01_counter.py` | State, buttons, badges |
|
|
73
|
+
| `02_todo.py` | Lists, dynamic rendering, checkboxes |
|
|
74
|
+
| `03_settings.py` | Sliders, selects, form layout |
|
|
75
|
+
| `04_geo_data.py` | Matplotlib figure + Leaflet map |
|
|
76
|
+
| `05_data_tools.py` | Table, date picker, file picker |
|
|
77
|
+
| `06_soil_water.py` | Sliders driving a live chart |
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Dependencies
|
|
82
|
+
|
|
83
|
+
| Package | Purpose |
|
|
84
|
+
|---------|---------|
|
|
85
|
+
| `pywebview` | Native window |
|
|
86
|
+
| `matplotlib` | Only if you use `gui.figure()` |
|
|
87
|
+
| `numpy` | Only if your app uses it |
|
|
88
|
+
|
|
89
|
+
Everything else is Python standard library.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Files
|
|
94
|
+
|
|
95
|
+
| File | Role |
|
|
96
|
+
|------|------|
|
|
97
|
+
| `state.py` | Reactive value class |
|
|
98
|
+
| `ui.py` | Render engine + all widgets |
|
|
99
|
+
| `_app.py` | Window lifecycle, pywebview bridge |
|
|
100
|
+
| `_template.py` | Embedded HTML/CSS/JS |
|
|
101
|
+
| `__init__.py` | Public API (`gui.*`) |
|
|
102
|
+
|
|
103
|
+
See `ARCHITECTURE.md` for a deeper explanation of how the files connect.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
## Versions
|
|
109
|
+
|
|
110
|
+
v0.1.0
|
|
111
|
+
First release including docs, reference, and 27 widgets. AP on 22 May 2026
|
|
112
|
+
|
|
113
|
+
v0.2.0
|
|
114
|
+
Added max_height argument to gui.scroll() widget
|
|
115
|
+
Replaced onchange for onblur in gui.multiselect() widget
|
|
116
|
+
|
|
117
|
+
v0.3.0
|
|
118
|
+
Added notify and modal widgets
|
|
119
|
+
Created new examples and improved existing examples
|
|
120
|
+
|
|
121
|
+
v0.4.0
|
|
122
|
+
Added tabs
|
|
123
|
+
Fixed the datetime-local input to display in 24-hour format by setting lang="en-GB"
|
|
124
|
+
|
|
125
|
+
MIT License
|