Skip to content

Instantly share code, notes, and snippets.

@iritkatriel
Last active Jan 11, 2022
Embed
What would you like to do?
Towards removing the exc_info triplet from Python's API
Following recent work [https://bugs.python.org/issue45711], the interpreter's internal
representation of the active exception (sys.exc_info()) is no longer the (typ, val, tb)
triplet, but just the exception instance.
For backward compatibility, existing APIs reconstruct the triplet from the instance, so
for example ``sys.exc_info()`` returns the triplet ``(type(exc), exc, exc.__traceback__)``,
where ``exc`` is the active exception.
Removing the triplet representation entirely is not something we can realistically
do anytime soon. However, it is feasible to reach a state where the triplet need not
show up in new python code, making the language simpler and removing some redundancy.
Below I am collecting a list of the changes required to achieve that. We don't have
to do all of them, and we certainly don't have to do all at once.
1. Getters/setters for the active exception
In python, we have sys.exc_info() and in the C api we have both PyErr_GetExcInfo
and PyErr_SetExcInfo. We will need alternatives that get/set a single exception
instance rather than the tuple. Proposed names:
sys.exception() (as suggested in PEP 3134)
PyErr_GetActiveExc() / PyErr_SetActiveExc()
The reason that we need to specify "Active" in the names in the C api but not in python
is because in the C api we can also access the interpreter's error indicator (i.e., the
in-flight exception) via PyErr_Fetch/Restore.
On the other hand, from Python code it is only possible to access the active exception.
(By definition, the error indicator is never set when python code is executing).
2. stdlib APIs that accept a (typ, val, tb) triplet representing an exception:
These APIs can be made versatile, as was already done in the traceback
[https://bugs.python.org/issue26389] and logging [https://bugs.python.org/issue20537]
modules. We would need to similarly update also:
In unittest.result, methods like addError, addFailure, etc accept the exc_info tuple.
They will need to accept an exc as well.
3. callback signatures
The exc_info is in the signatures of a few callbacks that the interpreter calls:
1. sys.excepthook(typ, val, tb)
2. __exit__/__aexit__(self, typ, val, tb) methods of context managers
In both of the above cases we would like to support the same callback
with a simplified signature: sys.excepthook(exc) and __exit__(self, exc).
This will require inspection of the signature of the callback, to find out
how many arguments it expects and call with exc or exc_info accordingly.
This is fairly straightforward in python, but in the C api I don't think
this is currently formalized, so we need to add some kind of introspection
API for callables (or maybe not all callables, just methods and functions,
and assume that any other callable has the legacy API, then document the
restrictions).
This appears to be the most technically complicated item in this list, but
I think the ergonomic gain of simplifying the __exit__ signature may well
be worth it.
3. Lib/shutil methods accept an onerror callback that accepts the exc_info
tuple as one of its args.
In this case inspection of the callable won't help because the callback
takes the tuple in a single arg. It will probably be necessary for users
to explicitly indicate that the callback is expecting exc rather than
exc_info.
@gvanrossum
Copy link

gvanrossum commented Jan 11, 2022

sys.exception() (as suggested in PEP 3134)

Note that the PEP proposes it as a member, not as a function. (But we should not copy that mistake.)

I agree with all these proposals. Fixing __exit__() sounds like the most painful one (being a dunder).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment