This is a backport of the BaseExceptionGroup
and ExceptionGroup
classes from
Python 3.11.
It contains the following:
- The
exceptiongroup.BaseExceptionGroup
andexceptiongroup.ExceptionGroup
classes - A utility function (
exceptiongroup.catch()
) for catching exceptions possibly nested in an exception group - Patches to the
TracebackException
class that properly formats exception groups (installed on import) - An exception hook that handles formatting of exception groups through
TracebackException
(installed on import) - Special versions of some of the functions from the
traceback
module, modified to correctly handle exception groups even when monkey patching is disabled, or blocked by another custom exception hook:traceback.format_exception()
traceback.format_exception_only()
traceback.print_exception()
traceback.print_exc()
If this package is imported on Python 3.11 or later, the built-in implementations of the
exception group classes are used instead, TracebackException
is not monkey patched
and the exception hook won't be installed.
See the standard library documentation for more information on exception groups.
Due to the lack of the except*
syntax introduced by PEP 654 in earlier Python
versions, you need to use exceptiongroup.catch()
to catch exceptions that are
potentially nested inside an exception group. This function returns a context manager
that calls the given handler for any exceptions matching the sole argument.
The argument to catch()
must be a dict (or any Mapping
) where each key is either
an exception class or an iterable of exception classes. Each value must be a callable
that takes a single positional argument. The handler will be called at most once, with
an exception group as an argument which will contain all the exceptions that are any
of the given types, or their subclasses. The exception group may contain nested groups
containing more matching exceptions.
Thus, the following Python 3.11+ code:
try:
...
except* (ValueError, KeyError) as excgroup:
for exc in excgroup.exceptions:
print('Caught exception:', type(exc))
except* RuntimeError:
print('Caught runtime error')
would be written with this backport like this:
from exceptiongroup import ExceptionGroup, catch
def value_key_err_handler(excgroup: ExceptionGroup) -> None:
for exc in excgroup.exceptions:
print('Caught exception:', type(exc))
def runtime_err_handler(exc: ExceptionGroup) -> None:
print('Caught runtime error')
with catch({
(ValueError, KeyError): value_key_err_handler,
RuntimeError: runtime_err_handler
}):
...
NOTE: Just like with except*
, you cannot handle BaseExceptionGroup
or
ExceptionGroup
with catch()
.
To make exception groups render properly when an unhandled exception group is being printed out, this package does two things when it is imported on any Python version earlier than 3.11:
- The
traceback.TracebackException
class is monkey patched to store extra information about exception groups (in__init__()
) and properly format them (informat()
) - An exception hook is installed at
sys.excepthook
, provided that no other hook is already present. This hook causes the exception to be formatted usingtraceback.TracebackException
rather than the built-in rendered.
If sys.exceptionhook
is found to be set to something else than the default when
exceptiongroup
is imported, no monkeypatching is done at all.
To prevent the exception hook and patches from being installed, set the environment
variable EXCEPTIONGROUP_NO_PATCH
to 1
.
Normally, the monkey patching applied by this library on import will cause exception
groups to be printed properly in tracebacks. But in cases when the monkey patching is
blocked by a third party exception hook, or monkey patching is explicitly disabled,
you can still manually format exceptions using the special versions of the traceback
functions, like format_exception()
, listed at the top of this page. They work just
like their counterparts in the traceback
module, except that they use a separately
patched subclass of TracebackException
to perform the rendering.
Particularly in cases where a library installs its own exception hook, it is recommended to use these special versions to do the actual formatting of exceptions/tracebacks.