This is a question I have wondered about for quite some time, yet I have never found a suitable solution. If I run a script and I come across, let\'s say an IndexError, pyth
Put a breakpoint inside the constructor of topmost exception class in the hierarchy, and most of the times you will see where the error was raised.
Putting a breakpoint means whatever you want it to mean : you can use an IDE, or pdb.set_trace
, or whatever
If you are using ipython
, after launching type %pdb
In [1]: %pdb
Automatic pdb calling has been turned ON
If you are running a module:
python -m mymodule
And now you want to enter pdb
when an exception occurs, do this:
PYTHONPATH="." python -m pdb -c c mymodule/__main__.py
(or extend your PYTHONPATH
). The PYTHONPATH
is needed so that the module is found in the path, since you are running the pdb
module now.
IPython makes this simple on the command line:
python myscript.py arg1 arg2
can be rewritten to
ipython --pdb myscript.py -- arg1 arg2
Or, similarly, if calling a module:
python -m mymodule arg1 arg2
can be rewritten to
ipython --pdb -m mymodule -- arg1 arg2
Note the --
to stop IPython from reading the script's arguments as its own.
This also has the advantage of invoking the enhanced IPython debugger (ipdb) instead of pdb.
You can use traceback.print_exc to print the exceptions traceback. Then use sys.exc_info to extract the traceback and finally call pdb.post_mortem with that traceback
import pdb, traceback, sys
def bombs():
a = []
print a[0]
if __name__ == '__main__':
try:
bombs()
except:
extype, value, tb = sys.exc_info()
traceback.print_exc()
pdb.post_mortem(tb)
If you want to start an interactive command line with code.interact using the locals of the frame where the exception originated you can do
import traceback, sys, code
def bombs():
a = []
print a[0]
if __name__ == '__main__':
try:
bombs()
except:
type, value, tb = sys.exc_info()
traceback.print_exc()
last_frame = lambda tb=tb: last_frame(tb.tb_next) if tb.tb_next else tb
frame = last_frame().tb_frame
ns = dict(frame.f_globals)
ns.update(frame.f_locals)
code.interact(local=ns)
If you are using the IPython environment, you can just use the %debug and the shell will take you back to the offending line with the ipdb environment for inspections etc. Another option as pointed above is to use the iPython magic %pdb which effectively does the same.