PythonBernsteinPydbIntro
From Wiki
The is the support page for Rocky Bernstein's Introduction to the pydb Debugger.
Transcript
Hi. My name is Rocky Bernstein and I'd like to give a brief demo of just a few of the extensions to the stock Python debugger that I've been working on.
I started around January of 2006, and I call this debugger pydb. The home page for this debugger is http://bashdb.sf.net/pydb . I adopted the name from another forked Python debugger that has since been "retired." Of course, I got the blessing from the author to do this. The additional features from that project have been merged in.
Today I'll use Microsoft Windows because that was the only way I could figure out how do the demo with sound. But I generally work on GNU/Linux. So what I show you is equally valid on any Unix box or Mac OSX box. And although I'm using GNU Emacs as sort of a front-end, the same could be done on a command line or using the front-end GUI, ddd. The software for this pydb-enabled debugger can be found again on the site in the download area.
Okay let's begin.
First let's load up the pydb Emacs interface which comes with the package.
>>> M-x load-library pydb >>> M-x pydb
In contrast to the stock debugger, pydb has options. For example, to debug with threading support, you would use the option --threading. We'll see some options later in the demo.
>>> pydb /tmp/gcd.py 5
Notice that the above is exactly the same as you would issue if you were in a shell.
Like pdb, the debugger has a step command which goes to the next runnable statement. In fact this is one of the few commands you'll see in this demo that is the same.
(Pydb) step
There are a couple of subtle things that have happened here. In the stock python debugger we would have been positioned at the "def" statement, because in fact that's the next executable statement that the interpreter encounters. The "def" statement here is defining the function and adding that name to the "globals" dictionary.
To see that this is so, use pydb's disassemble command:
(Pydb) disas<TAB>
semble
[Scroll back and you'll see line 3 code.]
Notice that we also have command completion available. I typed D-I-S-A-S and then a tab character. Since there is only one command that starts "disas", "disassemble" was completed.
In contrast to the stock debugger, pdb, in this debugger we skip over such def statements, since they generally aren't of interest for someone running a program. [If you do not want to skip over such method-creation statements, issue the debugger command: "set deftrace on".]
The other subtle thing going on is that we issued a step command but really didn't enter the sys module. That's because sys is a C module. You'll find that the first time, and only the first time, that you "import" a module that has runnable statements you will enter that module. If that's not what you want use the next command.
Okay let's continue with the program and see how far we get. 'c' is an a abbreviation for continue (same as in pdb).
(Pydb) c
[Bug because only one parameter given]
In a test the display is a little off here. If that were the case the frame command can be used to center the display at the proper stopping point.
We gave the wrong number of arguments. Let's see what they are:
(Pydb) show args
The first extension to pdb I added was a command that allows you to restart the program. Following gdb, it's called "run". So let's use that now and give the correct number of parameters:
(Pydb) run 3 5
Now I'm now going to show off another feature of pydb. We can actually watch the execution of the program as it is going along. This is done with the set linetrace command.
(Pydb) set line<TAB>
trace on
"set linetrace" shows every line as it gets executed. However things may flash too rapidly, so I'll set a delay after showing each line:
(Pydb) set line<TAB>
trace delay 0.25
Now let's continue and see what happens.
Okay what is the type of a:
(Pydb) wha<TAB>
tis a
[it's a string]
Let's correct this problem. By the way, bugs are generally not made singly and that's the case here as well.
Let's run again. The capital R is an abbreviation for "run". The mnemonic is taken from the Perl debugger.
(Pydb) R
We saw "continue" before. But pydb allows you to give a position name to continue up to. Let's try that.
(Pydb) c gcd
Let's see if we've fixed things.
(Pydb) wha<TAB>
tis a
Okay. Now I'll show another command not in the stock debugger although it was something that was in the older pydb: "display expressions". By the way, now may be a good time to mention that many of the extensions follow the gdb command interface. Display expressions are in gdb, as is command completion. The set commands we have are a little different but follow the general set command syntax.
(Pydb) display a
(Pydb) disp<TAB>
lay b
Now every step inside of the function gcd() will show the values of a and b
Okay; Let's continue.
(Pydb) c
Good.
Before, I mentioned that pydb has command options. And linetrace is one of the options. It allows you to do non-interactive line tracing of a Python program.
>>>> M-x shell $ pydb --trace /tmp/gcd.py 3 6
Using 6 instead of 5 gives shorter output. I should also note that you can put statements in your program to turn on and off line trace display. See the pydb documentation [1] from the homepage for that.
Finally, let's do the same thing and capture the output to a file:
$ pydb --output /tmp/gcd.out --trace /tmp/gcd.py 3 6 $ tail /tmp/gcd.out
Note is the output is same as output above.
This completes this small demo. There are many other features pydb has such as gdb-style signal handling, or examining complex objects with the examine command [2], and thread debugging. You can set up your program so that when you send it a signal, either a call stack trace is shown or you go into the debugger. For these things I invite you to look at the documentation: http://bashdb.sf.net/pydb/pydb/lib
Thanks.
gcd.py
#!/usr/bin/python
import sys
def gcd(a,b):
""" GCD. We assume positive numbers"""
if a > b:
(a, b) = (b, a)
if a <= 0:
return None
if a == 1 or b-a == 0:
return a
return gcd(b-a, a)
if __name__=='__main__':
(a, b) = sys.argv[1:3]
print "The GCD of %s and %s is %d" % (a, b, gcd(a, b))

