Skip to content

Commit 4782b9f

Browse files
iritkatrielmiss-islington
authored andcommitted
pythongh-135629: rewrite language reference section on except* to improve clarity (pythonGH-136150)
(cherry picked from commit a651ec9) Co-authored-by: Irit Katriel <[email protected]>
1 parent 9d0ca23 commit 4782b9f

File tree

1 file changed

+32
-28
lines changed

1 file changed

+32
-28
lines changed

Doc/reference/compound_stmts.rst

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -335,15 +335,29 @@ stored in the :mod:`sys` module is reset to its previous value::
335335
:keyword:`!except*` clause
336336
--------------------------
337337

338-
The :keyword:`!except*` clause(s) are used for handling
339-
:exc:`ExceptionGroup`\s. The exception type for matching is interpreted as in
340-
the case of :keyword:`except`, but in the case of exception groups we can have
341-
partial matches when the type matches some of the exceptions in the group.
342-
This means that multiple :keyword:`!except*` clauses can execute,
343-
each handling part of the exception group.
344-
Each clause executes at most once and handles an exception group
345-
of all matching exceptions. Each exception in the group is handled by at most
346-
one :keyword:`!except*` clause, the first that matches it. ::
338+
The :keyword:`!except*` clause(s) specify one or more handlers for groups of
339+
exceptions (:exc:`BaseExceptionGroup` instances). A :keyword:`try` statement
340+
can have either :keyword:`except` or :keyword:`!except*` clauses, but not both.
341+
The exception type for matching is mandatory in the case of :keyword:`!except*`,
342+
so ``except*:`` is a syntax error. The type is interpreted as in the case of
343+
:keyword:`!except`, but matching is performed on the exceptions contained in the
344+
group that is being handled. An :exc:`TypeError` is raised if a matching
345+
type is a subclass of :exc:`!BaseExceptionGroup`, because that would have
346+
ambiguous semantics.
347+
348+
When an exception group is raised in the try block, each :keyword:`!except*`
349+
clause splits (see :meth:`~BaseExceptionGroup.split`) it into the subgroups
350+
of matching and non-matching exceptions. If the matching subgroup is not empty,
351+
it becomes the handled exception (the value returned from :func:`sys.exception`)
352+
and assigned to the target of the :keyword:`!except*` clause (if there is one).
353+
Then, the body of the :keyword:`!except*` clause executes. If the non-matching
354+
subgroup is not empty, it is processed by the next :keyword:`!except*` in the
355+
same manner. This continues until all exceptions in the group have been matched,
356+
or the last :keyword:`!except*` clause has run.
357+
358+
After all :keyword:`!except*` clauses execute, the group of unhandled exceptions
359+
is merged with any exceptions that were raised or re-raised from within
360+
:keyword:`!except*` clauses. This merged exception group propagates on.::
347361

348362
>>> try:
349363
... raise ExceptionGroup("eg",
@@ -356,22 +370,18 @@ one :keyword:`!except*` clause, the first that matches it. ::
356370
caught <class 'ExceptionGroup'> with nested (TypeError(2),)
357371
caught <class 'ExceptionGroup'> with nested (OSError(3), OSError(4))
358372
+ Exception Group Traceback (most recent call last):
359-
| File "<stdin>", line 2, in <module>
360-
| ExceptionGroup: eg
373+
| File "<doctest default[0]>", line 2, in <module>
374+
| raise ExceptionGroup("eg",
375+
| [ValueError(1), TypeError(2), OSError(3), OSError(4)])
376+
| ExceptionGroup: eg (1 sub-exception)
361377
+-+---------------- 1 ----------------
362378
| ValueError: 1
363379
+------------------------------------
364380

365-
366-
Any remaining exceptions that were not handled by any :keyword:`!except*`
367-
clause are re-raised at the end, along with all exceptions that were
368-
raised from within the :keyword:`!except*` clauses. If this list contains
369-
more than one exception to reraise, they are combined into an exception
370-
group.
371-
372-
If the raised exception is not an exception group and its type matches
373-
one of the :keyword:`!except*` clauses, it is caught and wrapped by an
374-
exception group with an empty message string. ::
381+
If the exception raised from the :keyword:`try` block is not an exception group
382+
and its type matches one of the :keyword:`!except*` clauses, it is caught and
383+
wrapped by an exception group with an empty message string. This ensures that the
384+
type of the target ``e`` is consistently :exc:`BaseExceptionGroup`::
375385

376386
>>> try:
377387
... raise BlockingIOError
@@ -380,13 +390,7 @@ exception group with an empty message string. ::
380390
...
381391
ExceptionGroup('', (BlockingIOError()))
382392

383-
An :keyword:`!except*` clause must have a matching expression; it cannot be ``except*:``.
384-
Furthermore, this expression cannot contain exception group types, because that would
385-
have ambiguous semantics.
386-
387-
It is not possible to mix :keyword:`except` and :keyword:`!except*`
388-
in the same :keyword:`try`.
389-
The :keyword:`break`, :keyword:`continue`, and :keyword:`return` statements
393+
:keyword:`break`, :keyword:`continue` and :keyword:`return`
390394
cannot appear in an :keyword:`!except*` clause.
391395

392396

0 commit comments

Comments
 (0)