Become a pdb power-user
Ashwini Chaudhary
Software Engineer, Instamojo
@ashwch
MUPy 2016
Links
https://www.github.com/ashwch/pdb-mupy
http://slides.com/ashwch/pdb-mupy
What's pdb?
Interactive source code debugger for Python programs
Starting pdb
Start a script under debugger control
$ python -m pdb script.py
> /script.py(1)<module>()
-> """I am the first script in this demo"""
(Pdb)
Start a command under debugger control
>>> import pdb
>>> import script
>>> pdb.run('script.divide(10, 5)')
> <string>(1)<module>()
(Pdb)
>>> pdb.runeval('script.divide(10, 5)')
> <string>(1)<module>()
(Pdb)
>>> pdb.runcall(script.divide, 10, 5)
> /script.py(7)divide()
-> return numerator / denominator
Setting a Breakpoint
import pdb; pdb.set_trace()
Post-Mortem debugging
>>> import pdb
>>> import script
>>> script.divide(10, 0)
Traceback (most recent call last):
ZeroDivisionError: integer division or
modulo by zero
>>> pdb.pm()
> /script.py(7)divide()
-> return numerator / denominator
(Pdb)
Basic Commands
help
(`!` is the only exception, use `pdb exec` for it).
h(elp) [command]
Printing
p - Normal print
pp - Pretty print
p
pp
Print function arguments
a(rgs)
(Pdb) args
numerator = 10
denominator = 0
Quit the debugger
q(uit)
Run Python statements
! statement
Re-run current program
run
List lines in source code
l(ist) [first[, last]]
Setting Aliases
alias [name [command]]
unalias name
(Pdb) alias squares [i**2 for i in xrange(%1)]
(Pdb) squares 5
[0, 1, 4, 9, 16]
(Pdb) alias squares_7 squares 7
(Pdb) squares_7
[0, 1, 4, 9, 16, 25, 36]
Stepping through code
n(ext)
Go the next line in the current function
s(tep)
Stop at the very next line
unt(il)
Stop only when line greater than current line number is reached
r(eturn)
Reach the end of a function
c(ont(inue))
I am Done with debugging
Finish my program
j(ump) lineno
Jump to a line number
# -*- coding: utf-8 -*-
import pdb
def knights():
print "We are the Knights who say ni!"
# Done with this function. Want to reach the end this function? Use r(eturn).
print "Get us a shrubbery."
def credits():
print "A Møøse once bit my sister... No realli!"
print "We apologise for the fault in the print statements."
print "Those responsible have been sacked."
return "Møøse bites Kan be pretti nasti."
pdb.set_trace()
knights() # Just want to run this function and move on to next line? Use n(ext).
credits() # Want to step inside this function? Use s(tep).
for i in range(1, 5):
# To exit loop unt(il) can be used.
print "Shrubbery #{}".format(i)
print "We have found the Holy Grail."
Jumping between stack calls
Where Am I?
w(here)
$ python recursive.py
> /recursive.py(10)func()
-> return 0
(Pdb) where
/recursive.py(14)<module>()
-> print func(4)
/recursive.py(7)func()
-> return func(n - 1)
/recursive.py(7)func()
-> return func(n - 1)
/mupy/recursive.py(7)func()
-> return func(n - 1)
/recursive.py(7)func()
-> return func(n - 1)
> /recursive.py(10)func()
-> return 0
# -*- coding: utf-8 -*-
import pdb
def func(n):
if n > 0:
return func(n - 1)
else:
pdb.set_trace()
return 0
if __name__ == '__main__':
print func(4)
How do I go Up and Down in stack?
u(p)
d(own)
$ python recursive.py
> /recursive.py(10)func()
-> return 0
(Pdb) args
n = 0
(Pdb) u
> /recursive.py(7)func()
-> return func(n - 1)
(Pdb) args
n = 1
(Pdb) u
> /recursive.py(7)func()
-> return func(n - 1)
(Pdb) args
n = 2
(Pdb) d
> /recursive.py(7)func()
-> return func(n - 1)
(Pdb) args
n = 1
# -*- coding: utf-8 -*-
import pdb
def func(n):
if n > 0:
return func(n - 1)
else:
pdb.set_trace()
return 0
if __name__ == '__main__':
print func(4)
Breakpoints
Setting a Breakpoint
b(reak) [[filename:]lineno | function[, condition]]
Temporary Breakpoint
Useful if you want to debug something only once in a loop.
tbreak [[filename:]lineno | function[, condition]]
Clearing Breakpoints
cl(ear) [filename:lineno | bpnumber [bpnumber ...]]
Disable/Enable Breakpoints
Disable breakpoint(s) but don't remove them permanently.
enable [bpnumber [bpnumber ...]]
disable [bpnumber [bpnumber ...]]
Ignoring Breakpoint
Allows you to ignore a breakpoint count times. Breakpoint is re-activated when count becomes 0.
ignore bpnumber [count]
Adding/Updating condition
Condition is an expression which must evaluate to true before the breakpoint is honored.
condition bpnumber [condition]
Commands
Allows you to set list of commands at a breakpoint.
commands [bpnumber]
# -*- coding: utf-8 -*-
import sys
def divide(numerator, denominator):
# Break on this function: `break divide`
# Break when denominator == 0: `break divide, denominator == 0`
print "Calculating {}/{}".format(numerator, denominator)
return numerator / denominator # `break 9`
if __name__ == '__main__':
numerator = float(sys.argv[1])
denominator = float(sys.argv[2])
print divide(numerator, denominator)
Tips and Tricks
- .pdbrc file: If present the commands present in this file are ran at the start of debugger session.
- Plain enter repeats the last command(`list` command is an exception)
- To enter multiple commands on a single line use `;;` as separator.
- To run interactive shell inside debugger (Ctrl-D for exit):
`!import code; code.interact(local=vars())`
In Python 3.2+ this can be using interact command.
Other debugging packages
ipdb - Brings IPython functionality in pdb
PuDB is a full-screen, console-based visual debugger for Python.
pydbgr - Has features like repeat a command n-times, stop only at certain events(returns, function calls etc)
Questions?
Become a pdb power-user | MUPy
By Ashwini Chaudhary
Become a pdb power-user | MUPy
- 2,735