PEP 654: Add section about handling ExceptionGroups (#1841)

This commit is contained in:
Irit Katriel 2021-02-26 02:49:58 +00:00 committed by GitHub
parent e93b2efdea
commit d729120776
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 55 additions and 12 deletions

View File

@ -306,6 +306,47 @@ in the following example:
ValueError: 1
>>>
Handling ``ExceptionGroups``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We expect that when programs catch and handle ``ExceptionGroups``, they will
typically either query to check if it has leaf exceptions for which some
condition holds (using ``subgroup`` or ``split``) or format the exception
(using the ``traceback`` module's methods).
It is unlikely to be useful to inspect the individual leaf exceptions. To see
why, suppose that an application caught an ``ExceptionGroup`` raised in an
``asyncio.gather()`` call. At this stage, the context for each specific
exception is lost. Any recovery for this exception should have been performed
before it was grouped with other exceptions into the ``ExceptionGroup`` [10]_.
Furthermore, the application is likely to react in the same way to any number
of instances of a certain exception type, so it is more likely that we will
want to know whether ``eg.subgroup(T)`` is None or not, than we are to be
intersted in the number of ``Ts`` in ``eg``.
If it does turn out to be necessary for an applicaiton to iterate over the
individual exceptions of an ``ExceptionGroup`` ``eg``, this can be done by
calling ``traverse(eg)``, where ``traverse`` is defined as follows:
.. code-block::
def traverse(exc, tbs=None, cause=None, context=None):
if tbs is None:
tbs = []
cause = exc.__cause__
context = exc.__context__
tbs.append(exc.__traceback__)
if isinstance(exc, ExceptionGroup):
for e in exc.errors:
traverse(e, tbs, cause, context)
else:
# exc is a leaf exception and its traceback
# is the concatenation of the traceback in tbs
process_leaf(exc, tbs, cause, context)
tbs.pop()
except*
-------
@ -930,7 +971,7 @@ Reference Implementation
========================
We developed these concepts (and the examples for this PEP) with
the help of the reference implementation [10]_.
the help of the reference implementation [11]_.
It has the builtin ``ExceptionGroup`` along with the changes to the traceback
formatting code, in addition to the grammar, compiler and interpreter changes
@ -951,18 +992,20 @@ metadata as the original, while the raised ones do not.
Rejected Ideas
==============
The ExceptionGroup API
----------------------
Make ExceptionGroup Iterable
----------------------------
We considered making ``ExceptionGroups`` iterable, so that ``list(eg)`` would
produce a flattened list of the leaf exceptions contained in the group.
We decided that this would not be not be a sound API, because the metadata
We decided that this would not be a sound API, because the metadata
(cause, context and traceback) of the individual exceptions in a group is
incomplete and this could create problems. If use cases arise where this
can be helpful, we can document (or even provide in the standard library)
a sound recipe for accessing an individual exception: use the ``split()``
method to create an ``ExceptionGroup`` for a single exception and then
extract the contained exception with the correct metadata.
incomplete and this could create problems.
Furthermore, as we explained in the `Handling ExceptionGroups`_ section, we
find it unlikely that iteration over leaf exceptions will have many use cases.
We did, however, provide there the code for a traversal algorithm that
correctly constructs each leaf exception's metadata. If it does turn out to
be useful in practice, we can add that utility to the standard library.
Traceback Representation
------------------------
@ -1133,7 +1176,7 @@ See Also
========
* An analysis of how exception groups will likely be used in asyncio
programs: [11]_.
programs: [10]_.
* The issue where the ``except*`` concept was first formalized: [12]_.
@ -1163,9 +1206,9 @@ References
.. [9] https://trio.readthedocs.io/en/stable/reference-core.html#trio.MultiError
.. [10] https://github.com/iritkatriel/cpython/tree/exceptionGroup-stage5
.. [10] https://github.com/python/exceptiongroups/issues/3#issuecomment-716203284
.. [11] https://github.com/python/exceptiongroups/issues/3#issuecomment-716203284
.. [11] https://github.com/iritkatriel/cpython/tree/exceptionGroup-stage5
.. [12] https://github.com/python/exceptiongroups/issues/4