diff --git a/pep-0654.rst b/pep-0654.rst index 1ee5d4e3c62..a5d1f550e06 100644 --- a/pep-0654.rst +++ b/pep-0654.rst @@ -133,14 +133,24 @@ Specification ExceptionGroup -------------- -The new builtin exception type, ``ExceptionGroup`` is a subclass of -``BaseException``, so it is assignable to ``Exception.__cause__`` and -``Exception.__context__``, and can be raised and handled as any exception -with ``raise ExceptionGroup(...)`` and ``try: ... except ExceptionGroup: ...``. - -Its constructor takes two positional-only parameters: a message string and a -sequence of the nested exceptions, for example: +We propose to add two new builtin exception types: +``BaseExceptionGroup(BaseException)`` and +``ExceptionGroup(BaseExceptionGroup, Exception)``. They are assignable to +``Exception.__cause__`` and ``Exception.__context__``, and they can be +raised and handled as any exception with ``raise ExceptionGroup(...)`` and +``try: ... except ExceptionGroup: ...`` or ``raise BaseExceptionGroup(...)`` +and ``try: ... except BaseExceptionGroup: ...``. + +Both have a constructor that takes two positional-only parameters: a message +string and a sequence of the nested exceptions, for example: ``ExceptionGroup('issues', [ValueError('bad value'), TypeError('bad type')])``. +The difference between them is that ``ExceptionGroup`` can only wrap +``Exception`` subclasses while ``BaseExceptionGroup`` can wrap any +``BaseException`` subclass. A factory method that inspects the nested +execptions and selects between ``ExceptionGroup`` and ``BaseExceptionGroup`` +makes the choice automatic. In the rest of the document, unless stated +otherwise, when we refer to ``ExceptionGroup`` we mean either an +``ExceptionGroup`` or a ``BaseExceptionGroup``. The ``ExceptionGroup`` class exposes these parameters in the fields ``message`` and ``errors``. A nested exception can also be an ``ExceptionGroup`` so the @@ -951,17 +961,20 @@ propose in this PEP will not break any existing code: Programs will only be impacted by the changes proposed in this PEP once they begin to use ``ExceptionGroups`` and ``except*``. +* An important concern was that ``except Exception:`` will continue to catch + almost all exceptions, and by making ``ExceptionGroup`` extend ``Exception`` + we ensured that this will be the case. ``BaseExceptionGroups`` will not be + caught, which is appropriate because they include exceptions that would not + have been caught by ``except Exception``. Once programs begin to use these features, there will be migration issues to consider: -* An ``except Exception:`` clause will not catch ``ExceptionGroup`` because it - is derived from ``BaseException``. Any such clause will need to be replaced - by ``except (Exception, ExceptionGroup):`` or ``except *Exception:``. - -* Similarly, any ``except T:`` clause that wraps code which is now potentially - raising ``ExceptionGroup`` needs to become ``except *T:``, and its body may - need to be updated. +* An ``except T:`` clause that wraps code which is now potentially raising + ``ExceptionGroup`` may need to become ``except *T:``, and its body may + need to be updated. This means that raising an ``ExceptionGroup`` is an + API-breaking change and will likely be done in new APIs rather than + added to existing ones. * Libraries that need to support older Python versions will not be able to use ``except*`` or raise ``ExceptionGroups``.