personal web log written by izabeera and dryobates

python pdb debugging

Navigating in Pdb

by dryobates

I often see programmers, even experienced, that tediously press "n" and "s" few hundreds of times, one after another, only to skip some for loop or get into state where loop is executed n-th time in pdb. Here is a little tip how to do it smarter.

Conditions

What I often see is debugging some loop with code like below:

for i in range(100):
     import pdb; pdb.set_trace()
     print i
     ...

I wrote earlier how to cope with above problem and get debugger started only once. But often we want to stop execution when some condition is met. It would be a lot of typing if you would like to stop execution when "i == 98". Better solution is to put a breakpoint with condition:

import pdb; pdb.set_trace()
for i in range(100):
     print i
     ...
-> for i in range(100):
(Pdb) l
  1         import pdb; pdb.set_trace()
  2  ->     for i in range(100):
  3             print i
  ...
(Pdb) b 3, i == 98
Breakpoint 1 at some_file.py:3
(Pdb) c
0
1
...
96
97
> some_file.py(3)<module>()
-> print i
(Pdb) p i
98
(Pdb)

With above code execution will be stopped only when "i == 98".

Sometimes execution path is quite complex and putting set_trace just before loop isn't good choice. If you know filename and line number you can forget about set_trace and editing any file. Just run program with pdb and place breakpoint in file and line you want it:

python -m pdb some_file.py
(Pdb) b some_file.py:2, i == 98
Breakpoint 1 at some_file.py:2
(Pdb) c

Aliases

Sometimes condition isn't easy to express with simple math. There are times when you have to print some more complex variable and decide yourself if you should skip another loop or not. In such cases you often put simple breakpoint inside a loop and type:

(Pdb) p i
0
(Pdb) c
> some_file.py(2)<module>()
-> print i
(Pdb) p i
1
(Pdb) c
> some_file.py(2)<module>()
-> print i
(Pdb) p i
2
(Pdb) c
> some_file.py(2)<module>()
-> print i
...

And so one. Print, continue, print, continue... If you end up with such repetitive task it's time for aliases:

(Pdb) alias cp c ;; p i
(Pdb) cp
> some_file.py(2)<module>()
-> print i
0
(Pdb) cp
> some_file.py(2)<module>()
-> print i
1
(Pdb) cp
> some_file.py(2)<module>()
-> print i
2
...

Alias definition has simple, yet powerful syntax. You can pass parameters to aliases or define them ahead in ".pdbrc" file. All of that you can find in documentation [1] What you won't find in documentation is ";;" trick. Placing double semicolon while defining alias allows to stream multiple commands as seen above.

More elastic alias that could be placed in ".pdbrc" could be:

(Pdb) alias cp c ;; p %1
(Pdb) cp i
> some_file.py(2)<module>()
-> print i
0
...
[1]pdb's Documentation https://docs.python.org/2/library/pdb.html
dryobates
dryobates
Jakub Stolarski. Software engineer. I work professionally as programmer since 2005. Speeding up software development with Test Driven Development, task automation and optimization for performance are things that focus my mind from my early career up to now. If you ask me for my religion: Python, Vim and FreeBSD are my trinity ;) Email: jakub@stolarscy.com

Archive

Tag cloud