pyguides

pdb module

Overview

pdb is the Python debugger, part of the standard library. It lets you stop execution of a program and inspect the state of variables, evaluate expressions, and step through code line by line. It is useful when you need to understand why a program is behaving unexpectedly or crashing.

pdb is invoked in three main ways:

# 1. Run from the command line
python -m pdb script.py

# 2. Insert into your source code
import pdb; pdb.set_trace()

# 3. Use breakpoint() (Python 3.7+)
breakpoint()

Invoking the Debugger

From the command line

Running python -m pdb script.py starts the debugger before the first line of the script executes. The (Pdb) prompt appears immediately:

python -m pdb my_script.py
# > <string>(1)<module>
# -> import my_module
# (Pdb)

You can also pass arguments to your script:

python -m pdb my_script.py arg1 arg2

Within a running script

Insert breakpoint() anywhere in your code to pause execution at that point. This is the cleanest approach and respects the PYTHONBREAKPOINT environment variable.

def divide(a, b):
    result = a / b
    return result

def main():
    x = 10
    y = 0
    breakpoint()  # execution stops here
    print(divide(x, y)

main()

Disabling breakpoint entirely

Set the PYTHONBREAKPOINT environment variable to 0 to disable all breakpoint() calls without removing them from the code:

PYTHONBREAKPOINT=0 python my_script.py

Conditional breakpoints

Append a condition to the break command to only pause when the condition is true:

# Inside pdb:
(Pdb) break 15, count > 3

In the source, use pdb.set_trace() with a condition:

import pdb

for i in range(100):
    if i > 50:
        pdb.set_trace()  # only stops when i > 50
    process(i)

PDB Commands

The debugger accepts single-character commands. Most can be shortened to one letter.

CommandShortDescription
stepsExecute the current line, stop inside any called function
nextnExecute the current line, do not descend into called functions
continuecResume execution until the next breakpoint or the program finishes
returnrRun until the current function returns
untiluntContinue until the line number is greater than the current
# my_script.py
def faulty_func(x):
    result = x * 2  # line 3
    return result   # line 4

faulty_func(5)      # line 7
$ python -m pdb my_script.py
# (Pdb) break 3
# Breakpoint 1 at /path/my_script.py:3
# (Pdb) continue
# > .../my_script.py(3)faulty_func()
# -> result = x * 2
# (Pdb) step
# > .../my_script.py(4)faulty_func()
# -> return result
# (Pdb) next
# (Pdb) return
# The program finished.

Inspecting state

CommandShortDescription
printpPrint the value of an expression
ppppPretty-print the value
listlShow source code around the current line
longlistllShow the full source of the current function
wherewPrint the full stack trace
upuMove up one stack frame
downdMove down one stack frame
argsaPrint the arguments of the current function
sourcesoPrint the source code of an object
# (Pdb) p my_var
# 42
# (Pdb) pp some_dict
# {'key': 'value',
#  'nested': {'a': 1}}
# (Pdb) where
#   <string>(1)<module>()
# -> faulty_func(5)
#   /path/my_script.py(7)<module>()
# (Pdb) args
# x = 5
# (Pdb) up
# > <string>(1)<module>()
# (Pdb) p x
# 5

Breakpoints

CommandShortDescription
breakbSet a breakpoint at a line or function
tbreaktbSet a temporary breakpoint (deleted after hit)
disabledisDisable a breakpoint
enableenaRe-enable a breakpoint
clearclDelete a breakpoint by number
commandsSet commands to run automatically when a breakpoint is hit
# (Pdb) break 10
# Breakpoint 1 at /path/my_script.py:10
# (Pdb) break my_func
# Breakpoint 2 at /path/my_script.py:5
# (Pdb) break
# Num Type         Disp Enb Address    What
# 1   breakpoint   keep yes 0x...      my_script.py:10
# 2   breakpoint   keep yes 0x...      my_script.py:5
# (Pdb) disable 1
# (Pdb) clear 2
# Deleted breakpoint 2

Managing execution

CommandShortDescription
quitqExit the debugger and terminate the program
exitexExit the debugger and terminate the program
jumpjContinue execution from a different line
interruptPress Enter to interrupt while the program is running

Evaluating Python code

Prefix any command with ! to evaluate it as Python, or just type an expression at the (Pdb) prompt to print it:

# (Pdb) !my_var = 99
# (Pdb) p my_var
# 99
# (Pdb) !import os; print(os.getcwd())
# /home/user/project

Post-Mortem Debugging

When an unhandled exception causes a crash, pdb.post_mortem() drops you into the debugger with the traceback loaded:

import pdb

def risky():
    return 1 / 0

try:
    risky()
except ZeroDivisionError:
    pdb.post_mortem()

Running this script produces:

$ python my_script.py
# > .../my_script.py(3)risky()
# -> return 1 / 0
# (Pdb)

Running Without Pdb

pdb.pm() enters post-mortem mode directly from the most recent exception:

import pdb

try:
    int("not a number")
except ValueError:
    pdb.pm()

Configuration

pdb reads a startup file at ~/.pdbrc if it exists. Commands in this file run automatically when pdb starts:

# ~/.pdbrc
# Enable pretty-printing by default
pp locals()

# Always show the full stack on entry
where

To skip the startup file, use python -m pdb -c "" script.py.

Command-Line Options

OptionDescription
-m pdbRun pdb as a module
-c commandExecute a pdb command (can be used multiple times)
-m pdb script.py --args arg1Pass arguments after --
# Run script with two pdb commands before first stop
python -m pdb -c "break 10" -c "continue" my_script.py

# Pass arguments to the script
python -m pdb my_script.py -- arg1 arg2

Common Mistakes

Using pdb.set_trace() in production code. Remove or guard pdb calls with an environment check:

import os
if os.environ.get("DEBUG"):
    import pdb; pdb.set_trace()

Confusing step and next. step descends into functions; next runs them to completion without descending. Use next to skip over code you are confident about and step to dive into code you need to inspect.

Forgetting the program is paused. A long-running loop with a breakpoint inside it will appear frozen. Press c to continue to the next breakpoint or q to quit.

See Also