Debugging your Cython program¶
Cython comes with an extension for the GNU Debugger that helps users debugCython code. To use this functionality, you will need to install gdb 7.2 orhigher, built with Python support (linked to Python 2.6 or higher).The debugger supports debuggees with versions 2.6 and higher. For Python 3,code should be built with Python 3 and the debugger should be run withPython 2 (or at least it should be able to find the Python 2 Cythoninstallation). Note that in recent versions of Ubuntu, for instance,gdb
installed withapt-get
is configured with Python 3. On such systems, theproper configuration ofgdb
can be obtained by downloading thegdb
source, and then running:
./configure--with-python=python2makesudomakeinstall
Installing the Cython debugger can be quite tricky.This installation script and example code might be useful.
The debugger will need debug information that the Cython compiler can export.This can be achieved from within the setup script by passinggdb_debug=True
tocythonize()
:
fromsetuptoolsimportExtension,setupextensions=[Extension('source',['source.pyx'])]setup(...,ext_modules=cythonize(extensions,gdb_debug=True))
For development it’s often helpful to pass the--inplace
flag tothesetup.py
script, which makes setuptools build your project“in place”, i.e., not in a separatebuild directory.
When invoking Cython from the command line directly you can have it writedebug information using the--gdb
flag:
cython--gdbmyfile.pyx
Running the Debugger¶
To run the Cython debugger and have it import the debug information exportedby Cython, runcygdb
in the build directory:
$pythonsetup.pybuild_ext--inplace$cygdbGNUgdb(GDB)7.2...(gdb)
When using the Cython debugger, it’s preferable that you build and run your codewith an interpreter that is compiled with debugging symbols (i.e. configuredwith--with-pydebug
or compiled with the-g
CFLAG). If your Python isinstalled and managed by your package manager you probably need to install debugsupport separately. If using NumPy then you also need to install numpy debugging, or you’llsee animport error for multiarray.E.G. for ubuntu:
$sudoapt-getinstallpython-dbgpython-numpy-dbg$python-dbgsetup.pybuild_ext--inplace
Then you need to run your script withpython-dbg
also. Ensure that whenbuilding your package with debug symbols that cython extensions are re-compiledif they had been previously compiled. If your package is version controlled, youmight want to performgitclean-fxd
orhgpurge--all
before building.
You can also pass additional arguments to gdb:
$cygdb/path/to/build/directory/GDBARGS
i.e.:
$cygdb.----argspython-dbgmainscript.py
To tell cygdb not to import any debug information, supply--
as the firstargument:
$cygdb--
Using the Debugger¶
The Cython debugger comes with a set of commands that support breakpoints,stack inspection, source code listing, stepping, stepping over, etc. Mostof these commands are analogous to their respective gdb command.
- cybreakbreakpoints...
Break in a Python, Cython or C function. First it will look for a Cythonfunction with that name, if cygdb doesn’t know about a function (or method)with that name, it will set a (pending) C breakpoint. The
-p
option canbe used to specify a Python breakpoint.Breakpoints can be set for either the function or method name, or they canbe fully “qualified”, which means that the entire “path” to a function isgiven:
(gdb)cybreakcython_function_or_method(gdb)cybreakpackagename.cython_module.cython_function(gdb)cybreakpackagename.cython_module.ClassName.cython_method(gdb)cybreakc_function
You can also break on Cython line numbers:
(gdb)cybreak:14(gdb)cybreakcython_module:14(gdb)cybreakpackagename.cython_module:14
Python breakpoints currently support names of the module (not the entirepackage path) and the function or method:
(gdb)cybreak-ppython_module.python_function_or_method(gdb)cybreak-ppython_function_or_method
Note
Python breakpoints only work in Python builds where the Python frameinformation can be read from the debugger. To ensure this, use aPython debug build or a non-stripped build compiled with debugsupport.
- cystep
Step through Python, Cython or C code. Python, Cython and C functionscalled directly from Cython code are considered relevant and will bestepped into.
- cynext
Step over Python, Cython or C code.
- cyrun
Run the program. The default interpreter is the interpreter that was usedto build your extensions with, or the interpreter
cygdb
is run within case the “don’t import debug information” option was in effect.The interpreter can be overridden using gdb’sfile
command.
- cycont
Continue the program.
- cyup
- cydown
Go up and down the stack to what is considered a relevant frame.
- cyfinish
Execute until an upward relevant frame is met or something haltsexecution.
- cybt
- cybacktrace
Print a traceback of all frames considered relevant. The
-a
optionmakes it print the full traceback (all C frames).
- cyselect
Select a stack frame by number as listed by
cybacktrace
. Thiscommand is introduced becausecybacktrace
prints a reversed stacktrace, so frame numbers differ from gdb’sbt
.
- cyprintvarname
Print a local or global Cython, Python or C variable (depending on thecontext). Variables may also be dereferenced:
(gdb)cyprintxx=1(gdb)cyprint*x*x=(PyObject){_ob_next=0x93efd8,_ob_prev=0x93ef88,ob_refcnt=65,ob_type=0x83a3e0}
- cysetcython_variable=value
Set a Cython variable on the Cython stack to value.
- cylist
List the source code surrounding the current line.
- cylocals
- cyglobals
Print all the local and global variables and their values.
- cyimportFILE...
Import debug information from files given as arguments. The easiest way toimport debug information is to use the cygdb command line tool.
- cyexeccode
Execute code in the current Python or Cython frame. This works likePython’s interactive interpreter.
For Python frames it uses the globals and locals from the Python frame,for Cython frames it uses the dict of globals used on the Cython moduleand a new dict filled with the local Cython variables.
Note
cyexec
modifies state and executes code in the debuggee and istherefore potentially dangerous.
Example:
(gdb)cyexecx+12(gdb)cyexecimportsys;printsys.version_info(2,6,5,'final',0)(gdb)cyexec>globalfoo>>foo='something'>end
Convenience functions¶
The following functions are gdb functions, which means they can be used in agdb expression.
- cy_cname(varname)¶
Returns the C variable name of a Cython variable. For globalvariables this may not be actually valid.
- cy_cvalue(varname)¶
Returns the value of a Cython variable.
- cy_eval(expression)¶
Evaluates Python code in the nearest Python or Cython frame and returnsthe result of the expression as a gdb value. This gives a new referenceif successful, NULL on error.
- cy_lineno()¶
Returns the current line number in the selected Cython frame.
Example:
(gdb)print$cy_cname("x")$1="__pyx_v_x"(gdb)watch$cy_cvalue("x")Hardwarewatchpoint13:$cy_cvalue("x")(gdb)cysetmy_cython_variable=$cy_eval("{'spam': 'ham'}")(gdb)print$cy_lineno()$2=12
Configuring the Debugger¶
A few aspects of the debugger are configurable with gdb parameters. Forinstance, colors can be disabled, the terminal background colorand breakpoint autocompletion can be configured.
- cy_complete_unqualified¶
Tells the Cython debugger whether
cybreak
should also completeplain function names, i.e. not prefixed by their module name.E.g. if you have a function namedspam
,in moduleM
, it tells whether to only completeM.spam
or also justspam
.The default is true.
- cy_colorize_code¶
Tells the debugger whether to colorize source code. The default is true.
- cy_terminal_background_color¶
Tells the debugger about the terminal background color, which affectssource code coloring. The default is “dark”, another valid option is“light”.
This is how these parameters can be used:
(gdb)setcy_complete_unqualifiedoff(gdb)setcy_terminal_background_colorlight(gdb)showcy_colorize_code