imgui_debugger 0.1.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.
- imgui_debugger-0.1.0/LICENSE +21 -0
- imgui_debugger-0.1.0/PKG-INFO +225 -0
- imgui_debugger-0.1.0/README.md +198 -0
- imgui_debugger-0.1.0/pyproject.toml +43 -0
- imgui_debugger-0.1.0/setup.cfg +4 -0
- imgui_debugger-0.1.0/src/imgui_debugger/__init__.py +88 -0
- imgui_debugger-0.1.0/src/imgui_debugger/_assets.py +125 -0
- imgui_debugger-0.1.0/src/imgui_debugger/debugger.py +553 -0
- imgui_debugger-0.1.0/src/imgui_debugger/edit.py +125 -0
- imgui_debugger-0.1.0/src/imgui_debugger/format.py +130 -0
- imgui_debugger-0.1.0/src/imgui_debugger/py.typed +0 -0
- imgui_debugger-0.1.0/src/imgui_debugger/runner.py +91 -0
- imgui_debugger-0.1.0/src/imgui_debugger/scopes.py +734 -0
- imgui_debugger-0.1.0/src/imgui_debugger/search.py +170 -0
- imgui_debugger-0.1.0/src/imgui_debugger/theme.py +129 -0
- imgui_debugger-0.1.0/src/imgui_debugger/tree.py +285 -0
- imgui_debugger-0.1.0/src/imgui_debugger.egg-info/PKG-INFO +225 -0
- imgui_debugger-0.1.0/src/imgui_debugger.egg-info/SOURCES.txt +28 -0
- imgui_debugger-0.1.0/src/imgui_debugger.egg-info/dependency_links.txt +1 -0
- imgui_debugger-0.1.0/src/imgui_debugger.egg-info/requires.txt +8 -0
- imgui_debugger-0.1.0/src/imgui_debugger.egg-info/top_level.txt +1 -0
- imgui_debugger-0.1.0/tests/test_assets.py +38 -0
- imgui_debugger-0.1.0/tests/test_debugger.py +95 -0
- imgui_debugger-0.1.0/tests/test_doctests.py +27 -0
- imgui_debugger-0.1.0/tests/test_edit.py +33 -0
- imgui_debugger-0.1.0/tests/test_format.py +45 -0
- imgui_debugger-0.1.0/tests/test_headless_render.py +123 -0
- imgui_debugger-0.1.0/tests/test_scopes.py +163 -0
- imgui_debugger-0.1.0/tests/test_search.py +56 -0
- imgui_debugger-0.1.0/tests/test_theme.py +33 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Flynn OConnell
|
|
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.
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: imgui_debugger
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A live variable inspector you can drop into any imgui-bundle widget.
|
|
5
|
+
Author-email: Flynn OConnell <flynnoconnell@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/FlynnOConnell/imgui_debugger
|
|
8
|
+
Project-URL: Source, https://github.com/FlynnOConnell/imgui_debugger
|
|
9
|
+
Project-URL: Issues, https://github.com/FlynnOConnell/imgui_debugger/issues
|
|
10
|
+
Keywords: imgui,imgui-bundle,hello-imgui,debugger,inspector,gui,widget
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
16
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: imgui-bundle<2,>=1.92
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
23
|
+
Provides-Extra: docs
|
|
24
|
+
Requires-Dist: pillow>=9; extra == "docs"
|
|
25
|
+
Requires-Dist: numpy>=1.21; extra == "docs"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
<h1 align="center">imgui_debugger</h1>
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<a href="https://pypi.org/project/imgui_debugger/"><img src="https://img.shields.io/pypi/v/imgui_debugger.svg" alt="PyPI version"></a>
|
|
32
|
+
<a href="https://pypi.org/project/imgui_debugger/"><img src="https://img.shields.io/badge/python-3.10%2B-blue.svg" alt="Python 3.10+"></a>
|
|
33
|
+
<a href="LICENSE"><img src="https://img.shields.io/pypi/l/imgui_debugger.svg" alt="License: MIT"></a>
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
<samp>
|
|
37
|
+
<p align="center">
|
|
38
|
+
A live <b>variable inspector</b> for any imgui-bundle widget
|
|
39
|
+
<br>
|
|
40
|
+
<br>
|
|
41
|
+
<a href="#install">install</a> ·
|
|
42
|
+
<a href="#quick-start">quick start</a> ·
|
|
43
|
+
<a href="#scopes">scopes</a> ·
|
|
44
|
+
<a href="#examples">examples</a> ·
|
|
45
|
+
<a href="#configuration-reference">configuration</a> ·
|
|
46
|
+
<a href="https://github.com/FlynnOConnell/imgui_debugger/issues">issues</a>
|
|
47
|
+
</p>
|
|
48
|
+
</samp>
|
|
49
|
+
|
|
50
|
+
## About
|
|
51
|
+
|
|
52
|
+
Point it at a widget and it draws every variable that widget can see, grouped by
|
|
53
|
+
scope, in a collapsible tree that re-reads its values every frame:
|
|
54
|
+
|
|
55
|
+
- **instance** — the object's own `__dict__` and `__slots__`
|
|
56
|
+
- **properties** — `property` descriptors, evaluated live; one that raises shows
|
|
57
|
+
the exception instead of blanking the panel
|
|
58
|
+
- **class** — class attributes from the whole MRO
|
|
59
|
+
- **locals / globals** — the call frame you captured, so you can follow a draw
|
|
60
|
+
method's own variables
|
|
61
|
+
- **imgui** — io, mouse, keyboard, the window rect and the style metrics that
|
|
62
|
+
explain most layout bugs
|
|
63
|
+
- **watches** — anything else you promote to a top-level scope
|
|
64
|
+
|
|
65
|
+
Leaves that are a bool, number, string or color tuple get an inline editor that
|
|
66
|
+
writes straight back onto the object, so you can find the value that fixes the
|
|
67
|
+
layout without restarting the app.
|
|
68
|
+
|
|
69
|
+
It is built for widgets like the ones in
|
|
70
|
+
[mbo_utilities](https://github.com/MillerBrainObservatory/mbo_utilities) and
|
|
71
|
+
[masknmf-toolbox](https://github.com/apasarkar/masknmf-toolbox), but it knows
|
|
72
|
+
nothing about them — it works on any Python object.
|
|
73
|
+
|
|
74
|
+
## Install
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pip install imgui_debugger
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The only dependency is `imgui-bundle` (which provides imgui, hello_imgui,
|
|
81
|
+
immapp and the FontAwesome icon font).
|
|
82
|
+
|
|
83
|
+
## Quick start
|
|
84
|
+
|
|
85
|
+
Inspect one object in its own window, no host app needed:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from imgui_debugger import run_debugger
|
|
89
|
+
|
|
90
|
+
run_debugger({"fs": 9.6, "dz": 5.0, "planes": [1, 2, 3]})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Add a debug window to a widget you already have:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from imgui_debugger import attach
|
|
97
|
+
|
|
98
|
+
class RoiWidget:
|
|
99
|
+
def __init__(self):
|
|
100
|
+
self.threshold = 0.4
|
|
101
|
+
self.debugger = attach(self, title="ROIs widget")
|
|
102
|
+
|
|
103
|
+
def update(self): # your per-frame draw
|
|
104
|
+
...
|
|
105
|
+
self.debugger.capture() # follow this method's locals
|
|
106
|
+
self.debugger.render_window() # draw the debug window
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or draw the tree inline, in a panel you already own:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
self.debugger.render() # toolbar + tree at the current cursor
|
|
113
|
+
self.debugger.draw_tree() # tree only, no toolbar
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Scopes
|
|
117
|
+
|
|
118
|
+
`Debugger.scopes()` returns them in display order: the target's
|
|
119
|
+
`instance` / `properties` / `class`, then your watches, then `locals` /
|
|
120
|
+
`globals`, then `imgui`.
|
|
121
|
+
|
|
122
|
+
| scope | source | writable |
|
|
123
|
+
|-------|--------|----------|
|
|
124
|
+
| `instance` | `vars(obj)` + `__slots__` | yes |
|
|
125
|
+
| `properties` | `property` / `cached_property` on the MRO | only with an `fset` |
|
|
126
|
+
| `class` | class attributes, no methods or descriptors | yes |
|
|
127
|
+
| `locals` | the captured frame's `f_locals` | no (writes do not stick) |
|
|
128
|
+
| `globals` | the captured frame's `f_globals` | yes |
|
|
129
|
+
| `imgui` | `io`, `mouse`, `keyboard`, `window`, `style` | no |
|
|
130
|
+
| watches | `watch(name, value_or_callable)` | depends on the value |
|
|
131
|
+
|
|
132
|
+
A watch takes a value or a zero-argument callable; the callable is re-read every
|
|
133
|
+
frame, so `watch("metadata", lambda: self.metadata)` survives the attribute
|
|
134
|
+
being reassigned:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
dbg.watch("metadata", lambda: self.metadata, role="prop")
|
|
138
|
+
dbg.watch("fps", lambda: {"now": imgui.get_io().framerate}, role="runtime")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`watch_all(obj, ["metadata", "indices"])` does the same for several attributes
|
|
142
|
+
in one call.
|
|
143
|
+
|
|
144
|
+
## Toolbar
|
|
145
|
+
|
|
146
|
+
| control | what it does |
|
|
147
|
+
|---------|--------------|
|
|
148
|
+
| filter | case-insensitive match over names and leaf values, recursing into children (bounded to 6 levels and 64 items per container, memoized per filter string) |
|
|
149
|
+
| expand / collapse | force every node open or shut for one frame |
|
|
150
|
+
| private | include `_name` attributes |
|
|
151
|
+
| edit | turn the inline editors off and read only |
|
|
152
|
+
|
|
153
|
+
## Examples
|
|
154
|
+
|
|
155
|
+
See all examples in [`examples/`](examples/).
|
|
156
|
+
|
|
157
|
+
| name | file | what it shows |
|
|
158
|
+
|------|------|---------------|
|
|
159
|
+
| debug_minimal | [`debug_minimal.py`](examples/debug_minimal.py) | one-shot window over a settings dataclass |
|
|
160
|
+
| debug_widget | [`debug_widget.py`](examples/debug_widget.py) | a widget that owns its debugger, captures its own locals, and toggles it with F12 |
|
|
161
|
+
| debug_edge_window | [`debug_edge_window.py`](examples/debug_edge_window.py) | a fastplotlib `EdgeWindow`, the widget shape pml_utilities and masknmf-toolbox use |
|
|
162
|
+
|
|
163
|
+
## Configuration reference
|
|
164
|
+
|
|
165
|
+
`DebuggerConfig` fields:
|
|
166
|
+
|
|
167
|
+
| field | default | purpose |
|
|
168
|
+
|-------|---------|---------|
|
|
169
|
+
| `target` | `None` | the object whose scopes come first |
|
|
170
|
+
| `title` | `"Debugger"` | header text and default window title |
|
|
171
|
+
| `theme` | `Theme.dark()` | colors |
|
|
172
|
+
| `private` | `False` | show `_name` attributes |
|
|
173
|
+
| `properties` | `True` | show the `properties` scope and expand nested properties |
|
|
174
|
+
| `class_attrs` | `True` | show the `class` scope |
|
|
175
|
+
| `editable` | `True` | inline editors for writable leaves |
|
|
176
|
+
| `show_frame` | `True` | show `locals` / `globals` |
|
|
177
|
+
| `show_runtime` | `True` | show the live `imgui` scope |
|
|
178
|
+
| `max_depth` | `8` | deepest level the tree expands |
|
|
179
|
+
| `max_items` | `200` | rows per container before "+N more" |
|
|
180
|
+
| `value_col` | `0.0` | pixel column values align at; `0` packs them after the name |
|
|
181
|
+
| `show_toolbar` | `True` | draw the filter box and toggles |
|
|
182
|
+
| `window_title`, `window_size`, `resizable` | — | OS window (one-shot mode) |
|
|
183
|
+
| `ini_path` | `~/.imgui_debugger/debugger.ini` | where the layout `.ini` is saved |
|
|
184
|
+
| `assets_folder` | `None` | folder providing the icon font; unset never overrides a host app's |
|
|
185
|
+
|
|
186
|
+
`attach(target, **kwargs)` and `run_debugger(target, **kwargs)` take any of
|
|
187
|
+
these as keyword arguments.
|
|
188
|
+
|
|
189
|
+
## Files on disk
|
|
190
|
+
|
|
191
|
+
Everything the library writes lives under `~/.imgui_debugger/` (override with
|
|
192
|
+
the `IMGUI_DEBUGGER_HOME` env var):
|
|
193
|
+
|
|
194
|
+
| path | written by | purpose |
|
|
195
|
+
|------|-----------|---------|
|
|
196
|
+
| `~/.imgui_debugger/debugger.ini` | `run_debugger` | hello_imgui window layout. Override with `config.ini_path`; an embedding app's own `ini_filename` always wins. |
|
|
197
|
+
| `~/.imgui_debugger/assets/` | you (optional) | user assets folder. Never created automatically; added to hello_imgui's search path when the icon font cannot be resolved. |
|
|
198
|
+
|
|
199
|
+
Embedded use writes nothing: `render()` and `render_window()` only draw.
|
|
200
|
+
|
|
201
|
+
## Notes
|
|
202
|
+
|
|
203
|
+
- Reads are guarded. A property that raises, a `__repr__` that raises, and a
|
|
204
|
+
container that changes size mid-frame all render as a row rather than
|
|
205
|
+
crashing the frame.
|
|
206
|
+
- Values are read fresh every frame, so the tree shows the state of the frame
|
|
207
|
+
you are looking at.
|
|
208
|
+
- Big containers are capped, not truncated silently: a "+N more" line says how
|
|
209
|
+
many rows were left out.
|
|
210
|
+
- Editing writes through the same setter the row was built from — `setattr` for
|
|
211
|
+
an attribute, `__setitem__` for a dict or list entry, the property's `fset`
|
|
212
|
+
for a property.
|
|
213
|
+
|
|
214
|
+
## Acknowledgements
|
|
215
|
+
|
|
216
|
+
The tree rendering, the bounded memoized filter and the value formatting come
|
|
217
|
+
from the metadata inspector in
|
|
218
|
+
[mbo_utilities](https://github.com/MillerBrainObservatory/mbo_utilities) at the
|
|
219
|
+
[Miller Brain Observatory](https://github.com/MillerBrainObservatory). The
|
|
220
|
+
packaging, theming and one-shot harness follow
|
|
221
|
+
[imgui_data_loader](https://github.com/FlynnOConnell/imgui_data_loader).
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
<h1 align="center">imgui_debugger</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://pypi.org/project/imgui_debugger/"><img src="https://img.shields.io/pypi/v/imgui_debugger.svg" alt="PyPI version"></a>
|
|
5
|
+
<a href="https://pypi.org/project/imgui_debugger/"><img src="https://img.shields.io/badge/python-3.10%2B-blue.svg" alt="Python 3.10+"></a>
|
|
6
|
+
<a href="LICENSE"><img src="https://img.shields.io/pypi/l/imgui_debugger.svg" alt="License: MIT"></a>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<samp>
|
|
10
|
+
<p align="center">
|
|
11
|
+
A live <b>variable inspector</b> for any imgui-bundle widget
|
|
12
|
+
<br>
|
|
13
|
+
<br>
|
|
14
|
+
<a href="#install">install</a> ·
|
|
15
|
+
<a href="#quick-start">quick start</a> ·
|
|
16
|
+
<a href="#scopes">scopes</a> ·
|
|
17
|
+
<a href="#examples">examples</a> ·
|
|
18
|
+
<a href="#configuration-reference">configuration</a> ·
|
|
19
|
+
<a href="https://github.com/FlynnOConnell/imgui_debugger/issues">issues</a>
|
|
20
|
+
</p>
|
|
21
|
+
</samp>
|
|
22
|
+
|
|
23
|
+
## About
|
|
24
|
+
|
|
25
|
+
Point it at a widget and it draws every variable that widget can see, grouped by
|
|
26
|
+
scope, in a collapsible tree that re-reads its values every frame:
|
|
27
|
+
|
|
28
|
+
- **instance** — the object's own `__dict__` and `__slots__`
|
|
29
|
+
- **properties** — `property` descriptors, evaluated live; one that raises shows
|
|
30
|
+
the exception instead of blanking the panel
|
|
31
|
+
- **class** — class attributes from the whole MRO
|
|
32
|
+
- **locals / globals** — the call frame you captured, so you can follow a draw
|
|
33
|
+
method's own variables
|
|
34
|
+
- **imgui** — io, mouse, keyboard, the window rect and the style metrics that
|
|
35
|
+
explain most layout bugs
|
|
36
|
+
- **watches** — anything else you promote to a top-level scope
|
|
37
|
+
|
|
38
|
+
Leaves that are a bool, number, string or color tuple get an inline editor that
|
|
39
|
+
writes straight back onto the object, so you can find the value that fixes the
|
|
40
|
+
layout without restarting the app.
|
|
41
|
+
|
|
42
|
+
It is built for widgets like the ones in
|
|
43
|
+
[mbo_utilities](https://github.com/MillerBrainObservatory/mbo_utilities) and
|
|
44
|
+
[masknmf-toolbox](https://github.com/apasarkar/masknmf-toolbox), but it knows
|
|
45
|
+
nothing about them — it works on any Python object.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install imgui_debugger
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The only dependency is `imgui-bundle` (which provides imgui, hello_imgui,
|
|
54
|
+
immapp and the FontAwesome icon font).
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
Inspect one object in its own window, no host app needed:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from imgui_debugger import run_debugger
|
|
62
|
+
|
|
63
|
+
run_debugger({"fs": 9.6, "dz": 5.0, "planes": [1, 2, 3]})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Add a debug window to a widget you already have:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from imgui_debugger import attach
|
|
70
|
+
|
|
71
|
+
class RoiWidget:
|
|
72
|
+
def __init__(self):
|
|
73
|
+
self.threshold = 0.4
|
|
74
|
+
self.debugger = attach(self, title="ROIs widget")
|
|
75
|
+
|
|
76
|
+
def update(self): # your per-frame draw
|
|
77
|
+
...
|
|
78
|
+
self.debugger.capture() # follow this method's locals
|
|
79
|
+
self.debugger.render_window() # draw the debug window
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Or draw the tree inline, in a panel you already own:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
self.debugger.render() # toolbar + tree at the current cursor
|
|
86
|
+
self.debugger.draw_tree() # tree only, no toolbar
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Scopes
|
|
90
|
+
|
|
91
|
+
`Debugger.scopes()` returns them in display order: the target's
|
|
92
|
+
`instance` / `properties` / `class`, then your watches, then `locals` /
|
|
93
|
+
`globals`, then `imgui`.
|
|
94
|
+
|
|
95
|
+
| scope | source | writable |
|
|
96
|
+
|-------|--------|----------|
|
|
97
|
+
| `instance` | `vars(obj)` + `__slots__` | yes |
|
|
98
|
+
| `properties` | `property` / `cached_property` on the MRO | only with an `fset` |
|
|
99
|
+
| `class` | class attributes, no methods or descriptors | yes |
|
|
100
|
+
| `locals` | the captured frame's `f_locals` | no (writes do not stick) |
|
|
101
|
+
| `globals` | the captured frame's `f_globals` | yes |
|
|
102
|
+
| `imgui` | `io`, `mouse`, `keyboard`, `window`, `style` | no |
|
|
103
|
+
| watches | `watch(name, value_or_callable)` | depends on the value |
|
|
104
|
+
|
|
105
|
+
A watch takes a value or a zero-argument callable; the callable is re-read every
|
|
106
|
+
frame, so `watch("metadata", lambda: self.metadata)` survives the attribute
|
|
107
|
+
being reassigned:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
dbg.watch("metadata", lambda: self.metadata, role="prop")
|
|
111
|
+
dbg.watch("fps", lambda: {"now": imgui.get_io().framerate}, role="runtime")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`watch_all(obj, ["metadata", "indices"])` does the same for several attributes
|
|
115
|
+
in one call.
|
|
116
|
+
|
|
117
|
+
## Toolbar
|
|
118
|
+
|
|
119
|
+
| control | what it does |
|
|
120
|
+
|---------|--------------|
|
|
121
|
+
| filter | case-insensitive match over names and leaf values, recursing into children (bounded to 6 levels and 64 items per container, memoized per filter string) |
|
|
122
|
+
| expand / collapse | force every node open or shut for one frame |
|
|
123
|
+
| private | include `_name` attributes |
|
|
124
|
+
| edit | turn the inline editors off and read only |
|
|
125
|
+
|
|
126
|
+
## Examples
|
|
127
|
+
|
|
128
|
+
See all examples in [`examples/`](examples/).
|
|
129
|
+
|
|
130
|
+
| name | file | what it shows |
|
|
131
|
+
|------|------|---------------|
|
|
132
|
+
| debug_minimal | [`debug_minimal.py`](examples/debug_minimal.py) | one-shot window over a settings dataclass |
|
|
133
|
+
| debug_widget | [`debug_widget.py`](examples/debug_widget.py) | a widget that owns its debugger, captures its own locals, and toggles it with F12 |
|
|
134
|
+
| debug_edge_window | [`debug_edge_window.py`](examples/debug_edge_window.py) | a fastplotlib `EdgeWindow`, the widget shape pml_utilities and masknmf-toolbox use |
|
|
135
|
+
|
|
136
|
+
## Configuration reference
|
|
137
|
+
|
|
138
|
+
`DebuggerConfig` fields:
|
|
139
|
+
|
|
140
|
+
| field | default | purpose |
|
|
141
|
+
|-------|---------|---------|
|
|
142
|
+
| `target` | `None` | the object whose scopes come first |
|
|
143
|
+
| `title` | `"Debugger"` | header text and default window title |
|
|
144
|
+
| `theme` | `Theme.dark()` | colors |
|
|
145
|
+
| `private` | `False` | show `_name` attributes |
|
|
146
|
+
| `properties` | `True` | show the `properties` scope and expand nested properties |
|
|
147
|
+
| `class_attrs` | `True` | show the `class` scope |
|
|
148
|
+
| `editable` | `True` | inline editors for writable leaves |
|
|
149
|
+
| `show_frame` | `True` | show `locals` / `globals` |
|
|
150
|
+
| `show_runtime` | `True` | show the live `imgui` scope |
|
|
151
|
+
| `max_depth` | `8` | deepest level the tree expands |
|
|
152
|
+
| `max_items` | `200` | rows per container before "+N more" |
|
|
153
|
+
| `value_col` | `0.0` | pixel column values align at; `0` packs them after the name |
|
|
154
|
+
| `show_toolbar` | `True` | draw the filter box and toggles |
|
|
155
|
+
| `window_title`, `window_size`, `resizable` | — | OS window (one-shot mode) |
|
|
156
|
+
| `ini_path` | `~/.imgui_debugger/debugger.ini` | where the layout `.ini` is saved |
|
|
157
|
+
| `assets_folder` | `None` | folder providing the icon font; unset never overrides a host app's |
|
|
158
|
+
|
|
159
|
+
`attach(target, **kwargs)` and `run_debugger(target, **kwargs)` take any of
|
|
160
|
+
these as keyword arguments.
|
|
161
|
+
|
|
162
|
+
## Files on disk
|
|
163
|
+
|
|
164
|
+
Everything the library writes lives under `~/.imgui_debugger/` (override with
|
|
165
|
+
the `IMGUI_DEBUGGER_HOME` env var):
|
|
166
|
+
|
|
167
|
+
| path | written by | purpose |
|
|
168
|
+
|------|-----------|---------|
|
|
169
|
+
| `~/.imgui_debugger/debugger.ini` | `run_debugger` | hello_imgui window layout. Override with `config.ini_path`; an embedding app's own `ini_filename` always wins. |
|
|
170
|
+
| `~/.imgui_debugger/assets/` | you (optional) | user assets folder. Never created automatically; added to hello_imgui's search path when the icon font cannot be resolved. |
|
|
171
|
+
|
|
172
|
+
Embedded use writes nothing: `render()` and `render_window()` only draw.
|
|
173
|
+
|
|
174
|
+
## Notes
|
|
175
|
+
|
|
176
|
+
- Reads are guarded. A property that raises, a `__repr__` that raises, and a
|
|
177
|
+
container that changes size mid-frame all render as a row rather than
|
|
178
|
+
crashing the frame.
|
|
179
|
+
- Values are read fresh every frame, so the tree shows the state of the frame
|
|
180
|
+
you are looking at.
|
|
181
|
+
- Big containers are capped, not truncated silently: a "+N more" line says how
|
|
182
|
+
many rows were left out.
|
|
183
|
+
- Editing writes through the same setter the row was built from — `setattr` for
|
|
184
|
+
an attribute, `__setitem__` for a dict or list entry, the property's `fset`
|
|
185
|
+
for a property.
|
|
186
|
+
|
|
187
|
+
## Acknowledgements
|
|
188
|
+
|
|
189
|
+
The tree rendering, the bounded memoized filter and the value formatting come
|
|
190
|
+
from the metadata inspector in
|
|
191
|
+
[mbo_utilities](https://github.com/MillerBrainObservatory/mbo_utilities) at the
|
|
192
|
+
[Miller Brain Observatory](https://github.com/MillerBrainObservatory). The
|
|
193
|
+
packaging, theming and one-shot harness follow
|
|
194
|
+
[imgui_data_loader](https://github.com/FlynnOConnell/imgui_data_loader).
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
MIT
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "imgui_debugger"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A live variable inspector you can drop into any imgui-bundle widget."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Flynn OConnell", email = "flynnoconnell@gmail.com" }]
|
|
14
|
+
keywords = ["imgui", "imgui-bundle", "hello-imgui", "debugger", "inspector", "gui", "widget"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
20
|
+
"Topic :: Software Development :: Debuggers",
|
|
21
|
+
"Topic :: Software Development :: User Interfaces",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"imgui-bundle>=1.92,<2",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
dev = ["pytest>=7"]
|
|
29
|
+
docs = ["pillow>=9", "numpy>=1.21"]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/FlynnOConnell/imgui_debugger"
|
|
33
|
+
Source = "https://github.com/FlynnOConnell/imgui_debugger"
|
|
34
|
+
Issues = "https://github.com/FlynnOConnell/imgui_debugger/issues"
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.packages.find]
|
|
37
|
+
where = ["src"]
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.package-data]
|
|
40
|
+
imgui_debugger = ["py.typed"]
|
|
41
|
+
|
|
42
|
+
[tool.pytest.ini_options]
|
|
43
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""imgui_debugger — a live variable inspector for any imgui-bundle widget.
|
|
2
|
+
|
|
3
|
+
Examples
|
|
4
|
+
--------
|
|
5
|
+
Drop a debug window into an app you already have:
|
|
6
|
+
|
|
7
|
+
>>> from imgui_debugger import attach
|
|
8
|
+
>>> dbg = attach(my_widget, title="ROI tab") # doctest: +SKIP
|
|
9
|
+
>>> # each frame, inside your show_gui:
|
|
10
|
+
>>> dbg.render_window() # doctest: +SKIP
|
|
11
|
+
|
|
12
|
+
Inspect an object with no host app at all:
|
|
13
|
+
|
|
14
|
+
>>> from imgui_debugger import run_debugger
|
|
15
|
+
>>> run_debugger({"fs": 9.6, "dz": 5.0}) # doctest: +SKIP
|
|
16
|
+
|
|
17
|
+
Follow a function's own locals while it draws:
|
|
18
|
+
|
|
19
|
+
>>> def draw(self): # doctest: +SKIP
|
|
20
|
+
... rows = self.build_rows()
|
|
21
|
+
... self.dbg.capture()
|
|
22
|
+
... self.dbg.render_window()
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from ._assets import data_dir, default_ini_path, ensure_assets
|
|
28
|
+
from .debugger import Debugger, DebuggerConfig, attach, watch_all
|
|
29
|
+
from .edit import can_edit, edit_value
|
|
30
|
+
from .format import fmt_value, type_label
|
|
31
|
+
from .runner import run_debugger
|
|
32
|
+
from .scopes import (
|
|
33
|
+
Child,
|
|
34
|
+
Scope,
|
|
35
|
+
Watch,
|
|
36
|
+
children_of,
|
|
37
|
+
class_children,
|
|
38
|
+
frame_scopes,
|
|
39
|
+
instance_children,
|
|
40
|
+
object_scopes,
|
|
41
|
+
property_children,
|
|
42
|
+
runtime_scope,
|
|
43
|
+
)
|
|
44
|
+
from .search import clear_cache, matches
|
|
45
|
+
from .theme import Theme, to_vec4
|
|
46
|
+
from .tree import TreeStyle, draw_child, draw_children, draw_scope
|
|
47
|
+
|
|
48
|
+
__version__ = "0.1.0"
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
# widget + harness
|
|
52
|
+
"Debugger",
|
|
53
|
+
"DebuggerConfig",
|
|
54
|
+
"attach",
|
|
55
|
+
"watch_all",
|
|
56
|
+
"run_debugger",
|
|
57
|
+
"ensure_assets",
|
|
58
|
+
"data_dir",
|
|
59
|
+
"default_ini_path",
|
|
60
|
+
# scopes
|
|
61
|
+
"Scope",
|
|
62
|
+
"Child",
|
|
63
|
+
"Watch",
|
|
64
|
+
"children_of",
|
|
65
|
+
"instance_children",
|
|
66
|
+
"property_children",
|
|
67
|
+
"class_children",
|
|
68
|
+
"object_scopes",
|
|
69
|
+
"frame_scopes",
|
|
70
|
+
"runtime_scope",
|
|
71
|
+
# rendering
|
|
72
|
+
"TreeStyle",
|
|
73
|
+
"draw_scope",
|
|
74
|
+
"draw_child",
|
|
75
|
+
"draw_children",
|
|
76
|
+
"can_edit",
|
|
77
|
+
"edit_value",
|
|
78
|
+
"fmt_value",
|
|
79
|
+
"type_label",
|
|
80
|
+
# search
|
|
81
|
+
"matches",
|
|
82
|
+
"clear_cache",
|
|
83
|
+
# theme
|
|
84
|
+
"Theme",
|
|
85
|
+
"to_vec4",
|
|
86
|
+
# meta
|
|
87
|
+
"__version__",
|
|
88
|
+
]
|