Python Debugging
Several utilities are available to help debug your python code. Here are 3,
from easiest to hardest, that you can use on CUED’s linux system.
- VSCode in the anaconda distribution has a debug menu, and some info under the “Help” menu.
- If you have wxpython installed, you can use a debugging facility designed with wxpython in mind even if you’re not using wxpython. It produces tidy output that you can easily switch on and off. Here’s an example –
from wx.tools.dbg import Logger dbg = Logger('mymodule') dbg('something to print') d = {1:'a', 2:'dictionary', 3:'of', 4:'words'} dbg(enable=1) def foo(d): dbg('foo', indent=1) bar(d) dbg('end of foo', indent=0) def bar(d): dbg('bar', indent=1) dbg('contents of d:', indent=1) l = list(d.items()) l.sort() for key, value in l: dbg('%d =' % key, value) dbg(indent=0) dbg('end of bar', indent=0) foo(d) - If you’re running Python 3.7 or newer, you can use
breakpoint()
wherever you’d like your program to stop so that you can check values. With older Python versions, you’ll need to add
import pdb pdb.set_trace()
to your code where you’d like the program to stop. At the prompt you can type commands interactively to check on types and values.
Typingcwill let the program continue. Typingnwill step to the next line.
See Debugging in Python for details. - Suppose you have a program called
prog.pywhich is crashing (causing a segmentation fault, say). Begin the program withsys.settrace()(having imported thesyspackage) and do the following
gdb python run prog.py
After a lot of text you’ll get something like
Program received signal SIGSEGV, Segmentation fault. 0x00007fffef34cbad in wxWindow::AddChildGTK(wxWindow*) () from /usr/local/apps/anaconda3-5.0.1/lib/python3.6/site-packages/wx/libwx_gtk3u_core-3.0.so.0
If you type
backtrace
you’ll see more details, though they might not help you much.
logging
The print statements used for debugging can produce a lot of output that you don’t normally need. The logging package lets you disable output selectively by changing a “level” variable (an integer, so you have lots of flexibility, though there are present values like “INFO”). If you run the example below, only the “logger.info” lines will appear, but if you change the “level” variable to “DEBUG” you’ll see all the output.
import logging
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger.debug('Start of program')
def factorial(n):
logger.debug('Start of factorial(%s)' % (n))
logger.info('Some info')
total = 1
for i in range(1,n + 1):
total *= i
logger.debug('i is ' + str(i) + ', total is ' + str(total))
logger.debug('End of factorial(%s)' % (n))
return total
print(factorial(5))
logger.debug('End of program')
More info is on Logging in Python: A Developer’s Guide
Computing help and support