Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Doc/reference/compound_stmts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
may be found in section :ref:`raise`.

.. versionchanged:: next
Support for optionally dropping grouping parentheses when using multiple exception types. See :pep:`758`.

.. _except:

Expand All @@ -247,7 +249,8 @@ An expression-less :keyword:`!except` clause, if present, must be last;
it matches any exception.

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
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.
Expand Down
26 changes: 26 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,32 @@ If you encounter :exc:`NameError`\s or pickling errors coming out of
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.")

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:

PEP 649: deferred evaluation of annotations
Expand Down
16 changes: 10 additions & 6 deletions Grammar/python.gram
Original file line number Diff line number Diff line change
Expand Up @@ -435,14 +435,18 @@ try_stmt[stmt_ty]:

except_block[excepthandler_ty]:
| invalid_except_stmt_indent
| 'except' e=expression t=['as' z=NAME { z }] ':' b=block {
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
| 'except' e=expressions ':' b=block {
_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) }
| invalid_except_stmt
except_star_block[excepthandler_ty]:
| invalid_except_star_stmt_indent
| 'except' '*' e=expression t=['as' z=NAME { z }] ':' b=block {
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
| 'except' '*' e=expressions ':' b=block {
_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
finally_block[asdl_stmt_seq*]:
| invalid_finally_stmt
Expand Down Expand Up @@ -1356,15 +1360,15 @@ invalid_try_stmt:
| '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'") }
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") }
| a='except' expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
| a='except' NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
| 'except' expression 'as' a=expression {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
a, "cannot use except statement with %s", _PyPegen_get_expr_name(a)) }
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") }
| a='except' '*' expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
| a='except' '*' (NEWLINE | ':') { RAISE_SYNTAX_ERROR("expected one or more exception types") }
Expand Down
4 changes: 4 additions & 0 deletions Lib/test/test_grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -1453,6 +1453,8 @@ def test_try(self):
try: 1/0
except (EOFError, TypeError, ZeroDivisionError): pass
try: 1/0
except EOFError, TypeError, ZeroDivisionError: pass
try: 1/0
except (EOFError, TypeError, ZeroDivisionError) as msg: pass
try: pass
finally: pass
Expand All @@ -1476,6 +1478,8 @@ def test_try_star(self):
try: 1/0
except* (EOFError, TypeError, ZeroDivisionError): pass
try: 1/0
except* EOFError, TypeError, ZeroDivisionError: pass
try: 1/0
except* (EOFError, TypeError, ZeroDivisionError) as msg: pass
try: pass
finally: pass
Expand Down
30 changes: 1 addition & 29 deletions Lib/test/test_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -1667,21 +1667,7 @@
SyntaxError: invalid syntax

Check that an multiple exception types with missing parentheses
raise a custom exception

>>> 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
raise a custom exception only when using 'as'

>>> try:
... pass
Expand All @@ -1700,20 +1686,6 @@
SyntaxError: multiple exception types must be parenthesized


>>> 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:
... pass
... except* A, B, C as blech:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add support for optionally dropping grouping parentheses when using multiple
exception types as per :pep:`758`. Patch by Pablo Galindo
Loading
Loading