Debugging with IPython

Debugging is one of those things nobody really likes, but is very important to master. It can take hours, and because of Murphy's law, you most likely, don't have that time. Therefore, it is important to be systematic and know your tools well. After you are done finding the bug and implementing a fix, you should have a test in place. This way at least you will not have to go through the hell of debugging again. Unit testing is covered in the next chapter. We will debug the following buggy code, which tries to access an array element that is not present:

import numpy

a = numpy.arange(7)
print a[8]

The IPython debugger works as the normal Python pdb debugger; it adds features such as tab completion and syntax highlighting.

How to do it...

The following steps illustrate a typical debugging session:

  1. Run the buggy script in IPython.

    Start the IPython shell. Run the buggy script in IPython by issuing the following command:

    In [1]: %run buggy.py
    ---------------------------------------------------------------------------
    IndexError                                Traceback (most recent call last)
    .../site-packages/IPython/utils/py3compat.pyc in execfile(fname, *where)
        173             else:
        174                 filename = fname
    --> 175             __builtin__.execfile(filename, *where)
    
    .../buggy.py in <module>()
          2 
          3 a = numpy.arange(7)
    ----> 4 print a[8]
    
    IndexError: index out of bounds
    
  2. Start the debugger.

    Now that our program has crashed, we can start the debugger. This will set a breakpoint on the line where the error occurred:

    In [2]: %debug
    > .../buggy.py(4)<module>()
          2 
          3 a = numpy.arange(7)
    ----> 4 print a[8]
    
  3. List code.

    We can list code with the list command, or use the shorthand l:

    ipdb> list
          1 import numpy
          2 
          3 a = numpy.arange(7)
    ----> 4 print a[8]
    
  4. Evaluate the code at the current line.

    We can now evaluate arbitrary code at the current line, the line to which the debugger is currently pointing:

    ipdb> len(a)
    7
    
    ipdb> print a
    [0 1 2 3 4 5 6]
    
  5. View the call stack.

    The call stack is a stack containing information about active functions of a running program. We can view the call stack with the bt command:

    ipdb> bt
     .../py3compat.py(175)execfile()
        171             if isinstance(fname, unicode):
        172                 filename = fname.encode(sys.getfilesystemencoding())
        173             else:
        174                 filename = fname
    --> 175             __builtin__.execfile(filename, *where)
    > .../buggy.py(4)<module>()
          0 print a[8]
    

    Move up the call stack:

    ipdb> u
    > .../site-packages/IPython/utils/py3compat.py(175)execfile()
        173             else:
        174                 filename = fname
    --> 175             __builtin__.execfile(filename, *where)
    

    Move down the call stack:

    ipdb> d
    > .../buggy.py(4)<module>()
          2 
          3 a = numpy.arange(7)
    ----> 4 print a[8]
    

How to do it...

In this tutorial, we saw how to debug a NumPy program using IPython. We set a breakpoint and navigated the call stack. The following debugger commands were used:

Command

Description

list or l

Lists source code.

bt

Shows call stack.

u

Moves up a call stack.

d

Moves down a call stack.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset