Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Python, how to drop into the debugger in an except block and have access to the exception instance?

Tags:

python

I'm trying to do something similar to the following:

try:
    1/0
except ZeroDivisionError as e:
    import ipdb; ipdb.set_trace()

When I drop into the debugger, I'd like for the exception instance e to be in my local scope. However, if I run this script, I find that this is not the case:

Kurts-MacBook-Pro-2:Scratch kurtpeek$ python debug_exception.py
--Return--
None
> /Users/kurtpeek/Documents/Scratch/debug_exception.py(4)<module>()
      2         1/0
      3 except ZeroDivisionError as e:
----> 4         import ipdb; ipdb.set_trace()

ipdb> dir()
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__return__', '__spec__', 'ipdb']
ipdb> e
*** NameError: name 'e' is not defined

Why is e not defined? I'm currently using print statements to find out the attributes of e, but I feel this should be possible to do interactively.

like image 551
Kurt Peek Avatar asked Jul 11 '18 17:07

Kurt Peek


People also ask

How do I use pdb debugger in Python?

Starting Python Debugger To start debugging within the program just insert import pdb, pdb. set_trace() commands. Run your script normally and execution will stop where we have introduced a breakpoint. So basically we are hard coding a breakpoint on a line below where we call set_trace().

How do you set a breakpoint in Python pdb?

It's easy to set a breakpoint in Python code to i.e. inspect the contents of variables at a given line. Add import pdb; pdb. set_trace() at the corresponding line in the Python code and execute it. The execution will stop at the breakpoint.


Video Answer


2 Answers

ipdb.set_trace() doesn't quite trigger IPDB immediately. It triggers on the next trace event, which in your case, is after the except block ends.

Python 3 deletes the e variable at the end of the except block, to break traceback reference cycles. Unfortunately for you, that happens before IPDB can trigger.

One hacky workaround you could use would be to add another line after set_trace, so IPDB triggers on the 'line' event:

try:
    1/0
except ZeroDivisionError as e:
    import ipdb
    ipdb.set_trace()
    workaround = True

Another option would be to use post-mortem debugging, which doesn't need to wait for a trace event:

try:
    1/0
except ZeroDivisionError as e:
    import ipdb
    ipdb.post_mortem()

Post-mortem debugging has a number of important differences from regular debugging, though. It'll put you in the (usually dead) stack frame where the exception occurred, rather than the stack frame where the post_mortem call occurred. Those happen to be the same frame in your example, but they usually won't be. Having access to the stack frame where the exception was raised is pretty nice, and you can still navigate to the frame where the exception was caught (but no further, due to Python's unusual traceback system), but it's still a major difference.

Also, you can't step in post-mortem mode. Trying to run next or step will exit debugging.

like image 190
user2357112 supports Monica Avatar answered Oct 18 '22 09:10

user2357112 supports Monica


Actually you can use post_mortem to access the traceback context

import ipdb; ipdb.post_mortem()

ipdb> e
ZeroDivisionError('division by zero',)
like image 44
PRMoureu Avatar answered Oct 18 '22 09:10

PRMoureu