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