PEP-654: except *T --> except* T (#2091)

This commit is contained in:
Irit Katriel 2021-10-06 18:50:57 +01:00 committed by GitHub
parent 389e8219cb
commit 957b7eb9b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 34 additions and 34 deletions

View File

@ -532,11 +532,11 @@ exceptions can be handled by each ``except*`` clause:
try:
...
except *SpamError:
except* SpamError:
...
except *FooError as e:
except* FooError as e:
...
except *(BarError, BazError) as e:
except* (BarError, BazError) as e:
...
In a traditional ``try-except`` statement there is only one exception to handle,
@ -572,7 +572,7 @@ Exceptions are matched using a subclass check. For example:
try:
low_level_os_operation()
except *OSError as eg:
except* OSError as eg:
for e in eg.exceptions:
print(type(e).__name__)
@ -593,9 +593,9 @@ The order of ``except*`` clauses is significant just like with the regular
>>> try:
... raise ExceptionGroup("problem", [BlockingIOError()])
... except *OSError as e: # Would catch the error
... except* OSError as e: # Would catch the error
... print(repr(e))
... except *BlockingIOError: # Would never run
... except* BlockingIOError: # Would never run
... print('never')
...
ExceptionGroup('problem', [BlockingIOError()])
@ -619,9 +619,9 @@ recursively, using the ``split()`` method:
... [TypeError('c'), KeyError('d')])
... ]
... )
... except *TypeError as e1:
... except* TypeError as e1:
... print(f'e1 = {e1!r}')
... except *Exception as e2:
... except* Exception as e2:
... print(f'e2 = {e2!r}')
...
e1 = ExceptionGroup('eg', [TypeError('b'), ExceptionGroup('nested', [TypeError('c')])])
@ -644,9 +644,9 @@ clauses, the remaining part of the group is propagated on:
... TypeError('c'), KeyError('e')
... ]
... )
... except *ValueError as e:
... except* ValueError as e:
... print(f'got some ValueErrors: {e!r}')
... except *TypeError as e:
... except* TypeError as e:
... print(f'got some TypeErrors: {e!r}')
... except ExceptionGroup as e:
... print(f'propagated: {e!r}')
@ -670,7 +670,7 @@ message string. This is to make the type of ``e`` consistent and statically know
>>> try:
... raise BlockingIOError
... except *OSError as e:
... except* OSError as e:
... print(repr(e))
...
ExceptionGroup('', [BlockingIOError()])
@ -683,7 +683,7 @@ naked form:
>>> try:
... try:
... raise ValueError(12)
... except *TypeError as e:
... except* TypeError as e:
... print('never')
... except ValueError as e:
... print(f'caught ValueError: {e!r}')
@ -755,10 +755,10 @@ the original ``ExceptionGroup``:
... [OSError(4), TypeError(5), ValueError(6)])
... ]
... )
... except *ValueError as e:
... except* ValueError as e:
... print(f'*ValueError: {e!r}')
... raise
... except *OSError as e:
... except* OSError as e:
... print(f'*OSError: {e!r}')
... except ExceptionGroup as e:
... print(repr(e))
@ -793,10 +793,10 @@ merged with the unhandled ``TypeErrors``.
... [OSError(4), TypeError(5), ValueError(6)])
... ]
... )
... except *ValueError as e:
... except* ValueError as e:
... print(f'*ValueError: {e!r}')
... raise e
... except *OSError as e:
... except* OSError as e:
... print(f'*OSError: {e!r}')
... raise
...
@ -850,7 +850,7 @@ it into the new ``ExceptionGroup``.
>>> try:
... raise ExceptionGroup("one", [ValueError('a'), TypeError('b')])
... except *ValueError:
... except* ValueError:
... raise ExceptionGroup("two", [KeyError('x'), KeyError('y')])
...
| ExceptionGroup
@ -897,7 +897,7 @@ chaining:
>>> try:
... raise TypeError('bad type')
... except *TypeError as e:
... except* TypeError as e:
... raise ValueError('bad value') from e
...
| ExceptionGroup
@ -927,9 +927,9 @@ other clauses from the same ``try`` statement:
>>> try:
... raise TypeError(1)
... except *TypeError:
... except* TypeError:
... raise ValueError(2) from None # <- not caught in the next clause
... except *ValueError:
... except* ValueError:
... print('never')
...
| ExceptionGroup
@ -952,7 +952,7 @@ direct child of the new exception group created for that:
>>> try:
... raise ExceptionGroup("eg", [ValueError('a')])
... except *ValueError:
... except* ValueError:
... raise KeyError('x')
...
| ExceptionGroup
@ -975,7 +975,7 @@ direct child of the new exception group created for that:
>>>
>>> try:
... raise ExceptionGroup("eg", [ValueError('a'), TypeError('b')])
... except *ValueError:
... except* ValueError:
... raise KeyError('x')
...
| ExceptionGroup
@ -1013,7 +1013,7 @@ OS errors, while letting all other exceptions propagate.
try:
low_level_os_operation()
except *OSError as errors:
except* OSError as errors:
raise errors.subgroup(lambda e: e.errno != errno.EPIPE) from None
@ -1031,7 +1031,7 @@ exception group. Any modifications to ``e`` will likely be lost:
>>> eg.foo = 'foo'
>>> try:
... raise eg
... except *TypeError as e:
... except* TypeError as e:
... e.foo = 'bar'
... # ^----------- ``e`` is an ephemeral object that might get
>>> # destroyed after the ``except*`` clause.
@ -1052,7 +1052,7 @@ It is not possible to use both traditional ``except`` blocks and the new
...
except ValueError:
pass
except *CancelledError: # <- SyntaxError:
except* CancelledError: # <- SyntaxError:
pass # combining ``except`` and ``except*``
# is prohibited
@ -1069,12 +1069,12 @@ ambiguous:
try:
...
except *ExceptionGroup: # <- Runtime error
except* ExceptionGroup: # <- Runtime error
pass
try:
...
except *(TypeError, ExceptionGroup): # <- Runtime error
except* (TypeError, ExceptionGroup): # <- Runtime error
pass
@ -1121,7 +1121,7 @@ Once programs begin to use these features, there will be migration issues to
consider:
* An ``except T:`` clause that wraps code which is now potentially raising
an exception group may need to become ``except *T:``, and its body may
an exception group may need to become ``except* T:``, and its body may
need to be updated. This means that raising an exception group is an
API-breaking change and will likely be done in new APIs rather than
added to existing ones.
@ -1308,7 +1308,7 @@ It is unlikely that asyncio users would want to do something like this:
try:
async with asyncio.TaskGroup() as g:
g.create_task(task1); g.create_task(task2)
except *KeyError:
except* KeyError:
# handling KeyError here is meaningless, there's
# no context to do anything with it but to log it.
@ -1326,7 +1326,7 @@ exceptions in it.
Not Matching Naked Exceptions in ``except*``
--------------------------------------------
We considered the option of making ``except *T`` match only exception groups
We considered the option of making ``except* T`` match only exception groups
that contain ``Ts``, but not naked ``Ts``. To see why we thought this would
not be a desirable feature, return to the distinction in the previous paragraph
between operation errors and control flow exceptions. If we don't know whether
@ -1352,7 +1352,7 @@ write a separate code block to handle each case:
...
except SomeError:
# handle the naked exception
except *SomeError:
except* SomeError:
# handle the exception group
@ -1361,7 +1361,7 @@ Allow mixing ``except:`` and ``except*:`` in the same ``try``
This option was rejected because it adds complexity without adding useful
semantics. Presumably the intention would be that an ``except T:`` block handles
only naked exceptions of type ``T``, while ``except *T:`` handles ``T`` in
only naked exceptions of type ``T``, while ``except* T:`` handles ``T`` in
exception groups. We already discussed above why this is unlikely
to be useful in practice, and if it is needed then the nested ``try-except``
block can be used instead to achieve the same result.
@ -1379,7 +1379,7 @@ specified in the same place where we state ``T``.
Programming Without 'except \*'
===============================
Consider the following simple example of the ``except *`` syntax (pretending
Consider the following simple example of the ``except*`` syntax (pretending
Trio natively supported this proposal):
.. code-block::
@ -1389,7 +1389,7 @@ Trio natively supported this proposal):
# Make two concurrent calls to child()
nursery.start_soon(child)
nursery.start_soon(child)
except *ValueError:
except* ValueError:
pass
Here is how this code would look in Python 3.9: