gh-131831: Implement PEP 758 – Allow except and except* expressions without parentheses (#131833)
This commit is contained in:
parent
053c285f6b
commit
c2ac662f28
@ -232,6 +232,8 @@ Additional information on exceptions can be found in section :ref:`exceptions`,
|
|||||||
and information on using the :keyword:`raise` statement to generate exceptions
|
and information on using the :keyword:`raise` statement to generate exceptions
|
||||||
may be found in section :ref:`raise`.
|
may be found in section :ref:`raise`.
|
||||||
|
|
||||||
|
.. versionchanged:: next
|
||||||
|
Support for optionally dropping grouping parentheses when using multiple exception types. See :pep:`758`.
|
||||||
|
|
||||||
.. _except:
|
.. _except:
|
||||||
|
|
||||||
@ -247,7 +249,8 @@ An expression-less :keyword:`!except` clause, if present, must be last;
|
|||||||
it matches any exception.
|
it matches any exception.
|
||||||
|
|
||||||
For an :keyword:`!except` clause with an expression, the
|
For an :keyword:`!except` clause with an expression, the
|
||||||
expression must evaluate to an exception type or a tuple of exception types.
|
expression must evaluate to an exception type or a tuple of exception types. Parentheses
|
||||||
|
can be dropped if multiple exception types are provided and the ``as`` clause is not used.
|
||||||
The raised exception matches an :keyword:`!except` clause whose expression evaluates
|
The raised exception matches an :keyword:`!except` clause whose expression evaluates
|
||||||
to the class or a :term:`non-virtual base class <abstract base class>` of the exception object,
|
to the class or a :term:`non-virtual base class <abstract base class>` of the exception object,
|
||||||
or to a tuple that contains such a class.
|
or to a tuple that contains such a class.
|
||||||
|
@ -90,6 +90,33 @@ If you encounter :exc:`NameError`\s or pickling errors coming out of
|
|||||||
New features
|
New features
|
||||||
============
|
============
|
||||||
|
|
||||||
|
.. _whatsnew314-pep758:
|
||||||
|
|
||||||
|
PEP 758 – Allow except and except* expressions without parentheses
|
||||||
|
------------------------------------------------------------------
|
||||||
|
|
||||||
|
The :keyword:`except` and :keyword:`except* <except_star>` expressions now allow
|
||||||
|
parentheses to be omitted when there are multiple exception types and the ``as`` clause is not used.
|
||||||
|
For example the following expressions are now valid:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
try:
|
||||||
|
release_new_sleep_token_album()
|
||||||
|
except AlbumNotFound, SongsTooGoodToBeReleased:
|
||||||
|
print("Sorry, no new album this year.")
|
||||||
|
|
||||||
|
# The same applies to except* (for exception groups):
|
||||||
|
try:
|
||||||
|
release_new_sleep_token_album()
|
||||||
|
except* AlbumNotFound, SongsTooGoodToBeReleased:
|
||||||
|
print("Sorry, no new album this year.")
|
||||||
|
|
||||||
|
Check :pep:`758` for more details.
|
||||||
|
|
||||||
|
(Contributed by Pablo Galindo and Brett Cannon in :gh:`131831`.)
|
||||||
|
|
||||||
|
|
||||||
.. _whatsnew314-pep649:
|
.. _whatsnew314-pep649:
|
||||||
|
|
||||||
PEP 649: deferred evaluation of annotations
|
PEP 649: deferred evaluation of annotations
|
||||||
|
@ -435,14 +435,18 @@ try_stmt[stmt_ty]:
|
|||||||
|
|
||||||
except_block[excepthandler_ty]:
|
except_block[excepthandler_ty]:
|
||||||
| invalid_except_stmt_indent
|
| invalid_except_stmt_indent
|
||||||
| 'except' e=expression t=['as' z=NAME { z }] ':' b=block {
|
| 'except' e=expressions ':' b=block {
|
||||||
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
|
_PyAST_ExceptHandler(e, NULL, b, EXTRA) }
|
||||||
|
| 'except' e=expression 'as' t=NAME ':' b=block {
|
||||||
|
_PyAST_ExceptHandler(e, ((expr_ty) t)->v.Name.id, b, EXTRA) }
|
||||||
| 'except' ':' b=block { _PyAST_ExceptHandler(NULL, NULL, b, EXTRA) }
|
| 'except' ':' b=block { _PyAST_ExceptHandler(NULL, NULL, b, EXTRA) }
|
||||||
| invalid_except_stmt
|
| invalid_except_stmt
|
||||||
except_star_block[excepthandler_ty]:
|
except_star_block[excepthandler_ty]:
|
||||||
| invalid_except_star_stmt_indent
|
| invalid_except_star_stmt_indent
|
||||||
| 'except' '*' e=expression t=['as' z=NAME { z }] ':' b=block {
|
| 'except' '*' e=expressions ':' b=block {
|
||||||
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
|
_PyAST_ExceptHandler(e, NULL, b, EXTRA) }
|
||||||
|
| 'except' '*' e=expression 'as' t=NAME ':' b=block {
|
||||||
|
_PyAST_ExceptHandler(e, ((expr_ty) t)->v.Name.id, b, EXTRA) }
|
||||||
| invalid_except_star_stmt
|
| invalid_except_star_stmt
|
||||||
finally_block[asdl_stmt_seq*]:
|
finally_block[asdl_stmt_seq*]:
|
||||||
| invalid_finally_stmt
|
| invalid_finally_stmt
|
||||||
@ -1356,16 +1360,16 @@ invalid_try_stmt:
|
|||||||
| 'try' ':' block* except_star_block+ a='except' [expression ['as' NAME]] ':' {
|
| 'try' ':' block* except_star_block+ a='except' [expression ['as' NAME]] ':' {
|
||||||
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot have both 'except' and 'except*' on the same 'try'") }
|
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot have both 'except' and 'except*' on the same 'try'") }
|
||||||
invalid_except_stmt:
|
invalid_except_stmt:
|
||||||
| 'except' a=expression ',' expressions ['as' NAME ] ':' {
|
| 'except' a=expression ',' expressions 'as' NAME ':' {
|
||||||
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized") }
|
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized when using 'as'") }
|
||||||
| a='except' expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
|
| a='except' expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
|
||||||
| a='except' NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
|
| a='except' NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
|
||||||
| 'except' expression 'as' a=expression {
|
| 'except' expression 'as' a=expression {
|
||||||
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
|
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
|
||||||
a, "cannot use except statement with %s", _PyPegen_get_expr_name(a)) }
|
a, "cannot use except statement with %s", _PyPegen_get_expr_name(a)) }
|
||||||
invalid_except_star_stmt:
|
invalid_except_star_stmt:
|
||||||
| 'except' '*' a=expression ',' expressions ['as' NAME ] ':' {
|
| 'except' '*' a=expression ',' expressions 'as' NAME ':' {
|
||||||
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized") }
|
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized when using 'as'") }
|
||||||
| a='except' '*' expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
|
| a='except' '*' expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
|
||||||
| a='except' '*' (NEWLINE | ':') { RAISE_SYNTAX_ERROR("expected one or more exception types") }
|
| a='except' '*' (NEWLINE | ':') { RAISE_SYNTAX_ERROR("expected one or more exception types") }
|
||||||
| 'except' '*' expression 'as' a=expression {
|
| 'except' '*' expression 'as' a=expression {
|
||||||
|
@ -1375,6 +1375,8 @@ class GrammarTests(unittest.TestCase):
|
|||||||
try: 1/0
|
try: 1/0
|
||||||
except (EOFError, TypeError, ZeroDivisionError): pass
|
except (EOFError, TypeError, ZeroDivisionError): pass
|
||||||
try: 1/0
|
try: 1/0
|
||||||
|
except EOFError, TypeError, ZeroDivisionError: pass
|
||||||
|
try: 1/0
|
||||||
except (EOFError, TypeError, ZeroDivisionError) as msg: pass
|
except (EOFError, TypeError, ZeroDivisionError) as msg: pass
|
||||||
try: pass
|
try: pass
|
||||||
finally: pass
|
finally: pass
|
||||||
@ -1398,6 +1400,8 @@ class GrammarTests(unittest.TestCase):
|
|||||||
try: 1/0
|
try: 1/0
|
||||||
except* (EOFError, TypeError, ZeroDivisionError): pass
|
except* (EOFError, TypeError, ZeroDivisionError): pass
|
||||||
try: 1/0
|
try: 1/0
|
||||||
|
except* EOFError, TypeError, ZeroDivisionError: pass
|
||||||
|
try: 1/0
|
||||||
except* (EOFError, TypeError, ZeroDivisionError) as msg: pass
|
except* (EOFError, TypeError, ZeroDivisionError) as msg: pass
|
||||||
try: pass
|
try: pass
|
||||||
finally: pass
|
finally: pass
|
||||||
|
@ -1667,28 +1667,14 @@ Make sure that the old "raise X, Y[, Z]" form is gone:
|
|||||||
SyntaxError: invalid syntax
|
SyntaxError: invalid syntax
|
||||||
|
|
||||||
Check that an multiple exception types with missing parentheses
|
Check that an multiple exception types with missing parentheses
|
||||||
raise a custom exception
|
raise a custom exception only when using 'as'
|
||||||
|
|
||||||
>>> try:
|
|
||||||
... pass
|
|
||||||
... except A, B:
|
|
||||||
... pass
|
|
||||||
Traceback (most recent call last):
|
|
||||||
SyntaxError: multiple exception types must be parenthesized
|
|
||||||
|
|
||||||
>>> try:
|
|
||||||
... pass
|
|
||||||
... except A, B, C:
|
|
||||||
... pass
|
|
||||||
Traceback (most recent call last):
|
|
||||||
SyntaxError: multiple exception types must be parenthesized
|
|
||||||
|
|
||||||
>>> try:
|
>>> try:
|
||||||
... pass
|
... pass
|
||||||
... except A, B, C as blech:
|
... except A, B, C as blech:
|
||||||
... pass
|
... pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: multiple exception types must be parenthesized
|
SyntaxError: multiple exception types must be parenthesized when using 'as'
|
||||||
|
|
||||||
>>> try:
|
>>> try:
|
||||||
... pass
|
... pass
|
||||||
@ -1697,29 +1683,15 @@ raise a custom exception
|
|||||||
... finally:
|
... finally:
|
||||||
... pass
|
... pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: multiple exception types must be parenthesized
|
SyntaxError: multiple exception types must be parenthesized when using 'as'
|
||||||
|
|
||||||
|
|
||||||
>>> try:
|
|
||||||
... pass
|
|
||||||
... except* A, B:
|
|
||||||
... pass
|
|
||||||
Traceback (most recent call last):
|
|
||||||
SyntaxError: multiple exception types must be parenthesized
|
|
||||||
|
|
||||||
>>> try:
|
|
||||||
... pass
|
|
||||||
... except* A, B, C:
|
|
||||||
... pass
|
|
||||||
Traceback (most recent call last):
|
|
||||||
SyntaxError: multiple exception types must be parenthesized
|
|
||||||
|
|
||||||
>>> try:
|
>>> try:
|
||||||
... pass
|
... pass
|
||||||
... except* A, B, C as blech:
|
... except* A, B, C as blech:
|
||||||
... pass
|
... pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: multiple exception types must be parenthesized
|
SyntaxError: multiple exception types must be parenthesized when using 'as'
|
||||||
|
|
||||||
>>> try:
|
>>> try:
|
||||||
... pass
|
... pass
|
||||||
@ -1728,7 +1700,7 @@ raise a custom exception
|
|||||||
... finally:
|
... finally:
|
||||||
... pass
|
... pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: multiple exception types must be parenthesized
|
SyntaxError: multiple exception types must be parenthesized when using 'as'
|
||||||
|
|
||||||
Custom exception for 'except*' without an exception type
|
Custom exception for 'except*' without an exception type
|
||||||
|
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
Add support for optionally dropping grouping parentheses when using multiple
|
||||||
|
exception types as per :pep:`758`. Patch by Pablo Galindo
|
555
Parser/parser.c
generated
555
Parser/parser.c
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user