README.rst (5829B)
1 .. image:: https://github.com/agronholm/exceptiongroup/actions/workflows/test.yml/badge.svg 2 :target: https://github.com/agronholm/exceptiongroup/actions/workflows/test.yml 3 :alt: Build Status 4 .. image:: https://coveralls.io/repos/github/agronholm/exceptiongroup/badge.svg?branch=main 5 :target: https://coveralls.io/github/agronholm/exceptiongroup?branch=main 6 :alt: Code Coverage 7 8 This is a backport of the ``BaseExceptionGroup`` and ``ExceptionGroup`` classes from 9 Python 3.11. 10 11 It contains the following: 12 13 * The ``exceptiongroup.BaseExceptionGroup`` and ``exceptiongroup.ExceptionGroup`` 14 classes 15 * A utility function (``exceptiongroup.catch()``) for catching exceptions possibly 16 nested in an exception group 17 * Patches to the ``TracebackException`` class that properly formats exception groups 18 (installed on import) 19 * An exception hook that handles formatting of exception groups through 20 ``TracebackException`` (installed on import) 21 * Special versions of some of the functions from the ``traceback`` module, modified to 22 correctly handle exception groups even when monkey patching is disabled, or blocked by 23 another custom exception hook: 24 25 * ``traceback.format_exception()`` 26 * ``traceback.format_exception_only()`` 27 * ``traceback.print_exception()`` 28 * ``traceback.print_exc()`` 29 * A backported version of ``contextlib.suppress()`` from Python 3.12.1 which also 30 handles suppressing exceptions inside exception groups 31 32 If this package is imported on Python 3.11 or later, the built-in implementations of the 33 exception group classes are used instead, ``TracebackException`` is not monkey patched 34 and the exception hook won't be installed. 35 36 See the `standard library documentation`_ for more information on exception groups. 37 38 .. _standard library documentation: https://docs.python.org/3/library/exceptions.html 39 40 Catching exceptions 41 =================== 42 43 Due to the lack of the ``except*`` syntax introduced by `PEP 654`_ in earlier Python 44 versions, you need to use ``exceptiongroup.catch()`` to catch exceptions that are 45 potentially nested inside an exception group. This function returns a context manager 46 that calls the given handler for any exceptions matching the sole argument. 47 48 The argument to ``catch()`` must be a dict (or any ``Mapping``) where each key is either 49 an exception class or an iterable of exception classes. Each value must be a callable 50 that takes a single positional argument. The handler will be called at most once, with 51 an exception group as an argument which will contain all the exceptions that are any 52 of the given types, or their subclasses. The exception group may contain nested groups 53 containing more matching exceptions. 54 55 Thus, the following Python 3.11+ code: 56 57 .. code-block:: python 58 59 try: 60 ... 61 except* (ValueError, KeyError) as excgroup: 62 for exc in excgroup.exceptions: 63 print('Caught exception:', type(exc)) 64 except* RuntimeError: 65 print('Caught runtime error') 66 67 would be written with this backport like this: 68 69 .. code-block:: python 70 71 from exceptiongroup import BaseExceptionGroup, catch 72 73 def value_key_err_handler(excgroup: BaseExceptionGroup) -> None: 74 for exc in excgroup.exceptions: 75 print('Caught exception:', type(exc)) 76 77 def runtime_err_handler(exc: BaseExceptionGroup) -> None: 78 print('Caught runtime error') 79 80 with catch({ 81 (ValueError, KeyError): value_key_err_handler, 82 RuntimeError: runtime_err_handler 83 }): 84 ... 85 86 **NOTE**: Just like with ``except*``, you cannot handle ``BaseExceptionGroup`` or 87 ``ExceptionGroup`` with ``catch()``. 88 89 Suppressing exceptions 90 ====================== 91 92 This library contains a backport of the ``contextlib.suppress()`` context manager from 93 Python 3.12.1. It allows you to selectively ignore certain exceptions, even when they're 94 inside exception groups: 95 96 .. code-block:: python 97 98 from exceptiongroup import suppress 99 100 with suppress(RuntimeError): 101 raise ExceptionGroup("", [RuntimeError("boo")]) 102 103 Notes on monkey patching 104 ======================== 105 106 To make exception groups render properly when an unhandled exception group is being 107 printed out, this package does two things when it is imported on any Python version 108 earlier than 3.11: 109 110 #. The ``traceback.TracebackException`` class is monkey patched to store extra 111 information about exception groups (in ``__init__()``) and properly format them (in 112 ``format()``) 113 #. An exception hook is installed at ``sys.excepthook``, provided that no other hook is 114 already present. This hook causes the exception to be formatted using 115 ``traceback.TracebackException`` rather than the built-in rendered. 116 117 If ``sys.exceptionhook`` is found to be set to something else than the default when 118 ``exceptiongroup`` is imported, no monkeypatching is done at all. 119 120 To prevent the exception hook and patches from being installed, set the environment 121 variable ``EXCEPTIONGROUP_NO_PATCH`` to ``1``. 122 123 Formatting exception groups 124 --------------------------- 125 126 Normally, the monkey patching applied by this library on import will cause exception 127 groups to be printed properly in tracebacks. But in cases when the monkey patching is 128 blocked by a third party exception hook, or monkey patching is explicitly disabled, 129 you can still manually format exceptions using the special versions of the ``traceback`` 130 functions, like ``format_exception()``, listed at the top of this page. They work just 131 like their counterparts in the ``traceback`` module, except that they use a separately 132 patched subclass of ``TracebackException`` to perform the rendering. 133 134 Particularly in cases where a library installs its own exception hook, it is recommended 135 to use these special versions to do the actual formatting of exceptions/tracebacks. 136 137 .. _PEP 654: https://www.python.org/dev/peps/pep-0654/