Elementary debuggingI've noticed that many students who submit assignments in Python for a course I teach don't know how to use a debugger. Here are some simple notes on debugging Python scripts to get people started. Lets say you have the following trivial code:
# -- junk.py ---
print "hello"
foo
a = 1
print a+1
Importing this from IPython produces this::
In [1]: import junk
hello
---------------------------------------------------------------------------
Traceback (most recent call last)
/tmp/ in ()
/tmp/junk.py in ()
1 print "hello"
----> 2 foo
3 a = 1
4 print a+1
5
exceptions.NameError: name 'foo' is not defined
If you have a non-trivial program you can debug this right away using IPython's %debug magic.
In [2]: %debug
> /tmp/junk.py(2)()
1 print "hello"
----> 2 foo
3 a = 1
ipdb>
This drops you into ipdb which is an enhanced, pdb. At this point you can print variables and step through your code, go up the stack of execution etc. For more details on ipdb read the
pdb documentation.
If you use the %pdb magic then IPython automatically drops you into the debugger whenever it sees an error. This is often very convenient.
Debugging a VTK-Python scriptThis is obviously a little more complicated (because VTK is implemented in C++ and you want to step through C++ code to figure out what is wrong) and there are a few ways of doing this. In the following I assume that you are doing this on a *nix/Linux/Mac machine. Suppose you run a Python script that segfaults and need to figure out where it crashed you can do the following (assuming you have gdb installed of course):
$ gdb python
(gdb) run your_script.py
[gdb messages]
Segmentation fault (or whatever)
(gdb) backtrace
The backtrace should typically give you more information about the crash.
Several weeks ago I needed to debug a VTK related problem where a window was not being resized if the off screen rendering mode was set. Debugging this can again be achieved by running the script using Python started from gdb and then setting a breakpoint in gdb. However, I thought I'd illustrate a very handy gdb feature of debugging running applications. In my particular case, I had a simple Python script that was demonstrating a VTK bug. At the appropriate location wher, I added a simple raw_input('DBG:') to give me a point where execution would be paused. I then ran the script like so:
$ python offscreen.py
On another shell I did the following:
$ ps uax | grep python
Using the PID of the process (30708) I did the following:
$ gdb
(gdb) attach 30708
[tons of output]
Loaded symbols for /usr/lib/libwx_gtk2u_gl-2.8.so.0
Reading symbols from /usr/lib/libGLU.so.1...done.
Loaded symbols for /usr/lib/libGLU.so.1
0xffffe410 in __kernel_vsyscall ()
(gdb)
On the gdb prompt I specify a break point where I want to stop execution::
(gdb) br vtkXOpenGLRenderWindow.cxx:1185
Breakpoint 1 at 0xb52846a0: file /skratch/prabhu/vtk/cvs/VTK/Rendering/vtkXOpenGLRenderWindow.cxx, line 1185.
(gdb) c
Continuing.
[Switching to Thread -1210595664 (LWP 30708)]
Breakpoint 1, vtkXOpenGLRenderWindow::SetSize (this=0x99bfb78, width=800,
height=800)
at /skratch/prabhu/vtk/cvs/VTK/Rendering/vtkXOpenGLRenderWindow.cxx:1185
1185 if ((this->Size[0] != width)||(this->Size[1] != height))
Current language: auto; currently c++
(gdb)
At this point I can step through the code and try and figure out what is going on. This is extremely convenient and handy.