textual-debugger 0.1.1__tar.gz → 0.1.3__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.
Files changed (73) hide show
  1. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/PKG-INFO +130 -31
  2. {textual_debugger-0.1.1/src/tdb → textual_debugger-0.1.3}/README.md +129 -30
  3. {textual_debugger-0.1.1 → textual_debugger-0.1.3/src/tdb}/README.md +129 -30
  4. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/__init__.py +1 -1
  5. textual_debugger-0.1.3/src/tdb/_timeouts.py +59 -0
  6. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/app.py +332 -151
  7. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/app_handlers/dap_events.py +51 -25
  8. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/app_handlers/inspection.py +194 -44
  9. textual_debugger-0.1.3/src/tdb/app_handlers/routing.py +194 -0
  10. textual_debugger-0.1.3/src/tdb/app_handlers/ui_panels.py +63 -0
  11. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/app_helpers.py +2 -0
  12. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/breakpoint_hook.py +2 -1
  13. textual_debugger-0.1.3/src/tdb/cli.py +605 -0
  14. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/dap/client.py +116 -27
  15. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/dap/types.py +12 -4
  16. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/inspection.py +39 -30
  17. textual_debugger-0.1.3/src/tdb/inspection_full.py +230 -0
  18. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/keybindings/__init__.py +22 -11
  19. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/persist.py +73 -39
  20. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/post_mortem.py +39 -28
  21. textual_debugger-0.1.3/src/tdb/processes_cache.py +239 -0
  22. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/server/event_handler.py +9 -6
  23. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/server/handlers.py +84 -26
  24. textual_debugger-0.1.3/src/tdb/server/runner.py +132 -0
  25. textual_debugger-0.1.3/src/tdb/session/child_processes.py +248 -0
  26. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/session/controller.py +270 -298
  27. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/session/messages.py +9 -2
  28. textual_debugger-0.1.3/src/tdb/session/post_mortem_loader.py +78 -0
  29. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/session/state.py +66 -0
  30. textual_debugger-0.1.3/src/tdb/session/statement_stepper.py +196 -0
  31. textual_debugger-0.1.3/src/tdb/session/terminal.py +121 -0
  32. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/session/textual_handler.py +6 -2
  33. textual_debugger-0.1.3/src/tdb/source_analysis.py +162 -0
  34. textual_debugger-0.1.3/src/tdb/widgets/_inspection_modal.py +319 -0
  35. textual_debugger-0.1.3/src/tdb/widgets/async_tasks_modal.py +318 -0
  36. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/widgets/breakpoint_view.py +5 -2
  37. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/widgets/code_view.py +189 -57
  38. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/widgets/evaluate_console.py +6 -2
  39. textual_debugger-0.1.3/src/tdb/widgets/full_contents_modal.py +223 -0
  40. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/widgets/menu_bar.py +14 -5
  41. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/widgets/modals.py +112 -6
  42. textual_debugger-0.1.3/src/tdb/widgets/processes_modal.py +276 -0
  43. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/widgets/stack_view.py +3 -1
  44. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/widgets/status_bar.py +3 -1
  45. textual_debugger-0.1.3/src/tdb/widgets/threads_modal.py +154 -0
  46. textual_debugger-0.1.3/src/tdb/widgets/variable_view.py +179 -0
  47. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/textual_debugger.egg-info/PKG-INFO +130 -31
  48. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/textual_debugger.egg-info/SOURCES.txt +12 -0
  49. textual_debugger-0.1.1/src/tdb/cli.py +0 -360
  50. textual_debugger-0.1.1/src/tdb/server/runner.py +0 -89
  51. textual_debugger-0.1.1/src/tdb/widgets/async_tasks_modal.py +0 -340
  52. textual_debugger-0.1.1/src/tdb/widgets/processes_modal.py +0 -279
  53. textual_debugger-0.1.1/src/tdb/widgets/threads_modal.py +0 -244
  54. textual_debugger-0.1.1/src/tdb/widgets/variable_view.py +0 -97
  55. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/LICENSE +0 -0
  56. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/pyproject.toml +0 -0
  57. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/setup.cfg +0 -0
  58. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/__main__.py +0 -0
  59. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/app_handlers/__init__.py +0 -0
  60. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/dap/__init__.py +0 -0
  61. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/dap/messages.py +0 -0
  62. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/dap/protocol.py +0 -0
  63. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/server/__init__.py +0 -0
  64. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/server/app.py +0 -0
  65. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/server/rpc_types.py +0 -0
  66. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/session/__init__.py +0 -0
  67. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/session/event_bus.py +0 -0
  68. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/widgets/__init__.py +0 -0
  69. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/tdb/widgets/console_view.py +0 -0
  70. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/textual_debugger.egg-info/dependency_links.txt +0 -0
  71. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/textual_debugger.egg-info/entry_points.txt +0 -0
  72. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/src/textual_debugger.egg-info/requires.txt +0 -0
  73. {textual_debugger-0.1.1 → textual_debugger-0.1.3}/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.1
3
+ Version: 0.1.3
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:
@@ -88,9 +88,9 @@ It specifically supports modules
88
88
  - `threading` (with a thread inspector)
89
89
  - `multiprocessing` / `concurrent.futures` (with automatic child process attachment and a process inspector)
90
90
 
91
- - supports remote attachment to any debugpy-enabled Python program
91
+ - supports remote attachment to debugpy-enabled Python programs
92
92
 
93
- - includes a JSON-RPC server mode for programmatic debug control, making it suitable for
93
+ - includes a JSON-RPC server mode that enables programmatic debug control, making it suitable for
94
94
  automated, headless debugging workflows and AI-assisted debugging
95
95
 
96
96
  - can spawn the debuggee in an external terminal to enable debugging TUI applications
@@ -164,14 +164,16 @@ tdb my_program.py
164
164
  # debug with arguments
165
165
  tdb my_program.py arg1 arg2
166
166
 
167
- # add breakpoints at lines 20 and 35 of `my_program.py` and line 14 of `module.py`
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)
168
170
  tdb -k 20 -k 35 -k module.py:14 my_program.py arg1 arg2
169
171
 
170
172
  # use a specific virtualenv
171
173
  tdb --python /path/to/venv/bin/python my_program.py
172
174
 
173
175
  # step into, or stop at tracebacks in library code
174
- 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
175
177
 
176
178
  # run until first breakpoint or exit
177
179
  tdb --no-stop-on-entry my_program.py
@@ -180,10 +182,20 @@ tdb --no-stop-on-entry my_program.py
180
182
  tdb --terminal xterm my_program.py
181
183
 
182
184
  # attach to a remote Python program that has a debugpy server on port 5678
183
- tdb -r remotehost:5678 my_program.py
185
+ # (source code is automatically downloaded from the remote host)
186
+ tdb -r remotehost:5678
184
187
 
185
- # prevent `argparse` confusion by separating `tdb` switches from
186
- # the debuggee switches by prefixing the debuggee with `--`
188
+ # attach to a remote Python program that has a debugpy server on port 5678
189
+ # and set a breakpoint where tdb and the remote program have the same
190
+ # source code layout
191
+ tdb -r remotehost:5678 -k my_program.py:42
192
+
193
+ # attach to a remote Python program that has a debugpy server on port 5678
194
+ # and set a breakpoint where code on the local host is at a different location
195
+ # than code on the remote host
196
+ tdb -r remotehost:5678 --local-root /my/code/dir --remote-root /app -k my_program.py:42
197
+
198
+ # separate tdb arguments from debuggee arguments with `--`
187
199
  tdb --python /path/to/venv/bin/python -- my_program.py -k 17 --max 23.3
188
200
  ```
189
201
 
@@ -197,7 +209,7 @@ python -m tdb my_program.py
197
209
 
198
210
  ```
199
211
  ┌─ Header ──────────────────────────────────────────────┐
200
- ├─ Menu Bar (File | Configure | Help) ──────────────────┤
212
+ ├─ Menu Bar (File / Configure / Help)───────────────────┤
201
213
  │ │ │
202
214
  │ Code View │ Console View (stdout) │
203
215
  │ (source + breakpoints) ├───────────────────────────┤
@@ -242,7 +254,7 @@ A cursor line (blue) tracks your position; the current execution line is highlig
242
254
  | Key | Menu |
243
255
  |-----|------|
244
256
  | `Alt+F` | File (open a different script to debug) |
245
- | `Alt+C` | Configure (Color Theme, Keybindings) |
257
+ | `Alt+C` | Configure (Color Theme, Keybindings, Step Mode) |
246
258
  | `Alt+T` | Threads |
247
259
  | `Alt+P` | Processes |
248
260
  | `Alt+A` | Async Tasks |
@@ -268,7 +280,7 @@ Switch from Navigate back to Debug mode with `Escape`.
268
280
 
269
281
  > **Note:** Many terminals send the byte sequence `ESC+f` for `Alt+F`, which Textual's
270
282
  ANSI parser rewrites to `Ctrl+Right` (the readline "forward-word" convention).
271
- `tdb` binds both so `Alt+F` works as expected regardless.
283
+ `tdb` binds both so `Alt+F` works as expected.
272
284
 
273
285
  ### Debugging Controls
274
286
 
@@ -277,21 +289,42 @@ those for gdb/pdb, with some aliases and extras thrown in for convenience.
277
289
 
278
290
  | Key | Action |
279
291
  |-----|--------|
280
- | `n` | Step over (next line) |
292
+ | `n` | Step over (next statement) |
281
293
  | `s` | Step into function call |
282
294
  | `o` / `f` / `r` | Step out of current function (also aliased as "finish" and "return") |
283
295
  | `c` | Continue execution |
284
296
  | `p` | Pause a running program |
285
297
  | `t` | Run to cursor position |
286
298
  | `u` / `d` | Navigate stack up (caller) / down (callee) |
299
+ | `j` / `k` | Move cursor down / up (with count: `5j`, `10k`) |
300
+ | `G` | Go to last line (with count: `42G` jumps to line 42) |
301
+ | `e` | Re-display the last error (traceback) |
287
302
  | `R` | Restart the debug session |
288
- | `Ctrl+Q` | Quit |
303
+ | `q q` | Quit |
304
+ | `Ctrl+q` | Quit |
289
305
 
290
306
  > **Note:** `f` ("finish") and `r` ("return") are both aliases for step-out. DAP's only
291
307
  "exit-a-function" primitive is `stepOut`, which runs the rest of the current function
292
308
  normally and stops at the return point. A true gdb-style immediate-return (skipping
293
309
  remaining code in the function without executing side effects) is not supported by DAP/debugpy.
294
310
 
311
+ **Step granularity (statement vs. line):** by default, `n` (step over) and `s` (step into)
312
+ treat a multi-line source statement as a single step. For example, stepping over
313
+
314
+ ```python
315
+ results = await asyncio.gather(
316
+ fetch(1, 2),
317
+ fetch(2, 1),
318
+ fetch(3, 3),
319
+ )
320
+ print(results) # next stop lands here, not on each sub-line above
321
+ ```
322
+
323
+ lands on `print(results)`, not on each interior sub-line of the `gather` call. Switch to
324
+ **Line** mode (Configure > Step Mode) to get debugpy's native per-line behavior, which
325
+ stops on each physical line--useful for inspecting how a complex expression is built up.
326
+ The choice is saved to `~/.config/tdb/config.json`.
327
+
295
328
  ### Breakpoints
296
329
 
297
330
  Click the gutter in the Code View to toggle a breakpoint, or press `b` in Debug mode.
@@ -316,6 +349,11 @@ The Variable View shows a tree of scopes (Locals, Globals) with all variables in
316
349
  frame. Expand nodes to drill into complex objects. Children are loaded lazily on demand.
317
350
  Variable values can be changed in the Evaluate Console.
318
351
 
352
+ Double-click a variable, or highlight the variable with the text cursor in
353
+ the Variables View and press `Enter`
354
+ to display that variable in a modal. This simplifies inspection of
355
+ large or deeply nested data structures.
356
+
319
357
  ### Call Stack
320
358
 
321
359
  The Stack View shows the full call stack. Click a frame to navigate to its source
@@ -323,7 +361,8 @@ location and inspect its variables.
323
361
 
324
362
  ### Evaluate Console
325
363
 
326
- A REPL at the bottom-left evaluates expressions in the current scope:
364
+ A read-evaluate-print loop (REPL) at the bottom left permits
365
+ interactive evaluation of expressions in the current scope:
327
366
 
328
367
  ```
329
368
  >>> len(items)
@@ -349,8 +388,11 @@ The Console View captures stdout (normal text) and stderr (red text) from the de
349
388
  in real time.
350
389
 
351
390
  If your program prints a lot, or prompts for input, or uses colors or
352
- terminal control codes, consider running it in an external terminal
353
- with `--terminal` for the best experience.
391
+ terminal control codes, run the program in an external terminal
392
+ with `--terminal` for a better experience.
393
+ The `--terminal` switch requires a graphical environment and a compatible
394
+ terminal emulator.
395
+
354
396
 
355
397
  ### Crash Detection
356
398
 
@@ -360,6 +402,9 @@ When the debuggee raises an unhandled exception, `tdb`:
360
402
  3. Populates the Stack View with the exception's call stack
361
403
  4. Lets you press `R` to restart or `Escape` to dismiss
362
404
 
405
+ > Note: after dismissing the traceback modal, you
406
+ > can display it again by hitting `e` when focus is in the Code View.
407
+
363
408
  ### Post-Mortem Exception Hook
364
409
 
365
410
  You can have `tdb` pop open automatically when *any* Python program crashes without the
@@ -368,7 +413,6 @@ need to launch through `tdb` up front. Install the hook once at the top of your
368
413
  ```python
369
414
  import sys
370
415
  import tdb
371
-
372
416
  sys.excepthook = tdb.exception_hook
373
417
  ```
374
418
 
@@ -386,11 +430,11 @@ In post-mortem mode you can:
386
430
  - Read the full traceback (including chained `cause`/`context` exceptions) in the Console View
387
431
  - Jump around the source with the full Code View (syntax highlighting, goto-line, etc.)
388
432
 
389
- Stepping, `continue`, breakpoints, restart, and Evaluate are disabled. The original
390
- interpreter is gone, the view is a frozen snapshot. Press `q` to exit.
433
+ Stepping, continue, breakpoints, restart, and the Evaluate View are disabled. The original
434
+ interpreter is gone since the view is a frozen snapshot. Press `q` to exit.
391
435
 
392
436
  The hook is a no-op when stdin/stdout aren't a tty (e.g. when your program is piped or
393
- run from cron), so it's safe to leave installed in production-style code. Snapshots are
437
+ run from cron), so it is safe to leave installed in production code. Snapshots are
394
438
  written to a temp file that is deleted as soon as `tdb` exits.
395
439
 
396
440
  Snapshot depth / breadth is capped (5 levels, 50 children per container) to keep the
@@ -401,7 +445,6 @@ memoization.
401
445
 
402
446
  `tdb` has an improved implemenation of the standard `breakpoint()` function (or equivalently,
403
447
  `pdb.set_trace()`) used to pause at a specific line to inspect, then
404
- here=
405
448
  continuing--use `tdb.breakpoint()`:
406
449
 
407
450
  ```python
@@ -424,7 +467,7 @@ spawns `python -m tdb -r <port>` as a subprocess so the TUI takes over the termi
424
467
  and pauses the calling thread at the line that called `tdb.breakpoint()` (the hook
425
468
  auto-steps out of its own helper so you land in your own frame, not inside
426
469
  `breakpoint_hook.py`). Stepping (`n`/`s`/`o`), `continue`, and setting/removing breakpoints
427
- all work normally; quitting `tdb` (`Ctrl+Q`) detaches without killing the program, and
470
+ all work normally; quitting `tdb` (`Ctrl+q`) detaches without killing the program, and
428
471
  debugpy auto-resumes any threads still paused.
429
472
 
430
473
  This differs from `tdb.exception_hook` in one way:
@@ -437,6 +480,12 @@ drive the user's program forward.
437
480
  As with `exception_hook`, the call is a no-op when stdin/stdout aren't a tty, so it's
438
481
  safe to leave in code paths that sometimes run headless.
439
482
 
483
+ Quitting `tdb` while paused in a `tdb.breakpoint()` session detaches the debugger and
484
+ lets the program continue running normally.
485
+ This behavior matches hitting `c` while in a conventional (that is, the Python
486
+ standard library's) `breakpoint()` session.
487
+ If you want to kill the program instead, use `Ctrl+c` in the terminal running the debuggee.
488
+
440
489
  ### Async Task Inspector
441
490
 
442
491
  For programs using `asyncio`, the menu bar shows an **Async Tasks (N)** label with the count of
@@ -446,13 +495,17 @@ active tasks (updated each time the program stops). Click it to open a full-scre
446
495
  primitive (`Lock.acquire`, `Queue.get`, `asyncio.sleep`, …), and coroutine
447
496
  - **Right pane**: detail view with full stack trace and an expandable variable tree (same
448
497
  as the main Variables View) for the selected task
449
- - Press `g` to switch the right pane to the **wait graph** a tree showing each blocked
498
+ - Press `g` to switch the right pane to the **wait graph** which is a tree showing
499
+ each blocked
450
500
  task, the asyncio primitive it's parked on, and the task(s) holding that primitive.
451
501
  Cycles (deadlocks) are highlighted in red both in the task table and as a "Deadlock
452
502
  cycles" section at the top of the graph. Selecting a node in the tree highlights the
453
503
  corresponding task in the table.
454
504
  - Navigate with arrow keys; press `r` to refresh, `Escape` to close
455
505
 
506
+ > Note: Async task relationships may be directed acyclic graphs (DAGs) rather than trees
507
+ > but I don't know of a way to visualize DAGs in textual.
508
+
456
509
  RPC equivalents:
457
510
 
458
511
  ```bash
@@ -564,6 +617,36 @@ All debugging features (breakpoints, stepping, variable inspection, threads, pro
564
617
  async tasks) work in remote attach mode. The Code View automatically navigates to the
565
618
  source file when the program stops.
566
619
 
620
+ **Mapping remote paths to local copies (`--local-root` / `--remote-root`):** when the
621
+ debuggee lives on another machine, or in a container, or simply in a different directory
622
+ on the same machine, the source paths it reports (and the paths it expects breakpoints
623
+ to refer to) won't match anything on the `tdb` host. To bridge that gap, give `tdb` one
624
+ or more `--local-root` / `--remote-root` pairs. Each `--local-root` points at a local
625
+ directory containing a copy of the code; each `--remote-root` is the corresponding path
626
+ on the debuggee. The two flags must be supplied in equal numbers and are paired in CLI
627
+ order via `zip()`, so the first `--local-root` matches the first `--remote-root`, the
628
+ second matches the second, and so on. `debugpy` then translates paths bidirectionally:
629
+ breakpoints set on a local file land on the matching remote file, and source paths
630
+ returned in stopped-events / stack-traces are rewritten back to the local copy so the
631
+ Code View loads directly from disk (no DAP `source` round-trip needed).
632
+
633
+ These flags are required whenever you want to set a `-k` breakpoint against a remote
634
+ debuggee whose code lives at a different path than your local copy. For example, if the
635
+ remote runs `program.py` at `/path/to/code/program.py` and your local copy is at
636
+ `/local/project/code/program.py`, set a breakpoint at line 321 with:
637
+
638
+ ```bash
639
+ tdb -r RHOST:15678 \
640
+ --local-root /local/project/code \
641
+ --remote-root /path/to/code \
642
+ -k program.py:321
643
+ ```
644
+
645
+ With `--local-root` set, a relative `-k FILE:LINE` is resolved by searching each
646
+ `--local-root` directory in CLI order (first match wins); absolute paths still work as
647
+ before. Multiple pairs can be supplied to mirror multiple source trees (e.g. an
648
+ application directory and a shared library directory) in one invocation.
649
+
567
650
  ### External Terminal Support
568
651
 
569
652
  Some Python programs, notably text user interfaces, use terminal control
@@ -691,22 +774,25 @@ Each is JSON with `event`, `data`, and `timestamp` fields.
691
774
  ## CLI Reference
692
775
 
693
776
  ```
694
- usage: tdb [-h] [-v/--version] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
695
- [--no-just-my-code] [--no-subprocess] [--python PYTHON]
696
- [-d/--doc] [--doc-text] [--keybindings {default,vim,emacs}]
777
+ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
778
+ [--no-just-my-code] [--no-subprocess] [--python PYTHON] [--pv]
779
+ [--keybindings {default,vim,emacs}]
697
780
  [--terminal {xterm,konsole,gnome-terminal,ghostty,kitty,iterm2,warp,wezterm,terminator}]
698
- [--server] [--headless] [-k FILE:LINE|LINE] [--server-port SERVER_PORT]
781
+ [--local-root PATH] [--remote-root PATH]
782
+ [--server] [--headless] [-k FILE:LINE|LINE] [--server-port SERVER_PORT] [-d] [--doc-text]
699
783
  [program] [args ...]
700
-
701
784
  ```
702
785
 
703
786
  | Flag | Description |
704
787
  |------|-------------|
705
788
  | `-r HOST:PORT` | Attach to a remote debugpy server |
706
- | `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated) |
707
- | `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry) |
789
+ | `--local-root PATH` | Local directory containing a copy of remote code (repeat to mirror multiple trees). Pair with `--remote-root`; counts must match. Required when `-k` sets a breakpoint against a remote debuggee whose code lives at a different path. |
790
+ | `--remote-root PATH` | Remote directory matched to `--local-root` (same CLI position via `zip()`). |
791
+ | `-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. |
792
+ | `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
708
793
  | `--cwd DIR` | Working directory for the debuggee |
709
794
  | `--python PATH` | Python interpreter for the debuggee |
795
+ | `--pv` | Shorthand for --python .venv/bin/python |
710
796
  | `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
711
797
  (default: skipped). On uncaught exceptions, the crash modal always shows the full traceback
712
798
  including library frames, regardless of this flag. |
@@ -726,12 +812,25 @@ On Windows, it uses `%APPDATA%\tdb\`.
726
812
 
727
813
  | File | Contents |
728
814
  |------|----------|
729
- | `config.json` | User preferences (keybinding scheme) |
815
+ | `config.json` | User preferences (keybinding scheme, color theme, step mode) |
730
816
  | `breakpoints.json` | Breakpoints from previous sessions, keyed by project directory |
731
817
 
732
818
  Breakpoints are saved on exit and restored when debugging a program in the same
733
819
  directory. Each project's breakpoints are independent.
734
820
 
821
+ **Step mode** (`step_mode` in `config.json`) controls how `n` (step over) and `s` (step
822
+ into) handle multi-line source statements:
823
+
824
+ | Value | Behavior |
825
+ |-------|----------|
826
+ | `"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. |
827
+ | `"line"` | debugpy's native per-line behavior (stops on every physical line, including each interior sub-line of a multi-line expression)|
828
+
829
+ Change it from the menu (**Configure > Step Mode**); the choice is saved immediately and
830
+ applies to all future sessions. Breakpoint hits, exceptions, and pauses always interrupt
831
+ a statement step, so a breakpoint set on a sub-line of a multi-line expression still
832
+ fires as expected.
833
+
735
834
  ## Tech Stack
736
835
 
737
836
  - [textual](https://github.com/Textualize/textual) : TUI framework