diff --git a/pep-0654.rst b/pep-0654.rst index ccd9a634c14..674079acf90 100644 --- a/pep-0654.rst +++ b/pep-0654.rst @@ -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