Python
Python PDB Args: Debug a Script With python -m pdb
Run Python pdb with script arguments using python3 -m pdb script.py arg1 arg2. See exact command examples, common mistakes, and essential pdb commands.
Run python -m pdb With Script Arguments
If your script normally takes command-line arguments, put those arguments after the script name when you start pdb:
python3 -m pdb script.py arg1 arg2
For example, this runs calculate_total.py in pdb and still passes --env test --debug to the script:
python3 -m pdb calculate_total.py --env test --debug
The important rule is simple:
python3 -m pdb <your_script.py> <your_script_arguments>
Do not put the script arguments before the script name. Those arguments need to be passed to your script, not to pdb itself.
Once the debugger starts, use commands like:
| Command | Use it for |
|---|---|
args or a | Show arguments for the current function call. |
n | Run the next line without stepping into a function. |
s | Step into a function call. |
c | Continue until the next breakpoint or program exit. |
p variable_name | Print a variable. |
pp variable_name | Pretty print a variable. |
q | Quit pdb. |
Quick Example: Debug a Script That Takes Flags
Suppose your script is usually run like this:
python3 calculate_total.py --env test --debug
Start the same script under pdb like this:
python3 -m pdb calculate_total.py --env test --debug
When pdb opens, you can step through the script with n, inspect values with p, or continue with c. The --env test --debug flags are still available to your script through sys.argv or your argument parser.
Introduction To Python's pdb Debugger
pdb is Python's built-in debugger. It helps you pause a script, step through code line by line, inspect variable values, evaluate expressions, and understand why your program is behaving a certain way.
This guide starts with the most common search problem: running a Python script in pdb while still passing command-line arguments. Then it covers the everyday pdb commands you will use when debugging Python scripts, QA automation checks, or test utilities.
What Is pdb?
The Python debugger, pdb, provides an interactive debugging environment for Python programs. It allows you to execute programs step by step, inspect variable values, and understand program execution flow, which is crucial for diagnosing and solving complex bugs.
Getting Started With pdb
To use pdb, start by inserting a breakpoint in your code. A breakpoint tells Python to pause execution at that point and launch the debugger.
If you are using Python 3.7 or newer, add the breakpoint() function at the line where you want the script to pause.
print("Hello World!")
breakpoint()
print("Thank you!")
Before Python 3.7, import pdb and use the set_trace() function.
print("Hello World!")
import pdb; pdb.set_trace()
print("Thank you!")
Execution stops where you put the breakpoint. Then you can interact with the code to get information like variable values, test functions, and inspect program state.
Key pdb Commands
Before diving into the example scripts, review the essential pdb commands used to control execution and inspect programs.
| Command | What It Does |
|---|---|
breakpoint() | Inserts a breakpoint where the debugger pauses execution. |
print() or p | Prints the value of a variable or expression. |
pp | Pretty prints the value of a variable or expression in a more readable format. |
continue or c | Continues execution until the next breakpoint is encountered. |
list or l | Displays lines of code around the current line being executed. |
next or n | Executes the next line of code without stepping into functions. |
step or s | Steps into the function call at the current line. |
args or a | Displays the arguments of the current function call. |
quit or q | Quits the debugger and ends the program. |
You can get a complete list of debugger commands from the official Python documentation.
Step By Step Example
This example consists of two Python files: main.py and helpers.py. These scripts simulate a common scenario where data is gathered, processed, and displayed. The example shows how pdb can be used in a realistic debugging situation.
helpers.py
def gather_data():
return {
"name": "Jane Doe",
"age": 28,
"city": "New York",
"country": "USA",
"enrolled": True,
}
def process_data(data):
data["processed"] = True
return data
main.py
from helpers import gather_data, process_data
def main():
data = gather_data()
breakpoint() # Start debugging here
processed_data = process_data(data)
print("Original Data:", data)
print("Processed Data:", processed_data)
if __name__ == "__main__":
main()
When the main.py script is run, it pauses on the breakpoint. The prompt shows (Pdb).
admas@/.../python-debugger-pdb : python3 main.py
> /Users/admas/Demos/python-debugger-pdb/main.py(6)main()
-> processed_data = process_data(data)
(Pdb)
Using The p And pp Commands
The most common and useful debugging action is printing the value of a variable. In this example, the variable data is defined before the breakpoint, so we can print its value while the debugger is paused.
You can use print(), the p command for printing, or the pp command for pretty printing. My go-to is pp because it prints in a more readable format, especially when dealing with dictionaries, lists, or nested structures.
Here is what it looks like using print() and p.
admas@/.../python-debugger-pdb : python3 main.py
> /Users/admas/Demos/python-debugger-pdb/main.py(6)main()
-> processed_data = process_data(data)
(Pdb) print(data)
{'name': 'Jane Doe', 'age': 28, 'city': 'New York', 'country': 'USA', 'enrolled': True}
(Pdb) p data
{'name': 'Jane Doe', 'age': 28, 'city': 'New York', 'country': 'USA', 'enrolled': True}
(Pdb)
Here is what it looks like using pp.
admas@/.../python-debugger-pdb : python3 main.py
> /Users/admas/Demos/python-debugger-pdb/main.py(6)main()
-> processed_data = process_data(data)
(Pdb) pp data
{'age': 28,
'city': 'New York',
'country': 'USA',
'enrolled': True,
'name': 'Jane Doe'}
(Pdb)
The pp command improves readability, especially for nested or complex data structures. It organizes the data in a structured format, which helps you quickly understand the data and its relationships.
Continuing Execution With c
When you are done debugging and want the script to continue, type c and press Enter. The c command means continue.
If there is no other breakpoint, the script runs until the end. If there is another breakpoint, it runs until the next breakpoint is hit.
admas@/.../python-debugger-pdb : python3 main.py
> /Users/admas/Demos/python-debugger-pdb/main.py(6)main()
-> processed_data = process_data(data)
(Pdb) c
Original Data: {'name': 'Jane Doe', 'age': 28, 'city': 'New York', 'country': 'USA', 'enrolled': True, 'processed': True}
Processed Data: {'name': 'Jane Doe', 'age': 28, 'city': 'New York', 'country': 'USA', 'enrolled': True, 'processed': True}
admas@/.../python-debugger-pdb :
The c command lets you move from one debugging checkpoint to another, or complete the execution once you have finished your checks.
Using The l Command
The l command means list. It shows lines of code around the line currently being executed.
os/python-debugger-pdb/main.py
> /Users/admas/Demos/python-debugger-pdb/main.py(6)main()
-> processed_data = process_data(data)
(Pdb) l
1 from helpers import gather_data, process_data
2
3 def main():
4 data = gather_data()
5 breakpoint()
6 -> processed_data = process_data(data)
7 print("Original Data:", data)
8 print("Processed Data:", processed_data)
9
10
11 if __name__ == "__main__":
(Pdb)
The arrow, ->, tells you the next line that will be executed. In this case, line 6 will be executed next.
Using The n Command
The n command means next. It executes the next line of code without stepping into any functions. This is also called step over.
In this example, n executes process_data(data) without going into the function, then pauses on the next line.
os/python-debugger-pdb/main.py
> /Users/admas/Demos/python-debugger-pdb/main.py(6)main()
-> processed_data = process_data(data)
(Pdb) l
1 from helpers import gather_data, process_data
2
3 def main():
4 data = gather_data()
5 breakpoint()
6 -> processed_data = process_data(data)
7 print("Original Data:", data)
8 print("Processed Data:", processed_data)
9
10
11 if __name__ == "__main__":
(Pdb) n
> /Users/admas/Demos/python-debugger-pdb/main.py(7)main()
-> print("Original Data:", data)
(Pdb)
If you want to execute one line at a time, keep entering n.
> /Users/admas/Demos/python-debugger-pdb/main.py(6)main()
-> processed_data = process_data(data)
(Pdb) n
> /Users/admas/Demos/python-debugger-pdb/main.py(7)main()
-> print("Original Data:", data)
(Pdb) n
Original Data: {'name': 'Jane Doe', 'age': 28, 'city': 'New York', 'processed': True}
> /Users/admas/Demos/python-debugger-pdb/main.py(8)main()
-> print("Processed Data:", processed_data)
(Pdb) n
Processed Data: {'name': 'Jane Doe', 'age': 28, 'city': 'New York', 'processed': True}
--Return--
> /Users/admas/Demos/python-debugger-pdb/main.py(8)main()->None
-> print("Processed Data:", processed_data)
(Pdb)
Using The s Command
The s command means step. It steps into the function call at the current line. The difference between n and s is that n executes the next function without entering it, while s steps into the next function.
This is useful when you need to dive into a function implementation to trace a deeper issue or understand the flow inside the function.
admas@/.../python-debugger-pdb : python3 main.py
> /Users/admas/Demos/python-debugger-pdb/main.py(6)main()
-> processed_data = process_data(data)
(Pdb) s
--Call--
> /Users/admas/Demos/python-debugger-pdb/helpers.py(9)process_data()
-> def process_data(data):
(Pdb) s
> /Users/admas/Demos/python-debugger-pdb/helpers.py(14)process_data()
-> data['processed'] = True
(Pdb)
When you enter s, the debugger goes inside the process_data(data) function. When you enter n, it executes process_data(data) but does not step into it.
Conclusion
Mastering Python's pdb debugger is important for developers who want to improve their debugging skills. pdb lets you move through code precisely, set breakpoints, inspect application state, and understand program flow. By using commands like p, pp, c, l, n, and s, you can identify bugs faster and understand how your Python code actually executes.
How do I pass arguments when running python -m pdb?
Use python3 -m pdb script.py arg1 arg2. The arguments after script.py are passed to your script while PDB starts the script in debug mode.
