Open jaraco opened 1 year ago
Can you inspect the .__context__
of the ValueError
? That'd be the usual way of working with chained exceptions.
Can you inspect the
.__context__
of theValueError
?
Perhaps, but how do I get a handle on that exception instance? In the SO post, OP points out that sys.last_value
is viable in my example:
> /Users/jaraco/draft/test_something.py(9)test_something()
-> raise ValueError()
(Pdb) import sys
(Pdb) sys.last_value
ValueError()
(Pdb) sys.last_value.__context__
TypeError()
(Pdb) import pdb, sys; pdb.post_mortem(sys.last_value.__context__.__traceback__)
> /Users/jaraco/draft/test_something.py(2)raise_something()
-> raise TypeError()
(Pdb)
I'm 90% sure when I attempted this in a real-world case, sys.last_value
wasn't viable (had been cleared), I suspect by the presence of a fixture or by the fixture itself. I don't recall now what I was working on when I stumbled into this issue, so I may struggle to replicate the situation I had encountered.
Aha. The issue is with a handled exception:
def raise_something():
raise TypeError()
def test_something():
try:
raise_something()
except TypeError:
try:
raise ValueError()
except ValueError:
breakpoint()
In this example, after the breakpoint is reached, there's no longer a handle to the ValueError
:
--Return--
> /Users/jaraco/draft/test_something.py(12)test_something()->None
-> breakpoint()
(Pdb) import sys
(Pdb) sys.last_value
*** AttributeError: module 'sys' has no attribute 'last_value'
(Pdb) sys.exc_info()
(<class 'AttributeError'>, AttributeError("'PytestPdbWrapper' object has no attribute 'do_sys'"), <traceback object at 0x103b2d7c0>)
I even tried changing the catch to except ValueError as exc:
, but even then, exc
appears not to be in the namespace:
--Return--
> /Users/jaraco/draft/test_something.py(12)test_something()->None
-> breakpoint()
(Pdb) exc.__context__
*** NameError: name 'exc' is not defined
(Pdb) l
7 raise_something()
8 except TypeError:
9 try:
10 raise ValueError()
11 except ValueError as exc:
12 -> breakpoint()
[EOF]
Interestingly, the issue seems to be that if I'm handling the exception, I need a statement after the breakpoint in order for that block to still be active. Changing the code to the following allows the breakpoint to expose exc
, from which __context__
can be used:
def raise_something():
raise TypeError()
def test_something():
try:
raise_something()
except TypeError:
try:
raise ValueError()
except ValueError as exc:
breakpoint()
pass
Still, it would be nice if sys.exc_info()
contained the exception context from when the exception occurred and not the AttributeError
for PytestPdbWrapper
.
I even tried changing the catch to
except ValueError as exc:
, but even then,exc
appears not to be in the namespace
That behavior appears to be a known issue (python/cpython/#111744).
What's the problem this feature will solve?
I've got a test similar to the following with a nested exception:
Running the test produces:
I'd like to be able to inspect the stack where
raise_something()
failed. Best I can tell, that context is unreachable.If I use
--pdb
, the code breaks at test.py:9 with theValueError
, but by the time pytest has handled the error,sys.exc_info()
no longer points to the execution context where the failure occurred, but instead may be(None, None, None)
or perhaps an unrelated context like(<class 'AttributeError'>, AttributeError("'PytestPdbWrapper' object has no attribute 'do_sys'"), <traceback object at 0x101f26c40>)
. Therefore, I'm unable to take advantages of techniques to trace to the inner exception stack.Describe the solution you'd like
In the pdb context or in a global variable or in some other way, expose the original unhandled exception context.