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.
Typingc
will let the program continue. Typingn
will step to the next line.
See Debugging in Python for details. - Suppose you have a program called
prog.py
which is crashing (causing a segmentation fault, say). Begin the program withsys.settrace()
(having imported thesys
package) 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