Expose _PyExc_PrepReraiseStar (and other intrinsics?) in the unstable api
Opened this issue · 4 comments
Copied from a discuss discussion:
I’m looking into implementing
except*
in Cython. Most of it’s relatively straight-forward (I hope) but a big chunk of the important logic is in_PyExc_PrepReraiseStar
and it doesn’t seem possible to access that without including internal headers (which is never popular).It’d probably be possible to reimplement the logic for it myself, but it’s obviously quite a large chunk of code to be copying and trying to keep up to date.
Would it be possible to expose this more publicly? This is unlikely to be performance critical so, even something as simple as a method on
BaseExceptionGroup
that’s accessible from Python would do.(For the moment I’m probably just doing to do the internal header access, but it’d be nice to be able to do it right in future)
I was directed here:
I think this function, along with the other intrinsics (which are functions that implement an opcode) can be exposed as part of the ‘unstable API’. I’m not sure where we are on having that?
I'd slightly disagree with this interpretation - while it looks like _PyExc_PrepReraiseStar
is an intrinsic, it also seems like something that can be done to an instance of BaseExceptionGroup
independently of the bytecode (although practically I don't know why you'd want to except for reimplementing the interpreter).
_PyExc_PrepReraiseStar
[...] also seems like something that can be done to an instance ofBaseExceptionGroup
independently of the bytecode (although practically I don't know why you'd want to except for reimplementing the interpreter).
If we are to expose this, I think it has to be as "part of the implementation of except*
", rather than "a BaseExceptionGroup
operation", because (as you say) it won't be used for anything other than implementing except*
and people will want to know if the implementation of except*
changes.
And if we do expose it as an implementation detail, then it can't be part of the normal API.
I think I was erroneously think that this function has to exist for any implementation of except*
to be possible (and thus it isn't really an implementation detail).
I guess that isn't really true, because it'd be possible to write an implementation that builds up the result exception group incrementally after each individual except*
is processed.
In that case possibly the fundamental building blocks (that have to exist whatever implementation Python choses) are probably is_same_exception_metadata
and exception_group_projection
?
is_same_exception_metadata
uses the metadata comparison to determine whether one exception group is a subgroup of another. This method is correct within the interpreter's execution of an except* clause (the traceback of something raise in an except* clause is different to the traceback of what was raised in the try body). But it's not necessarily correct for hand-crafted input (you can construct different ExceptionGroups with the same metadata and confuse this check). If we want to make it work in general we need to recurse into the exception groups and make sure one is completely contained in the other. For the interpreter's except*
implementation that would be wasteful.
In any case, I think is_subgroup
is a fundamental operation, but is_same_exception_metadata
is not the only possible way to implement this check.
I've created a PR for _PyExc_PrepReraiseStar. I still see this issue as a more general one in the context of the C API, about exposing interpreter implementation details.