36

If ones catches an exception outside of the function it is originally thrown, ones loses access to the local stack. As a result one cannot inspect the values of the variables that might have caused the exception.

Is there a way to automatically start break into the debugger (import pdb; pdb.set_trace()) whenever a exception is thrown to inspect the local stack?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Framester
  • 33,341
  • 51
  • 130
  • 192

7 Answers7

33

You don't want to break on every exception; idiomatic Python code uses exceptions heavily (EAFP) so you'd be continually breaking in unrelated code.

Instead, use pdb post-mortem: import pdb; pdb.pm(). This uses sys.last_traceback to inspect the stack including the locals at the throw point.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • 1
    Thanks, I works perfectly in the interpreter like in the example in the [documentation](http://docs.python.org/2/library/pdb.html#debugger), but how do I do it inside my script? – Framester Sep 23 '13 at 13:53
  • @Framester You put it in the script, where you want it to break. `pdb.set_trace()` like you have in the question should work as well, it's what I usually use (not sure what the difference is) – Izkata Sep 23 '13 at 15:01
  • 2
    A more interesting question statement would be "automatically catch uncaught exceptions that would blow up the program", supposing there is a precise way to define that. – Ciro Santilli OurBigBook.com Dec 15 '18 at 13:07
  • 2
    This does not answer the question. I'll decide what I want to do. – Brent Apr 04 '19 at 16:17
  • 1
    Python [documentation](https://docs.python.org/2.7/library/sys.html#sys.last_traceback) for `sys.last_traceback` states that "These three variables are not always defined;" In such case, using [`pdb.post_mortem`](https://docs.python.org/2.7/library/pdb.html?highlight=pdb#pdb.post_mortem) sometimes helps. – Peter Bašista Apr 08 '19 at 12:53
27

ipython supports this (http://ipython.org). from inside ipython, do

%pdb on

and from then on, it will automatically drop you inside the debugger whenever you get an exception.

note that you'll (probably) quickly tire of this in general use... every time you mistype something and get a syntax error, you'll have to exit the debugger. but it's sometimes useful.

Corley Brigman
  • 11,633
  • 5
  • 33
  • 40
14

For python 3 (today at 3.8), this can be done with

python3 -m pdb myscript.py

From the docs:

When invoked as a script, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post-mortem debugging (or after normal exit of the program), pdb will restart the program. Automatic restarting preserves pdb’s state (such as breakpoints) and in most cases is more useful than quitting the debugger upon program’s exit.

Note that at launch, python will directly enter pdb mode, and you need to type c then enter to start running the script

Shadi
  • 9,742
  • 4
  • 43
  • 65
  • It will start an equivalent of `pdb.post_mortem()`. Is there a way to start `pdb.set_trace()` instead? Or `ipdb.set_trace()`? – fariaseduv Dec 09 '21 at 02:52
10

I found what I was looking for in an answer to What is the simplest way of using Python pdb to inspect the cause of an unhandled exception?

Wrap it with that:

def debug_on(*exceptions):
    if not exceptions:
        exceptions = (AssertionError, )
    def decorator(f):
        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            try:
                return f(*args, **kwargs)
            except exceptions:
                pdb.post_mortem(sys.exc_info()[2])
        return wrapper
    return decorator

Example:

@debug_on(TypeError)
def buggy_function()
    ....
    raise TypeError
tom
  • 21,844
  • 6
  • 43
  • 36
Framester
  • 33,341
  • 51
  • 130
  • 192
4

I know this is old and an answer has already been accepted, but I found this useful (for IPython): start IPython with the --pdb option

ipython --pdb <whatever command>
geogeo
  • 124
  • 2
  • 4
2

If you want to wrap only some inner part of a function, or would need to decorate multiple functions otherwise, a context manager could be used as an alternative to the accepted answer. I am now using this simple version that catches all exceptions. I recommend using pudb, but this will work pdb or any other debugger too

from contextlib import contextmanager

@contextmanager
def postmortem_pudb():
    try:
        yield
    except Exception as exc:
        import pudb
        pudb.post_mortem()

Use like this

with postmortem_pudb():
    function_that_might_throw_some()
    ...
    another_function_that_might_throw_some()
    ...
    yet_another_function_that_might_throw_some()

smido
  • 771
  • 6
  • 14
0

You can use ipython with --pdb flag to debug.

Note that all other arguments should be put after an extra -- (before --data in the example below).

For example, to debug my_python_file.py, we can open Terminal, then:

ipython --pdb my_python_file.py -- --dataset my_dataset --num_epochs 10

To quit the debug session, simply type q.

Chau Pham
  • 4,705
  • 1
  • 35
  • 30