Consider the following example:
try:
raise ValueError('test')
except ValueError as err:
breakpoint() # at this point in the debugger, name 'err' is not defined
Here, after the breakpoint is entered, the debugger doesn't have access to the exception instance bound to err:
$ python test.py
--Return--
> test.py(4)<module>()->None
-> breakpoint()
(Pdb) p err
*** NameError: name 'err' is not defined
Why is this the case? How can I access the exception instance? Currently I'm using the following workaround but it feels awkward:
try:
raise ValueError('test')
except ValueError as err:
def _tmp():
breakpoint()
_tmp()
# (lambda: breakpoint())() # or this one alternatively
Interestingly, using this version, I can also access the bound exception err when moving one frame up in the debugger:
$ python test.py
--Return--
> test.py(5)_tmp()->None
-> breakpoint()
(Pdb) up
> test.py(6)<module>()
-> _tmp()
(Pdb) p err
ValueError('test')
Disassembly via dis
In the following I compared two versions, one using breakpoint directly and the other wrapping it in a custom function _breakpoint:
def _breakpoint():
breakpoint()
try:
raise ValueError('test')
except ValueError as err:
breakpoint() # version (a), cannot refer to 'err'
# _breakpoint() # version (b), can refer to 'err'
The output of dis is similar except for some memory locations and the name of the function of course:
So it must be the additional stack frame that allows pdb to refer to the bound exception instance. However it is not clear why this is the case, since within the except block anything can refer to the bound exception instance.
