Repository navigation
Unexpected location of naked exception wrapped in except* block #128799
Description
Bug report
Bug description:
When an ExceptionGroup is implicitly constructed by catching a naked exception in an except* block, the traceback of the ExceptionGroup seems to point to the stackframe above where it is logically created:
def f():
try:
raise Exception # Exception (inner) traceback terminates here
except* Exception as e:
raise
f() # ExceptionGroup (wrapper) traceback terminates here→
+ Exception Group Traceback (most recent call last):
| File "/home/jobh/src/hypothesis/test_naked_exception.py", line 7, in <module>
| f() # ExceptionGroup (wrapper) traceback terminates here
| ^^^
| ExceptionGroup: (1 sub-exception)
+-+---------------- 1 ----------------
| Traceback (most recent call last):
| File "/home/jobh/src/hypothesis/test_naked_exception.py", line 3, in f
| raise Exception # Exception (inner) traceback terminates here
| ^^^^^^^^^^^^^^^
| Exception
+------------------------------------
I'm not sure if this should be called a bug, as it's not specifically documented how the wrapping ExceptionGroup traceback is constructed. But it is surprising, and did cause a bug in hypothesis where the Exception traceback is used to detect whether an exception originates in hypothesis itself or in user code 12. The issue being that for wrapped naked exceptions we have to inspect the inner exception since the outer exception appears to be raised by the calling function.
As an alternative to the current behaviour, would it be possible to create the wrapper ExceptionGroup with a traceback pointing to where it is logically triggered - i.e., the except* block - rather than initially empty? IMO, that would be less suprising and would allow us to use the traceback without special-casing ExceptionGroup.
([edit] Or, if the desire is to avoid branching the traceback between the wrapper and the inner exception, use the outermost frame of the naked exception as the initial ExceptionGroup traceback. This would still avoid the appearance of happening in the caller.)
CPython versions tested on:
3.11, 3.12, 3.13
Operating systems tested on:
Linux
Linked PRs
- gh-128799: Add frame of except* to traceback when wrapping a naked exception #128971
- [3.13] gh-128799: Add frame of except* to traceback when wrapping a naked exception (#128971) #129299
- [3.12] gh-128799: Add frame of except* to traceback when wrapping a naked exception (GH-128971) #129328
Activity
picnixz commentedon Jan 14, 2025
cc @iritkatriel @1st1 @gvanrossum as the authors of PEP-654.
iritkatriel commentedon Jan 14, 2025
I think it's fine to add a frame in the traceback for the
except Exception*line. It would be clearer than making it look like theraise Exceptionline created anExceptionGroup..pythongh-128799: Add frame of except* to traceback when wrapping a na…
iritkatriel commentedon Jan 18, 2025
PR to fix it: #128971
I would call this a bug and backport. @gvanrossum do you agree?
iritkatriel commentedon Jan 18, 2025
With the PR:
gvanrossum-ms commentedon Jan 18, 2025
Why does the
raiseon line 5 show up in the traceback?iritkatriel commentedon Jan 18, 2025
Good catch. It's because the location info for the
except*in the code object spans the whole block. I'll need to fix that:iritkatriel commentedon Jan 19, 2025
This is a fix for the location info: #129026
Merge branch 'main' into pythongh-128799
Merge branch 'main' into pythongh-128799
iritkatriel commentedon Jan 22, 2025
There is now also an AST issue to add more precise locations for compound statements: #129157
I don't think that should hold off merging the fix for this issue. It's an orthogonal problem to the one presented here.
Merge branch 'main' into pythongh-128799
gh-128799: Add frame of except* to traceback when wrapping a naked ex…
pythongh-128799: Add frame of except* to traceback when wrapping a na…
pythongh-128799: Add frame of except* to traceback when wrapping a na…
[3.12] pythongh-128799: Add frame of except* to traceback when wrappi…
[3.12] gh-128799: Add frame of except* to traceback when wrapping a n…
[3.13] gh-128799: Add frame of except* to traceback when wrapping a n…