Getting Started¶
This tutorial guides you through running a Python script with Debug Dojo, inspecting
state inside the dpdb interactive debugger, and using injected helper functions.
Prerequisites¶
Ensure you have Python 3.12+ and uv installed.
1. Zero-Install CLI Debugging¶
With debug-dojo, you can execute any Python script via uvx while automatically
configuring dpdb and injecting inspection shortcuts into Python's builtins.
Create a sample script named debug_demo.py:
"""Sample script demonstrating Debug Dojo builtins and dpdb."""
config_payload = {
"server": "us-east-1",
"retries": 3,
"features": ["auth", "caching", "metrics"],
}
# Injected helpers are available without importing!
p(config_payload)
i(config_payload)
b()
Run the script using uvx debug-dojo (or dojo when installed):
# Output formatted by Rich inspect╭─────────────────────────────── <class 'dict'> ───────────────────────────────╮
│ dict() -> new empty dictionary │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────╮ │
│ │ {'server': 'us-east-1', 'retries': 3, 'features': ['auth', 'caching'... │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
│ │
│ clear = def clear(...) D.clear() -> None. Remove all items from D. │
│ copy = def copy(...) D.copy() -> a shallow copy of D │
│ items = def items(...) D.items() -> a set-like object providing a view │
│ keys = def keys(...) D.keys() -> a set-like object providing a view │
╰──────────────────────────────────────────────────────────────────────────────╯
# b() stops execution in dpdbp config_payload['server']'us-east-1'c
2. Comparing Objects Side-by-Side¶
Use the c(obj1, obj2) helper to compare two dictionaries, objects, or data models.
Differences are displayed in a formatted side-by-side terminal table.
┌───────────────────────────────────────┬──────────────────────────────────────┐
│ ╭───────────────────────────────────╮ │ ╭──────────────────────────────────╮ │
│ │ <class 'dict'> │ │ │ <class 'dict'> │ │
│ │ │ │ │ │ │
│ │ Value: │ │ │ Value: │ │
│ │ {'a': 1, 'b': 2} │ │ │ {'a': 1, 'b': 3} │ │
│ │ │ │ │ │ │
│ │ No attributes or methods to │ │ │ No attributes or methods to │ │
│ │ display for this type. │ │ │ display for this type. │ │
│ ╰───────────────────────────────────╯ │ ╰──────────────────────────────────╯ │
└───────────────────────────────────────┴──────────────────────────────────────┘
3. In-Code Activation¶
When running tests or scripts where you do not use the debug-dojo CLI runner, import
debug_dojo.install once in your module or test fixture:
import debug_dojo.install
# The following helpers are now globally accessible:
# - b(): Enter the dpdb debugger
# - p(obj): Rich pretty-print
# - i(obj): Rich object inspection
# - c(obj1, obj2): Side-by-side comparison table
You can also use the pdb / ipdb-compatible top-level API or set
PYTHONBREAKPOINT=debug_dojo.set_trace:
import debug_dojo
debug_dojo.set_trace()
# Or enter post-mortem debugging directly:
# debug_dojo.post_mortem()
# debug_dojo.pm()
4. Automatic Post-Mortem Debugging¶
When debug-dojo encounters an unhandled exception, it renders the traceback and crash
banner with Rich and enters a dpdb post-mortem debugging session at the exact frame
where the failure occurred:
<b>Error while running failing_script.py:</b>
ZeroDivisionError: division by zero
Traceback (most recent call last):
File "/workspace/failing_script.py", line 4, in <module>
compute(0)
File "/workspace/failing_script.py", line 2, in compute
return 100 / divisor
^^^^^^^^^^^^^
ZeroDivisionError: division by zero
<b>Entering post-mortem debugging session...</b>
╭──────────── Dojo Post-Mortem — ZeroDivisionError ────────────╮
│ ZeroDivisionError: division by zero │
│ Location: /workspace/failing_script.py:2 in compute() │
╰──────────────────────────────────────────────────────────────╯
> /workspace/failing_script.py(2)compute()
----> 2 return 100 / divisor
↳ Line: divisor=0p divisor0q
Architecture & Lifecycles¶
The diagrams below describe how debug-dojo sets up the debugging environment,
executes targets, and manages failure states.
Component Architecture¶
flowchart TD
CLI["debug-dojo / dojo CLI (cli.py)"] --> INSTALLER["Installers (_core/installers.py)"]
INSTALLER --> BUILTINS["Python builtins (b, p, i, c)"]
INSTALLER --> HOOK["sys.breakpointhook (_core/debugger/session.py)"]
CLI --> EXEC["Target Execution (_core/execution.py)"]
BUILTINS --> EXEC
HOOK --> EXEC
EXEC -->|Unhandled Exception| PM["dpdb Post-Mortem (_core/debugger/session.py)"]
Execution Lifecycle¶
sequenceDiagram
autonumber
actor Dev as Developer
participant CLI as debug-dojo CLI
participant Inst as Tool Installer
participant Target as Target Script
participant Dpdb as dpdb Debugger
Dev->>CLI: uvx debug-dojo script.py
CLI->>Inst: install_tools()
Inst->>Inst: Inject b, p, i, c into builtins
Inst->>Dpdb: Configure sys.breakpointhook
CLI->>Target: Execute via runpy
Target->>Dpdb: b() or breakpoint() triggered
Dpdb-->>Dev: Interactive dpdb> Prompt
State Lifecycle¶
stateDiagram-v2
[*] --> Initializing: Invoke debug-dojo
Initializing --> InjectingTools: Install b, p, i, c & dpdb hook
InjectingTools --> RunningTarget: Execute script / module / exec
RunningTarget --> Completed: Script exits successfully
RunningTarget --> PostMortem: Unhandled exception raised
PostMortem --> Terminated: Developer exits dpdb
Completed --> [*]
Terminated --> [*]
Development Workflow¶
To contribute to Debug Dojo, clone the repository and synchronize the environment:
Run tests and verification tasks using Poe the Poet:
# Run unit tests with coverage
uv run poe test
# Run all code quality checks
uv run poe code-quality
# Preview documentation locally
uv run poe docs-serve
Tip
When browsing docs, press / or Cmd+K (or Ctrl+K on Linux/Windows) to search documentation symbols and pages. Hovering internal links activates floating previews.