textual-debugger 0.1.0__tar.gz → 0.1.2__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.
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/PKG-INFO +44 -8
- {textual_debugger-0.1.0/src/tdb → textual_debugger-0.1.2}/README.md +43 -7
- {textual_debugger-0.1.0 → textual_debugger-0.1.2/src/tdb}/README.md +43 -7
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/__init__.py +1 -1
- textual_debugger-0.1.2/src/tdb/_timeouts.py +59 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/app.py +189 -146
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/app_handlers/dap_events.py +40 -23
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/app_handlers/inspection.py +152 -45
- textual_debugger-0.1.2/src/tdb/app_handlers/routing.py +194 -0
- textual_debugger-0.1.2/src/tdb/app_handlers/ui_panels.py +53 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/app_helpers.py +2 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/breakpoint_hook.py +2 -1
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/cli.py +176 -61
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/dap/client.py +61 -27
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/dap/types.py +12 -4
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/inspection.py +39 -30
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/keybindings/__init__.py +20 -11
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/persist.py +73 -39
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/post_mortem.py +39 -28
- textual_debugger-0.1.2/src/tdb/processes_cache.py +239 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/server/event_handler.py +9 -6
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/server/handlers.py +84 -26
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/server/runner.py +8 -2
- textual_debugger-0.1.2/src/tdb/session/child_processes.py +248 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/session/controller.py +220 -297
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/session/messages.py +9 -2
- textual_debugger-0.1.2/src/tdb/session/post_mortem_loader.py +78 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/session/state.py +66 -0
- textual_debugger-0.1.2/src/tdb/session/statement_stepper.py +196 -0
- textual_debugger-0.1.2/src/tdb/session/terminal.py +121 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/session/textual_handler.py +6 -2
- textual_debugger-0.1.2/src/tdb/source_analysis.py +162 -0
- textual_debugger-0.1.2/src/tdb/widgets/_inspection_modal.py +319 -0
- textual_debugger-0.1.2/src/tdb/widgets/async_tasks_modal.py +318 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/widgets/breakpoint_view.py +5 -2
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/widgets/code_view.py +164 -56
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/widgets/evaluate_console.py +6 -2
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/widgets/menu_bar.py +14 -5
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/widgets/modals.py +112 -6
- textual_debugger-0.1.2/src/tdb/widgets/processes_modal.py +276 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/widgets/stack_view.py +3 -1
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/widgets/status_bar.py +3 -1
- textual_debugger-0.1.2/src/tdb/widgets/threads_modal.py +154 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/widgets/variable_view.py +3 -6
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/textual_debugger.egg-info/PKG-INFO +44 -8
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/textual_debugger.egg-info/SOURCES.txt +10 -0
- textual_debugger-0.1.0/src/tdb/widgets/async_tasks_modal.py +0 -340
- textual_debugger-0.1.0/src/tdb/widgets/processes_modal.py +0 -279
- textual_debugger-0.1.0/src/tdb/widgets/threads_modal.py +0 -244
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/LICENSE +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/pyproject.toml +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/setup.cfg +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/__main__.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/app_handlers/__init__.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/dap/__init__.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/dap/messages.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/dap/protocol.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/server/__init__.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/server/app.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/server/rpc_types.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/session/__init__.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/session/event_bus.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/widgets/__init__.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/tdb/widgets/console_view.py +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/textual_debugger.egg-info/dependency_links.txt +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/textual_debugger.egg-info/entry_points.txt +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/textual_debugger.egg-info/requires.txt +0 -0
- {textual_debugger-0.1.0 → textual_debugger-0.1.2}/src/textual_debugger.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: textual-debugger
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: A TUI Python debugger based on textual and debugpy
|
|
5
5
|
Author-email: Al Danial <al.danial@gmail.com>
|
|
6
6
|
License: textual-debugger is licensed to you under the MIT/X Consortium license:
|
|
@@ -130,6 +130,8 @@ as open source.
|
|
|
130
130
|
Videos:
|
|
131
131
|
- [tdb basics](https://youtu.be/2_qf2WZDHuA) views, keybindings, breakpoints, stepping, variable modification, call stack
|
|
132
132
|
- [asyncio tasks](https://youtu.be/vM4tODuqMGg) inspect asyncio tasks and their wait graph; code mod to allow pause
|
|
133
|
+
- [threads and processes](https://youtu.be/J8LOARLs2oQ) inspect variables and call stacks in multiple threads and processes
|
|
134
|
+
- [external terminal](https://youtu.be/121aihjAQ8g) run the debuggee in a separate terminal--ideal for debugging TUI applications
|
|
133
135
|
|
|
134
136
|
## Installation
|
|
135
137
|
|
|
@@ -162,14 +164,16 @@ tdb my_program.py
|
|
|
162
164
|
# debug with arguments
|
|
163
165
|
tdb my_program.py arg1 arg2
|
|
164
166
|
|
|
165
|
-
# add breakpoints at lines 20 and 35 of `my_program.py` and line 14
|
|
167
|
+
# add breakpoints at lines 20 and 35 of `my_program.py` and line 14
|
|
168
|
+
# of `module.py` (when -k is given, --no-stop-on-entry is set and the
|
|
169
|
+
# program runs to the first breakpoint)
|
|
166
170
|
tdb -k 20 -k 35 -k module.py:14 my_program.py arg1 arg2
|
|
167
171
|
|
|
168
172
|
# use a specific virtualenv
|
|
169
173
|
tdb --python /path/to/venv/bin/python my_program.py
|
|
170
174
|
|
|
171
175
|
# step into, or stop at tracebacks in library code
|
|
172
|
-
tdb --no-just-my-code /path/to/venv/bin/python my_program.py
|
|
176
|
+
tdb --no-just-my-code --python /path/to/venv/bin/python my_program.py
|
|
173
177
|
|
|
174
178
|
# run until first breakpoint or exit
|
|
175
179
|
tdb --no-stop-on-entry my_program.py
|
|
@@ -240,7 +244,7 @@ A cursor line (blue) tracks your position; the current execution line is highlig
|
|
|
240
244
|
| Key | Menu |
|
|
241
245
|
|-----|------|
|
|
242
246
|
| `Alt+F` | File (open a different script to debug) |
|
|
243
|
-
| `Alt+C` | Configure (Color Theme, Keybindings) |
|
|
247
|
+
| `Alt+C` | Configure (Color Theme, Keybindings, Step Mode) |
|
|
244
248
|
| `Alt+T` | Threads |
|
|
245
249
|
| `Alt+P` | Processes |
|
|
246
250
|
| `Alt+A` | Async Tasks |
|
|
@@ -275,13 +279,15 @@ those for gdb/pdb, with some aliases and extras thrown in for convenience.
|
|
|
275
279
|
|
|
276
280
|
| Key | Action |
|
|
277
281
|
|-----|--------|
|
|
278
|
-
| `n` | Step over (next
|
|
282
|
+
| `n` | Step over (next statement) |
|
|
279
283
|
| `s` | Step into function call |
|
|
280
284
|
| `o` / `f` / `r` | Step out of current function (also aliased as "finish" and "return") |
|
|
281
285
|
| `c` | Continue execution |
|
|
282
286
|
| `p` | Pause a running program |
|
|
283
287
|
| `t` | Run to cursor position |
|
|
284
288
|
| `u` / `d` | Navigate stack up (caller) / down (callee) |
|
|
289
|
+
| `j` / `k` | Move cursor down / up (with count: `5j`, `10k`) |
|
|
290
|
+
| `G` | Go to last line (with count: `42G` jumps to line 42) |
|
|
285
291
|
| `R` | Restart the debug session |
|
|
286
292
|
| `Ctrl+Q` | Quit |
|
|
287
293
|
|
|
@@ -290,6 +296,23 @@ those for gdb/pdb, with some aliases and extras thrown in for convenience.
|
|
|
290
296
|
normally and stops at the return point. A true gdb-style immediate-return (skipping
|
|
291
297
|
remaining code in the function without executing side effects) is not supported by DAP/debugpy.
|
|
292
298
|
|
|
299
|
+
**Step granularity (statement vs. line):** by default, `n` (step over) and `s` (step into)
|
|
300
|
+
treat a multi-line source statement as a single step. For example, stepping over
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
results = await asyncio.gather(
|
|
304
|
+
fetch(1, 2),
|
|
305
|
+
fetch(2, 1),
|
|
306
|
+
fetch(3, 3),
|
|
307
|
+
)
|
|
308
|
+
print(results) # next stop lands here, not on each sub-line above
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
lands on `print(results)`, not on each interior sub-line of the `gather` call. Switch to
|
|
312
|
+
**Line** mode (Configure > Step Mode) to get debugpy's native per-line behavior, which
|
|
313
|
+
stops on each physical line — useful for inspecting how a complex expression is built up.
|
|
314
|
+
The choice is saved to `~/.config/tdb/config.json`.
|
|
315
|
+
|
|
293
316
|
### Breakpoints
|
|
294
317
|
|
|
295
318
|
Click the gutter in the Code View to toggle a breakpoint, or press `b` in Debug mode.
|
|
@@ -701,8 +724,8 @@ usage: tdb [-h] [-v/--version] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
|
701
724
|
| Flag | Description |
|
|
702
725
|
|------|-------------|
|
|
703
726
|
| `-r HOST:PORT` | Attach to a remote debugpy server |
|
|
704
|
-
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated) |
|
|
705
|
-
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry) |
|
|
727
|
+
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated). Passing `-k` implies `--no-stop-on-entry` so the program runs straight to the first breakpoint. |
|
|
728
|
+
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
|
|
706
729
|
| `--cwd DIR` | Working directory for the debuggee |
|
|
707
730
|
| `--python PATH` | Python interpreter for the debuggee |
|
|
708
731
|
| `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
|
|
@@ -724,12 +747,25 @@ On Windows, it uses `%APPDATA%\tdb\`.
|
|
|
724
747
|
|
|
725
748
|
| File | Contents |
|
|
726
749
|
|------|----------|
|
|
727
|
-
| `config.json` | User preferences (keybinding scheme) |
|
|
750
|
+
| `config.json` | User preferences (keybinding scheme, color theme, step mode) |
|
|
728
751
|
| `breakpoints.json` | Breakpoints from previous sessions, keyed by project directory |
|
|
729
752
|
|
|
730
753
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
731
754
|
directory. Each project's breakpoints are independent.
|
|
732
755
|
|
|
756
|
+
**Step mode** (`step_mode` in `config.json`) controls how `n` (step over) and `s` (step
|
|
757
|
+
into) handle multi-line source statements:
|
|
758
|
+
|
|
759
|
+
| Value | Behavior |
|
|
760
|
+
|-------|----------|
|
|
761
|
+
| `"statement"` (default) | A multi-line statement (e.g. a `gather(...)` call spanning five lines) is one step. The debugger keeps issuing DAP steps until execution leaves the statement, then stops on the next logical line. |
|
|
762
|
+
| `"line"` | debugpy's native per-line behavior — stops on every physical line, including each interior sub-line of a multi-line expression. |
|
|
763
|
+
|
|
764
|
+
Change it from the menu (**Configure > Step Mode**); the choice is saved immediately and
|
|
765
|
+
applies to all future sessions. Breakpoint hits, exceptions, and pauses always interrupt
|
|
766
|
+
a statement step, so a breakpoint set on a sub-line of a multi-line expression still
|
|
767
|
+
fires as expected.
|
|
768
|
+
|
|
733
769
|
## Tech Stack
|
|
734
770
|
|
|
735
771
|
- [textual](https://github.com/Textualize/textual) : TUI framework
|
|
@@ -65,6 +65,8 @@ as open source.
|
|
|
65
65
|
Videos:
|
|
66
66
|
- [tdb basics](https://youtu.be/2_qf2WZDHuA) views, keybindings, breakpoints, stepping, variable modification, call stack
|
|
67
67
|
- [asyncio tasks](https://youtu.be/vM4tODuqMGg) inspect asyncio tasks and their wait graph; code mod to allow pause
|
|
68
|
+
- [threads and processes](https://youtu.be/J8LOARLs2oQ) inspect variables and call stacks in multiple threads and processes
|
|
69
|
+
- [external terminal](https://youtu.be/121aihjAQ8g) run the debuggee in a separate terminal--ideal for debugging TUI applications
|
|
68
70
|
|
|
69
71
|
## Installation
|
|
70
72
|
|
|
@@ -97,14 +99,16 @@ tdb my_program.py
|
|
|
97
99
|
# debug with arguments
|
|
98
100
|
tdb my_program.py arg1 arg2
|
|
99
101
|
|
|
100
|
-
# add breakpoints at lines 20 and 35 of `my_program.py` and line 14
|
|
102
|
+
# add breakpoints at lines 20 and 35 of `my_program.py` and line 14
|
|
103
|
+
# of `module.py` (when -k is given, --no-stop-on-entry is set and the
|
|
104
|
+
# program runs to the first breakpoint)
|
|
101
105
|
tdb -k 20 -k 35 -k module.py:14 my_program.py arg1 arg2
|
|
102
106
|
|
|
103
107
|
# use a specific virtualenv
|
|
104
108
|
tdb --python /path/to/venv/bin/python my_program.py
|
|
105
109
|
|
|
106
110
|
# step into, or stop at tracebacks in library code
|
|
107
|
-
tdb --no-just-my-code /path/to/venv/bin/python my_program.py
|
|
111
|
+
tdb --no-just-my-code --python /path/to/venv/bin/python my_program.py
|
|
108
112
|
|
|
109
113
|
# run until first breakpoint or exit
|
|
110
114
|
tdb --no-stop-on-entry my_program.py
|
|
@@ -175,7 +179,7 @@ A cursor line (blue) tracks your position; the current execution line is highlig
|
|
|
175
179
|
| Key | Menu |
|
|
176
180
|
|-----|------|
|
|
177
181
|
| `Alt+F` | File (open a different script to debug) |
|
|
178
|
-
| `Alt+C` | Configure (Color Theme, Keybindings) |
|
|
182
|
+
| `Alt+C` | Configure (Color Theme, Keybindings, Step Mode) |
|
|
179
183
|
| `Alt+T` | Threads |
|
|
180
184
|
| `Alt+P` | Processes |
|
|
181
185
|
| `Alt+A` | Async Tasks |
|
|
@@ -210,13 +214,15 @@ those for gdb/pdb, with some aliases and extras thrown in for convenience.
|
|
|
210
214
|
|
|
211
215
|
| Key | Action |
|
|
212
216
|
|-----|--------|
|
|
213
|
-
| `n` | Step over (next
|
|
217
|
+
| `n` | Step over (next statement) |
|
|
214
218
|
| `s` | Step into function call |
|
|
215
219
|
| `o` / `f` / `r` | Step out of current function (also aliased as "finish" and "return") |
|
|
216
220
|
| `c` | Continue execution |
|
|
217
221
|
| `p` | Pause a running program |
|
|
218
222
|
| `t` | Run to cursor position |
|
|
219
223
|
| `u` / `d` | Navigate stack up (caller) / down (callee) |
|
|
224
|
+
| `j` / `k` | Move cursor down / up (with count: `5j`, `10k`) |
|
|
225
|
+
| `G` | Go to last line (with count: `42G` jumps to line 42) |
|
|
220
226
|
| `R` | Restart the debug session |
|
|
221
227
|
| `Ctrl+Q` | Quit |
|
|
222
228
|
|
|
@@ -225,6 +231,23 @@ those for gdb/pdb, with some aliases and extras thrown in for convenience.
|
|
|
225
231
|
normally and stops at the return point. A true gdb-style immediate-return (skipping
|
|
226
232
|
remaining code in the function without executing side effects) is not supported by DAP/debugpy.
|
|
227
233
|
|
|
234
|
+
**Step granularity (statement vs. line):** by default, `n` (step over) and `s` (step into)
|
|
235
|
+
treat a multi-line source statement as a single step. For example, stepping over
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
results = await asyncio.gather(
|
|
239
|
+
fetch(1, 2),
|
|
240
|
+
fetch(2, 1),
|
|
241
|
+
fetch(3, 3),
|
|
242
|
+
)
|
|
243
|
+
print(results) # next stop lands here, not on each sub-line above
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
lands on `print(results)`, not on each interior sub-line of the `gather` call. Switch to
|
|
247
|
+
**Line** mode (Configure > Step Mode) to get debugpy's native per-line behavior, which
|
|
248
|
+
stops on each physical line — useful for inspecting how a complex expression is built up.
|
|
249
|
+
The choice is saved to `~/.config/tdb/config.json`.
|
|
250
|
+
|
|
228
251
|
### Breakpoints
|
|
229
252
|
|
|
230
253
|
Click the gutter in the Code View to toggle a breakpoint, or press `b` in Debug mode.
|
|
@@ -636,8 +659,8 @@ usage: tdb [-h] [-v/--version] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
|
636
659
|
| Flag | Description |
|
|
637
660
|
|------|-------------|
|
|
638
661
|
| `-r HOST:PORT` | Attach to a remote debugpy server |
|
|
639
|
-
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated) |
|
|
640
|
-
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry) |
|
|
662
|
+
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated). Passing `-k` implies `--no-stop-on-entry` so the program runs straight to the first breakpoint. |
|
|
663
|
+
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
|
|
641
664
|
| `--cwd DIR` | Working directory for the debuggee |
|
|
642
665
|
| `--python PATH` | Python interpreter for the debuggee |
|
|
643
666
|
| `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
|
|
@@ -659,12 +682,25 @@ On Windows, it uses `%APPDATA%\tdb\`.
|
|
|
659
682
|
|
|
660
683
|
| File | Contents |
|
|
661
684
|
|------|----------|
|
|
662
|
-
| `config.json` | User preferences (keybinding scheme) |
|
|
685
|
+
| `config.json` | User preferences (keybinding scheme, color theme, step mode) |
|
|
663
686
|
| `breakpoints.json` | Breakpoints from previous sessions, keyed by project directory |
|
|
664
687
|
|
|
665
688
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
666
689
|
directory. Each project's breakpoints are independent.
|
|
667
690
|
|
|
691
|
+
**Step mode** (`step_mode` in `config.json`) controls how `n` (step over) and `s` (step
|
|
692
|
+
into) handle multi-line source statements:
|
|
693
|
+
|
|
694
|
+
| Value | Behavior |
|
|
695
|
+
|-------|----------|
|
|
696
|
+
| `"statement"` (default) | A multi-line statement (e.g. a `gather(...)` call spanning five lines) is one step. The debugger keeps issuing DAP steps until execution leaves the statement, then stops on the next logical line. |
|
|
697
|
+
| `"line"` | debugpy's native per-line behavior — stops on every physical line, including each interior sub-line of a multi-line expression. |
|
|
698
|
+
|
|
699
|
+
Change it from the menu (**Configure > Step Mode**); the choice is saved immediately and
|
|
700
|
+
applies to all future sessions. Breakpoint hits, exceptions, and pauses always interrupt
|
|
701
|
+
a statement step, so a breakpoint set on a sub-line of a multi-line expression still
|
|
702
|
+
fires as expected.
|
|
703
|
+
|
|
668
704
|
## Tech Stack
|
|
669
705
|
|
|
670
706
|
- [textual](https://github.com/Textualize/textual) : TUI framework
|
|
@@ -65,6 +65,8 @@ as open source.
|
|
|
65
65
|
Videos:
|
|
66
66
|
- [tdb basics](https://youtu.be/2_qf2WZDHuA) views, keybindings, breakpoints, stepping, variable modification, call stack
|
|
67
67
|
- [asyncio tasks](https://youtu.be/vM4tODuqMGg) inspect asyncio tasks and their wait graph; code mod to allow pause
|
|
68
|
+
- [threads and processes](https://youtu.be/J8LOARLs2oQ) inspect variables and call stacks in multiple threads and processes
|
|
69
|
+
- [external terminal](https://youtu.be/121aihjAQ8g) run the debuggee in a separate terminal--ideal for debugging TUI applications
|
|
68
70
|
|
|
69
71
|
## Installation
|
|
70
72
|
|
|
@@ -97,14 +99,16 @@ tdb my_program.py
|
|
|
97
99
|
# debug with arguments
|
|
98
100
|
tdb my_program.py arg1 arg2
|
|
99
101
|
|
|
100
|
-
# add breakpoints at lines 20 and 35 of `my_program.py` and line 14
|
|
102
|
+
# add breakpoints at lines 20 and 35 of `my_program.py` and line 14
|
|
103
|
+
# of `module.py` (when -k is given, --no-stop-on-entry is set and the
|
|
104
|
+
# program runs to the first breakpoint)
|
|
101
105
|
tdb -k 20 -k 35 -k module.py:14 my_program.py arg1 arg2
|
|
102
106
|
|
|
103
107
|
# use a specific virtualenv
|
|
104
108
|
tdb --python /path/to/venv/bin/python my_program.py
|
|
105
109
|
|
|
106
110
|
# step into, or stop at tracebacks in library code
|
|
107
|
-
tdb --no-just-my-code /path/to/venv/bin/python my_program.py
|
|
111
|
+
tdb --no-just-my-code --python /path/to/venv/bin/python my_program.py
|
|
108
112
|
|
|
109
113
|
# run until first breakpoint or exit
|
|
110
114
|
tdb --no-stop-on-entry my_program.py
|
|
@@ -175,7 +179,7 @@ A cursor line (blue) tracks your position; the current execution line is highlig
|
|
|
175
179
|
| Key | Menu |
|
|
176
180
|
|-----|------|
|
|
177
181
|
| `Alt+F` | File (open a different script to debug) |
|
|
178
|
-
| `Alt+C` | Configure (Color Theme, Keybindings) |
|
|
182
|
+
| `Alt+C` | Configure (Color Theme, Keybindings, Step Mode) |
|
|
179
183
|
| `Alt+T` | Threads |
|
|
180
184
|
| `Alt+P` | Processes |
|
|
181
185
|
| `Alt+A` | Async Tasks |
|
|
@@ -210,13 +214,15 @@ those for gdb/pdb, with some aliases and extras thrown in for convenience.
|
|
|
210
214
|
|
|
211
215
|
| Key | Action |
|
|
212
216
|
|-----|--------|
|
|
213
|
-
| `n` | Step over (next
|
|
217
|
+
| `n` | Step over (next statement) |
|
|
214
218
|
| `s` | Step into function call |
|
|
215
219
|
| `o` / `f` / `r` | Step out of current function (also aliased as "finish" and "return") |
|
|
216
220
|
| `c` | Continue execution |
|
|
217
221
|
| `p` | Pause a running program |
|
|
218
222
|
| `t` | Run to cursor position |
|
|
219
223
|
| `u` / `d` | Navigate stack up (caller) / down (callee) |
|
|
224
|
+
| `j` / `k` | Move cursor down / up (with count: `5j`, `10k`) |
|
|
225
|
+
| `G` | Go to last line (with count: `42G` jumps to line 42) |
|
|
220
226
|
| `R` | Restart the debug session |
|
|
221
227
|
| `Ctrl+Q` | Quit |
|
|
222
228
|
|
|
@@ -225,6 +231,23 @@ those for gdb/pdb, with some aliases and extras thrown in for convenience.
|
|
|
225
231
|
normally and stops at the return point. A true gdb-style immediate-return (skipping
|
|
226
232
|
remaining code in the function without executing side effects) is not supported by DAP/debugpy.
|
|
227
233
|
|
|
234
|
+
**Step granularity (statement vs. line):** by default, `n` (step over) and `s` (step into)
|
|
235
|
+
treat a multi-line source statement as a single step. For example, stepping over
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
results = await asyncio.gather(
|
|
239
|
+
fetch(1, 2),
|
|
240
|
+
fetch(2, 1),
|
|
241
|
+
fetch(3, 3),
|
|
242
|
+
)
|
|
243
|
+
print(results) # next stop lands here, not on each sub-line above
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
lands on `print(results)`, not on each interior sub-line of the `gather` call. Switch to
|
|
247
|
+
**Line** mode (Configure > Step Mode) to get debugpy's native per-line behavior, which
|
|
248
|
+
stops on each physical line — useful for inspecting how a complex expression is built up.
|
|
249
|
+
The choice is saved to `~/.config/tdb/config.json`.
|
|
250
|
+
|
|
228
251
|
### Breakpoints
|
|
229
252
|
|
|
230
253
|
Click the gutter in the Code View to toggle a breakpoint, or press `b` in Debug mode.
|
|
@@ -636,8 +659,8 @@ usage: tdb [-h] [-v/--version] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
|
636
659
|
| Flag | Description |
|
|
637
660
|
|------|-------------|
|
|
638
661
|
| `-r HOST:PORT` | Attach to a remote debugpy server |
|
|
639
|
-
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated) |
|
|
640
|
-
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry) |
|
|
662
|
+
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated). Passing `-k` implies `--no-stop-on-entry` so the program runs straight to the first breakpoint. |
|
|
663
|
+
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
|
|
641
664
|
| `--cwd DIR` | Working directory for the debuggee |
|
|
642
665
|
| `--python PATH` | Python interpreter for the debuggee |
|
|
643
666
|
| `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
|
|
@@ -659,12 +682,25 @@ On Windows, it uses `%APPDATA%\tdb\`.
|
|
|
659
682
|
|
|
660
683
|
| File | Contents |
|
|
661
684
|
|------|----------|
|
|
662
|
-
| `config.json` | User preferences (keybinding scheme) |
|
|
685
|
+
| `config.json` | User preferences (keybinding scheme, color theme, step mode) |
|
|
663
686
|
| `breakpoints.json` | Breakpoints from previous sessions, keyed by project directory |
|
|
664
687
|
|
|
665
688
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
666
689
|
directory. Each project's breakpoints are independent.
|
|
667
690
|
|
|
691
|
+
**Step mode** (`step_mode` in `config.json`) controls how `n` (step over) and `s` (step
|
|
692
|
+
into) handle multi-line source statements:
|
|
693
|
+
|
|
694
|
+
| Value | Behavior |
|
|
695
|
+
|-------|----------|
|
|
696
|
+
| `"statement"` (default) | A multi-line statement (e.g. a `gather(...)` call spanning five lines) is one step. The debugger keeps issuing DAP steps until execution leaves the statement, then stops on the next logical line. |
|
|
697
|
+
| `"line"` | debugpy's native per-line behavior — stops on every physical line, including each interior sub-line of a multi-line expression. |
|
|
698
|
+
|
|
699
|
+
Change it from the menu (**Configure > Step Mode**); the choice is saved immediately and
|
|
700
|
+
applies to all future sessions. Breakpoint hits, exceptions, and pauses always interrupt
|
|
701
|
+
a statement step, so a breakpoint set on a sub-line of a multi-line expression still
|
|
702
|
+
fires as expected.
|
|
703
|
+
|
|
668
704
|
## Tech Stack
|
|
669
705
|
|
|
670
706
|
- [textual](https://github.com/Textualize/textual) : TUI framework
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Centralized timeout constants (seconds).
|
|
2
|
+
|
|
3
|
+
Reasoning per constant lives beside its value so the "why this number?"
|
|
4
|
+
question doesn't require reading commit history or guessing. Group by
|
|
5
|
+
subsystem; alphabetize within group.
|
|
6
|
+
|
|
7
|
+
Bare integers/floats for wall-clock seconds. Always pass to
|
|
8
|
+
`asyncio.wait_for(..., timeout=X)` (or equivalent). Don't multiply
|
|
9
|
+
these together to derive new timeouts — add a new named constant.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# --- DAP protocol round-trips --------------------------------------------
|
|
16
|
+
# debugpy is normally fast (single-digit ms) but some requests block on the
|
|
17
|
+
# debuggee's main thread (e.g. evaluate during a long sync call). 30s gives
|
|
18
|
+
# headroom for those without hanging a user-typed step forever.
|
|
19
|
+
DAP_REQUEST = 30.0
|
|
20
|
+
"""Default per-request timeout for `DAPClient._send`."""
|
|
21
|
+
|
|
22
|
+
# Child-process DAPClient disconnect runs in parallel with the parent's
|
|
23
|
+
# `disconnect(terminate=True)`. debugpy cascades termination from the
|
|
24
|
+
# parent, so the per-child handshake is cleanup, not load-bearing — keep
|
|
25
|
+
# it short so multi-process quit doesn't pile up 8 × 30s waits.
|
|
26
|
+
DAP_DISCONNECT_CHILD = 1.0
|
|
27
|
+
"""Wait for one child DAP session to acknowledge disconnect."""
|
|
28
|
+
|
|
29
|
+
# Parent disconnect is also bounded. The parent's `disconnect` is what
|
|
30
|
+
# actually kills the debuggee in non-remote-attach mode, so we wait a
|
|
31
|
+
# bit longer than children — but still capped to keep quit snappy.
|
|
32
|
+
DAP_DISCONNECT_PARENT = 2.0
|
|
33
|
+
"""Wait for the parent DAP session to acknowledge disconnect."""
|
|
34
|
+
|
|
35
|
+
# Time to wait for debugpy to emit `initialized` after launch/attach.
|
|
36
|
+
# Cold debugpy start (no compiled cache, large dependency graph) can
|
|
37
|
+
# take ~1-3s on modest machines; 10s is comfortable padding.
|
|
38
|
+
DAP_INITIALIZED = 10.0
|
|
39
|
+
"""Wait for `initialized` event after launch / attach."""
|
|
40
|
+
|
|
41
|
+
# Time to wait for a `stopped` event after launch with `stop_on_entry=True`.
|
|
42
|
+
# Same shape as DAP_INITIALIZED — we just need debugpy to reach line 1.
|
|
43
|
+
DAP_STOP_ON_ENTRY = 10.0
|
|
44
|
+
"""Wait for the first `stopped` event when stop_on_entry is set."""
|
|
45
|
+
|
|
46
|
+
# Child-process attach handshake: after a `debugpyAttach` reverse event,
|
|
47
|
+
# the child opens its DAP socket and we connect + initialize. 30s allows
|
|
48
|
+
# for slow forkserver starts on Linux (Python 3.14 default).
|
|
49
|
+
DAP_CHILD_ATTACH = 30.0
|
|
50
|
+
"""End-to-end timeout for connecting + initializing a child DAP session."""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# --- RPC handler waits ---------------------------------------------------
|
|
54
|
+
# Step / continue can run a long tail in multi-process programs: after
|
|
55
|
+
# releasing all breakpoint hits, the remainder of the script may run for
|
|
56
|
+
# many seconds before `terminated` arrives. 30s wasn't enough; 10 min is
|
|
57
|
+
# arbitrary-but-comfortable for typical interactive sessions.
|
|
58
|
+
RPC_STEP_WAIT = 600.0
|
|
59
|
+
"""How long the RPC `_step_action` blocks awaiting the next stop."""
|