Briefly:PyErr_SetObject(exc_type, exc_val)
does not create a new exception iff isinstance(exc_val, BaseException)
, but uses exc_val
instead.
Callers of PyErr_SetObject()
need various workarounds to handle this.
The long version:
Internally CPython handles exceptions as a triple (type, value, traceback)
, but the language treats exceptions as a single value.
This a legacy of the olden days before proper exceptions.
To handle adding proper exceptions to Python, various error handling functions, specifically _PyErr_SetObject
still treat exceptions as triples, with the convention that if the value is an exception, then the exception is already normalized.
One other oddity is that if exc_val
is a tuple, it is treated as the *
arguments to exc_type
when calling it. So, if isinstance(exc_val, BaseException)
the desired behavior can be achieved by wrapping exc_val
in a one-tuple.
As a consequence, both _PyErr_SetKeyError
and _PyGen_SetStopIterationValue
are a lot more complex than they should be to workaround this behavior.
We could make PyErr_SetObject
act as documented, but that is likely to break C extensions, given how old this behavior is, and that it is relied on throughout CPython.
Code that does the following is common:
exc = new_foo_exception(); PyErr_SetObject(&PyFooException_Type, exc);
We could just document the current behavior, but the current behavior is strange.
What I suggest is this:
PyErr_SetObject()
accuratelyThis is an old bug going back to the 2 series.
Linked PRsAlso relevant:
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4