1.3.1 Calling the Debugger from Inside your Program (pydb.debugger)

When you issue pydb myscript.py you are running pydb first which then invokes your script myscript.py via Python's exec command. The debugger, pydb, tries hard to make itself transparent and thus strips its own program options, resets sys.argv and sets __file__ to the values you would get by calling the debugged program directly.

There may be however some subtle differences. For example the Python interpreter used would be the one specified by pydb rather than possibly that specified inside myscript.py. Also pydb does not search your command path, as would be done if issued from a shell.

Of course you can arrange to get the same interpreter by putting python (with the right path) first before pydb; and you can give an explicit file path in the script name to debug.

But there are times when even this won't work right.

There is another approach which obviates this complexity and the attendant drawbacks. However in this approach though you need to modify your program to add calls to the debugger at special places. For this, the pydb function debugger() can be used. See 1.3.7. I've even this method to debug the debugger itself and to debug regression tests.

When pydb.debugger() is called, the program stops before the next statement. To continue running the program, issue a debugger next, step or a continue command.

The exit the program use the quit or a terminal EOF.

To make this more clear, let's go through an example. Save this in a file called hardtodebug.py:

import pydb
# some code here
def test():
    # Force a call to the debugger in running code here
    pydb.debugger()
    # ...
# ...
test()
x=5

Now here's a sample run of the program:

python hardtodebug.py a b c
--Return--
--Return--
(/tmp/hardtodebug.py:9):
(Pydb) list
  4         # Force a call to the debugger in running code here
  5         pydb.debugger()
  6         # ...
  7     # ...
  8     test()
  9  -> x=5
(/tmp/hardtodebug.py:9): 
(Pydb) restart
Re exec'ing
	['pydb', 'hardtodebug.py', 'a', 'b', 'c']
(/tmp/hardtodebug.py:1): 
(Pydb)

The first --Return-- line printed is a result of the debugger() exiting. But note that we stopped after the return from test(), which explains the second --Return-- line. Because the next executable statement is after the implicit return. If you want to stop inside test() put a statement after the debugger(), such as a return statement. Furthermore, if the program had ended at line 8, then no stopping would have occurred because the end of the program is reached first.1.3

Also note that we can issue a restart which involves some hackery. But at least in this case it gets things right.

There is one final advantage of using debugger(). When one is stepping code or has put a breakpoint in code, the interpreter has to be involved and calls debugger-checking code written in Python for every statement that he debugged program runs. And this has a noticeable effect. With debugger() there is absolutely no overhead (provided there are no other breakpoints set in the program).



Footnotes

... first.1.3
Perhaps this is a deficiency of the debugger. I'm not sure what the right way to address though. One could have another routine to stop at a return which would then skip intervening statements. Another possibility is to add a routine to have debugger stop inside the call, e.g. debugger above. This is not hard to code and I've done so, but I'm not sure that doesn't just confuse things more.



Subsections
See About this document... for information on suggesting changes.