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, python prints the line, location and quick description of the error and exits. Is it possible to automatically start pdb when an error is encountered? I am not against having an extra import statement at the top of the file, nor a few extra lines of code.
15 Answers
python -m pdb -c continue myscript.py
# or
python -m pdb -c continue -m myscript
If you don't provide the -c continue flag then you'll need to enter 'c' (for Continue) when execution begins. Then it will run to the error point and give you control there. As mentioned by eqzx, this flag is a new addition in python 3.2 so entering 'c' is required for earlier Python versions (see https://docs.python.org/3/library/pdb.html).
18 Comments
gdb; and when you enter 'r' in pdb, program does indeed run, but does NOT stop (nor generate backtrace) on error; had me puzzled until I read this. Cheers!ipdb; and of course arguments can be added after the script!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)
9 Comments
code over pdb since the latter seems to expand on the former?sys.exc_info to extract the traceback and finally call pdb.post_mortem with that traceback. You don't need to pass traceback object to pdb.post_mortem. From docs: If no traceback is given, it uses the one of the exception that is currently being handled (an exception must be being handled if the default is to be used).Use the following module:
import sys
def info(type, value, tb):
if hasattr(sys, 'ps1') or not sys.stderr.isatty():
# we are in interactive mode or we don't have a tty-like
# device, so we call the default hook
sys.__excepthook__(type, value, tb)
else:
import traceback, pdb
# we are NOT in interactive mode, print the exception...
traceback.print_exception(type, value, tb)
print
# ...then start the debugger in post-mortem mode.
# pdb.pm() # deprecated
pdb.post_mortem(tb) # more "modern"
sys.excepthook = info
Name it debug (or whatever you like) and put it somewhere in your python path.
Now, at the start of your script, just add an import debug.
2 Comments
try-catch which is just ugly IMO.sys.excepthook. They often have their own even better approaches like werkzeug, but see also python - Flask and sys\.excepthook - Stack OverflowIpython has a command for toggling this behavior: %pdb. It does exactly what you described, maybe even a bit more (giving you more informative backtraces with syntax highlighting and code completion). It's definitely worth a try!
4 Comments
%debug allows one to open the debugger after encountering an error. I often prefer this over %pdb. (The trade-off is merely typing q every time you don't want to debug an error vs. typing %debug every time you do want to debug an error.)c.InteractiveShell.pdb = True in one's ipython_config.py turns on %pdb automatically for every session.This isn't the debugger, but probably just as useful(?)
I know I heard Guido mention this in a speech somewhere.
I just checked python -?, and if you use the -i command you can interact where your script stopped.
So given this script:
testlist = [1,2,3,4,5, 0]
prev_i = None
for i in testlist:
if not prev_i:
prev_i = i
else:
result = prev_i/i
You can get this output!
PS D:\> python -i debugtest.py
Traceback (most recent call last):
File "debugtest.py", line 10, in <module>
result = prev_i/i
ZeroDivisionError: integer division or modulo by zero
>>>
>>>
>>> prev_i
1
>>> i
0
>>>
To be honest I haven't used this, but I should be, seems very useful.
4 Comments
import pdb;pdb.pm() to do a post mortem?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.
1 Comment
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.
1 Comment
up and down commands to go back to the line of your code that generated the error.ipdb has a nice context manager to achieve this behavior which makes the intent semantically clearer:
from ipdb import launch_ipdb_on_exception
with launch_ipdb_on_exception():
...
Comments
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.
Comments
You can put this line in your code:
import pdb ; pdb.set_trace()
More info: Start the python debugger at any line
1 Comment
If you happen to be using pudb (python debugger with a nice interface), you can enter debugger when an exception occurs with:
python -m pudb -c code_that_crashes.py
pudb describes the -c option as:
-c, --continue Let the script run until an exception occurs or a breakpoint is hit
Comments
Since 3.7, you can use the keyword breakpoint directly in your code (without any import), just like this:
try:
... # The line that raises an error
except:
breakpoint()
1 Comment
breakpoint everywhere in the code. No matter from which part of code, the exception is raised, OP wants to enter into debugger mode.
IPython, it's much simpler.ipython --pdb myscript.pypython -m pdb -c cont myscript.py(Elaborated in one of the answers below).ipdb,python -m ipdb -c cont myscript.py