Python ships with the built-in pdb
module. You can use it without installing or importing anything:
Set breakpoints
file.py
# python < 3.7
import pdb
pdb.set_trace()
# python 3.7+
breakpoint()
Is this step optional?
Run your app/file (in your terminal)
Run file + stop at first breakpoint()
:
$ python file.py
Run file and stop at first line (with or without breakpoints):
$ python -m pdb file.py
Run file but ignore all breakpoints:
$ PYTHONBREAKPOINT=0 python file.py
You will see the pdb
prompt:
$ python file.py
> /project/file.py(line number)<module>()
-> print(f'path = {filename}')
(Pdb)
- The line starting with
>
tells you what file, line number and scope (module or function name) you’re currently in - The line starting with
->
is where execution is paused has not been run yet - The line starting with
(Pdb)
is thepdb
prompt waiting for a command - Output starts with
--Call--
when you’ve just stepped into a function - Output starts with
--Return--
when a value is about to be returned - Separate “add breakpoints in file + run in terminal” workflow from “run in terminal without having to set any breakpoints in file” workflow?
- Would the workflow change at all when a debugging test?
Use the debugger (with (Pdb)
commands in your terminal):
- General:
<cr>
— repeat last command!<expr>
— execute python commandh
— help menuh <command>
— help for a commandrun
/restart
— restart debuggerq
/<c-d>
— quit debugger
- Navigate code:
- “Step over”
n
— “next”: continue until next logically executed line (without entering function calls) or until current function’s return statement- useful for following every iteration of a loop
unt
— “until”: continue until line ≥ current line in current file (without entering function calls) or until current function’s return statement- like
n
but based only on moving farther down in current file - useful for not following every iteration of a loop
- like
unt #
— “until line”: continue until line ≥ # in current file (without entering functions) or until current function’s return statement- Like
n
+b
(or the idea ofc #
)
- Like
s
— “step into”: continue until next logically executed line (entering called functions) or until current function’s return statementr
— “return”: continue until current function’s return statementc
— “continue” until next breakpointj #
— “jump” to line number (e.g. to break out of a loop)
- “Step over”
- Navigate stack trace:
w
— print stack trace with most recent frame at bottom and an arrow indicating the current frame (which determines the context of most commands)u
— move up the call stack- e.g. commands like
pp x
may output different values at different points in the stack trace - e.g. useful for spotting the function where a value changed unexpectedly
- e.g. commands like
d
— move down the call stacksource <expr>
— display source of expr
- Inspect values:
locals
— print local variablesa
— print args of current functionp <expr>
— print value of expr- e.g.
p var_1, var_2
- e.g.
pp <expr>
— pretty-print value of exprwhatis <expr>
— print type of exprl
— list 11 lines around current linell
— long-list all lines in current functionl #,#
— list lines in range
- Watch values:
display <expr>
— display value of expr whenever it changes- e.g. useful for watching a variable during a loop:
- e.g.
b #
(in loop body) +c
+display var
+c
+<cr>
, etc
display
— list all active display expressions (instead of just the first one)- useful after defining a watch list of expressions
- e.g.
b #
(in loop body) +c
+display var_1
+display var_2
+display var_3
+c
+display
+c
+display
, etc
undisplay
— clear all display expressionsundisplay <expr>
— stop displaying value of expr
- Breakpoints:
b
— list all breakpoints + their #sb [filename:]lineno
— set bp at line in file (defaults to current file)- e.g.
b util:5
- e.g.
b 5
- e.g.
b [filename:]lineno, condition
— set bp if condition met (e.g. wrong input)- e.g.
b util:5, x == 'abc'
- e.g.
b 5, not x.startsWith(’a’)
- e.g.
b func_name[, condition]
— set bp at first line of function with optional condition- condition can only use function args and global variables available when function is entered (not local function variables); otherwise it will fail
- e.g.
b util.get_path
- e.g.
b get_path, not argument.startsWith(’/’)
cl # […]
— clear bp #s (separate by spaces)cl filename:lineno
— clear all breakpoints at line in filecl
— clear all breakpoints (after confirming)disable #
— disable bp #enable #
— enable bp #ignore # count
— ignore bp # count timescondition # condition
— set/remove condition for bp # (remove if empty)
How to automatically enter debugger when an exception occurs?
Using pdb
to write new code
Useful for actually iterating slowly on new code:
- Write a few lines
- Then write a
breakpoint()
line - Run the file
- Inspect the values via the
Pdb
prompt (including creating temporary variables to save interesting values) to figure out what to write next - Write a few more lines, set a new breakpoint, and rerun with
pdb
- Repeat
I do this with console.log
when writing JavaScript, but this is a way to do the same with Python.
Research 📚
- pdb •
pdb
docs 📚 - Python Debugging With Pdb • Real Python 📖
- Python Debugger Cheat Sheet • Kapeli 📖
- How to use the Python Debugger using the breakpoint() • Patrick Loeber 📖
- Using breakpoint to debug in Python • Trey Hunner 📖
- An Introduction To Python Debugging with the PDB • TutorialEdge 📺
- Using pdb to Inspect Python Objects - YouTube • Pybites 📺
- python debugger crash course: pdb / breakpoint (beginner - intermediate) anthony explains #097 • Anthony Sottile 📺
- python: more advanced breakpoint() usage (intermediate) anthony explains #149 • Anthony Sottile 📺
- Python: Debugger - YouTube • Joe James 📺
- Python Quick Tip: Debugger and breakpoint() • Patrick Loeber 📺
- Python debugging with Python PDB - commands, post mortem and much more • Red Eyed Coder Club 📺
- Command-Line Python Debugging with pdb • NeuralNine 📺
- Start Python Debugging With pdb - YouTube • Real Python 📺