diff options
author | Irit Katriel <1055913+iritkatriel@users.noreply.github.com> | 2022-01-06 19:05:34 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-06 19:05:34 (GMT) |
commit | 9925e70e4811841556747a77acd89c1a70bf344a (patch) | |
tree | 8be9c36aebbe390ab92e8db0f2ad477e5a09eec7 /Doc/tutorial | |
parent | 68c76d9766cccb5fd992b0ac4b39645d9665dbe2 (diff) | |
download | cpython-9925e70e4811841556747a77acd89c1a70bf344a.zip cpython-9925e70e4811841556747a77acd89c1a70bf344a.tar.gz cpython-9925e70e4811841556747a77acd89c1a70bf344a.tar.bz2 |
bpo-45292: [PEP-654] exception groups and except* documentation (GH-30158)
Diffstat (limited to 'Doc/tutorial')
-rw-r--r-- | Doc/tutorial/errors.rst | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index 3f09db2..ad1ef84 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -462,3 +462,92 @@ used in a way that ensures they are always cleaned up promptly and correctly. :: After the statement is executed, the file *f* is always closed, even if a problem was encountered while processing the lines. Objects which, like files, provide predefined clean-up actions will indicate this in their documentation. + + +.. _tut-exception-groups: + +Raising and Handling Multiple Unrelated Exceptions +================================================== + +There are situations where it is necessary to report several exceptions that +have occurred. This it often the case in concurrency frameworks, when several +tasks may have failed in parallel, but there are also other use cases where +it is desirable to continue execution and collect multiple errors rather than +raise the first exception. + +The builtin :exc:`ExceptionGroup` wraps a list of exception instances so +that they can be raised together. It is an exception itself, so it can be +caught like any other exception. :: + + >>> def f(): + ... excs = [OSError('error 1'), SystemError('error 2')] + ... raise ExceptionGroup('there were problems', excs) + ... + >>> f() + + Exception Group Traceback (most recent call last): + | File "<stdin>", line 1, in <module> + | File "<stdin>", line 3, in f + | ExceptionGroup: there were problems + +-+---------------- 1 ---------------- + | OSError: error 1 + +---------------- 2 ---------------- + | SystemError: error 2 + +------------------------------------ + >>> try: + ... f() + ... except Exception as e: + ... print(f'caught {type(e)}: e') + ... + caught <class 'ExceptionGroup'>: e + >>> + +By using ``except*`` instead of ``except``, we can selectively +handle only the exceptions in the group that match a certain +type. In the following example, which shows a nested exception +group, each ``except*`` clause extracts from the group exceptions +of a certain type while letting all other exceptions propagate to +other clauses and eventually to be reraised. :: + + >>> def f(): + ... raise ExceptionGroup("group1", + ... [OSError(1), + ... SystemError(2), + ... ExceptionGroup("group2", + ... [OSError(3), RecursionError(4)])]) + ... + >>> try: + ... f() + ... except* OSError as e: + ... print("There were OSErrors") + ... except* SystemError as e: + ... print("There were SystemErrors") + ... + There were OSErrors + There were SystemErrors + + Exception Group Traceback (most recent call last): + | File "<stdin>", line 2, in <module> + | File "<stdin>", line 2, in f + | ExceptionGroup: group1 + +-+---------------- 1 ---------------- + | ExceptionGroup: group2 + +-+---------------- 1 ---------------- + | RecursionError: 4 + +------------------------------------ + >>> + +Note that the exceptions nested in an exception group must be instances, +not types. This is because in practice the exceptions would typically +be ones that have already been raised and caught by the program, along +the following pattern:: + + >>> excs = [] + ... for test in tests: + ... try: + ... test.run() + ... except Exception as e: + ... excs.append(e) + ... + >>> if excs: + ... raise ExceptionGroup("Test Failures", excs) + ... + |