Debugging code with IPython
Debugging is an integral part of software development and interactive computing. A widespread debugging technique consists of placing the print()
functions in various places in the code. Who hasn't done this? It is probably the simplest solution, but it is certainly not the most efficient (it is the poor man's debugger).
IPython is perfectly adapted for debugging, and the integrated debugger is quite easy to use (actually, IPython merely offers a nice interface to the native Python debugger pdb). In particular, tab completion works in the IPython debugger. This recipe describes how to debug code with IPython.
How to do it...
There are two not-mutually exclusive ways of debugging code in Python. In the post-mortem mode, the debugger steps into the code as soon as an exception is raised, so that we can investigate what caused it. In the step-by-step mode, we can stop the interpreter at a breakpoint and resume its execution step by step. This process allows us to check carefully the state of our variables as our code is executed.
Both methods can actually be used simultaneously; we can do step-by-step debugging in the post-mortem mode.
When an exception is raised within IPython, execute the %debug
magic command to launch the debugger and step into the code. Also, the %pdb on
command tells IPython to launch the debugger automatically as soon as an exception is raised.
Once you are in the debugger, you have access to several special commands, the most important ones being listed here:
p varname
prints the value of a variablew
shows your current location within the stacku
goes up in the stackd
goes down in the stackl
shows the lines of code around your current locationa
shows the arguments of the current function
The call stack contains the list of all active functions at a given location in the code's execution. You can easily navigate up and down the stack to inspect the values of the function arguments. Although quite simple to use, this mode should let you resolve most of your bugs. For more complex problems, you may need to do step-by-step debugging.
You have several options to start the step-by-step debugging mode. First, in order to put a breakpoint somewhere in your code, insert the following command:
import pdb pdb.set_trace()
Second, you can run a script from IPython with the following command:
%run -d -b extscript.py:20 script
This command runs the script.py
file under the control of the debugger with a breakpoint on line 20 in extscript.py
(which is imported by script.py
). Finally, you can do step-by-step debugging as soon as you are in the debugger.
Step-by-step debugging consists of precisely controlling the course of the interpreter. Starting from the beginning of a script or from a breakpoint, you can resume the execution of the interpreter with the following commands:
s
executes the current line and stops as soon as possible afterwards (step-by-step debugging—that is, the most fine-grained execution pattern)n
continues the execution until the next line in the current function is reachedr
continues the execution until the current function returnsc
continues the execution until the next breakpoint is reachedj 30
brings you to line 30 in the current file
You can add breakpoints dynamically from within the debugger using the b
command or with tbreak
(temporary breakpoint). You can also clear all or some of the breakpoints, enable or disable them, and so on. You can find the full details of the debugger at https://docs.python.org/3/library/pdb.html.
There's more...
To debug your code with IPython, you typically need to execute it first with IPython—for example, with %run
. However, you may not always have an easy way of doing this. For instance, your program may run with a custom command-line Python script, it may be launched by a complex bash script, or it may be integrated within a GUI. In these cases, you can embed an IPython interpreter at any point in your code (launched by Python), instead of running your whole program with IPython (which may be overkill if you just need to debug a small portion of your code).
To embed IPython within your program, simply insert the following commands somewhere in your code:
from IPython import embed embed()
When your Python program reaches this code, it will pause and launch an interactive IPython terminal at this specific point. You will then be able to inspect all local variables, run any code you want, and possibly debug your code before resuming normal execution.
Most Python IDEs offer graphical debugging features (see the Efficient interactive computing workflows with IPython recipe). A GUI can sometimes be more convenient than a command-line debugger. A list of Python debuggers is available at https://wiki.python.org/moin/PythonDebuggingTools.