Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
bpo-45292: [PEP-654] exception groups and except* documentation#30158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
f42d81e1eaebb259ae0f5af959d727db9c3274f7f19f90292a285f876a99f8c7a13adbbe728bfcbff13f2b76b03dd967c2a964a2d939a1f64a46570File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -220,6 +220,7 @@ returns the list ``[0, 1, 2]``. | ||
| .. _try: | ||
| .. _except: | ||
| .. _except_star: | ||
| .. _finally: | ||
| The :keyword:`!try` statement | ||
| @@ -237,12 +238,16 @@ The :keyword:`try` statement specifies exception handlers and/or cleanup code | ||
| for a group of statements: | ||
| .. productionlist:: python-grammar | ||
| try_stmt: `try1_stmt` | `try2_stmt` | ||
| try_stmt: `try1_stmt` | `try2_stmt` | `try3_stmt` | ||
| try1_stmt: "try" ":" `suite` | ||
| : ("except" [`expression` ["as" `identifier`]] ":" `suite`)+ | ||
| : ["else" ":" `suite`] | ||
| : ["finally" ":" `suite`] | ||
| try2_stmt: "try" ":" `suite` | ||
| : ("except" "*" `expression` ["as" `identifier`] ":" `suite`)+ | ||
| : ["else" ":" `suite`] | ||
| : ["finally" ":" `suite`] | ||
| try3_stmt: "try" ":" `suite` | ||
| : "finally" ":" `suite` | ||
| @@ -325,6 +330,47 @@ when leaving an exception handler:: | ||
| >>> print(sys.exc_info()) | ||
| (None, None, None) | ||
| .. index:: | ||
| keyword: except_star | ||
| The :keyword:`except*<except_star>` clause(s) are used for handling | ||
| :exc:`ExceptionGroup`s. The exception type for matching is interpreted as in | ||
| the case of :keyword:`except`, but in the case of exception groups we can have | ||
| partial matches when the type matches some of the exceptions in the group. | ||
| This means that multiple except* clauses can execute, each handling part of | ||
| the exception group. Each clause executes once and handles an exception group | ||
iritkatriel marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| of all matching exceptions. Each exception in the group is handled by at most | ||
| one except* clause, the first that matches it. :: | ||
Fidget-Spinner marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| >>> try: | ||
| ... raise ExceptionGroup("eg", | ||
| ... [ValueError(1), TypeError(2), OSError(3), OSError(4)]) | ||
| ... except* TypeError as e: | ||
| ... print(f'caught {type(e)} with nested {e.exceptions}') | ||
| ... except* OSError as e: | ||
| ... print(f'caught {type(e)} with nested {e.exceptions}') | ||
| ... | ||
| caught <class 'ExceptionGroup'> with nested (TypeError(2),) | ||
| caught <class 'ExceptionGroup'> with nested (OSError(3), OSError(4)) | ||
| + Exception Group Traceback (most recent call last): | ||
| | File "<stdin>", line 2, in <module> | ||
| | ExceptionGroup: eg | ||
| +-+---------------- 1 ---------------- | ||
| | ValueError: 1 | ||
| +------------------------------------ | ||
| >>> | ||
| Any remaining exceptions that were not handled by any except* clause | ||
| are re-raised at the end, combined into an exception group along with | ||
| all exceptions that were raised from within except* clauses. | ||
| An except* clause must have a matching type, and this type cannot be a | ||
| subclass of :exc:`BaseExceptionGroup`. It is not possible to mix except | ||
| and except* in the same :keyword:`try`. :keyword:`break`, | ||
| :keyword:`continue` and :keyword:`return` cannot appear in an except* | ||
| clause. | ||
| .. index:: | ||
| keyword: else | ||
| statement: return | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -496,3 +496,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')] | ||
iritkatriel marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| ... 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) | ||
| ... | ||
Uh oh!
There was an error while loading. Please reload this page.