Skip to content

Commit c03714f

Browse files
committed
gh-131831: Implement PEP 758 – Allow except and except* expressions without parentheses
Signed-off-by: Pablo Galindo <[email protected]>
1 parent 56d0f9a commit c03714f

File tree

6 files changed

+363
-258
lines changed

6 files changed

+363
-258
lines changed

Doc/reference/compound_stmts.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ Additional information on exceptions can be found in section :ref:`exceptions`,
232232
and information on using the :keyword:`raise` statement to generate exceptions
233233
may be found in section :ref:`raise`.
234234

235+
.. versionchanged:: 3.13
236+
Support for optionally dropping grouping parentheses when using multiple exception types. See :pep:`758`.
235237

236238
.. _except:
237239

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

249251
For an :keyword:`!except` clause with an expression, the
250-
expression must evaluate to an exception type or a tuple of exception types.
252+
expression must evaluate to an exception type or a tuple of exception types. Parentheses
253+
can be dropped if multiple exception types are provided and the ``as`` clause is not used.
251254
The raised exception matches an :keyword:`!except` clause whose expression evaluates
252255
to the class or a :term:`non-virtual base class <abstract base class>` of the exception object,
253256
or to a tuple that contains such a class.

Doc/whatsnew/3.14.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,29 @@ If you encounter :exc:`NameError`\s or pickling errors coming out of
9090
New features
9191
============
9292

93+
PEP 758 – Allow except and except* expressions without parentheses
94+
------------------------------------------------------------------
95+
96+
The :keyword:`except` and :keyword:`except*` expressions now allow
97+
parentheses to be omitted when there is only one exception type.
98+
For example the following expressions are now valid:
99+
100+
.. code-block:: python
101+
102+
try:
103+
release_new_sleep_token_album()
104+
except AlbumNotFound, SongsTooGoodToBeReleased:
105+
print("Sorry, no new album this year.")
106+
107+
try:
108+
release_new_sleep_token_album()
109+
except* AlbumNotFound, SongsTooGoodToBeReleased:
110+
print("Sorry, no new album this year.")
111+
112+
Check :pep:`758` for more details.
113+
114+
(Contributed by Pablo Galindo and Brett Cannin in :issue:`131831`.)
115+
93116
.. _whatsnew314-pep649:
94117

95118
PEP 649: deferred evaluation of annotations

Grammar/python.gram

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -435,14 +435,18 @@ try_stmt[stmt_ty]:
435435

436436
except_block[excepthandler_ty]:
437437
| invalid_except_stmt_indent
438-
| 'except' e=expression t=['as' z=NAME { z }] ':' b=block {
439-
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
438+
| 'except' e=expressions ':' b=block {
439+
_PyAST_ExceptHandler(e, NULL, b, EXTRA) }
440+
| 'except' e=expression 'as' t=NAME ':' b=block {
441+
_PyAST_ExceptHandler(e, ((expr_ty) t)->v.Name.id, b, EXTRA) }
440442
| 'except' ':' b=block { _PyAST_ExceptHandler(NULL, NULL, b, EXTRA) }
441443
| invalid_except_stmt
442444
except_star_block[excepthandler_ty]:
443445
| invalid_except_star_stmt_indent
444-
| 'except' '*' e=expression t=['as' z=NAME { z }] ':' b=block {
445-
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
446+
| 'except' '*' e=expressions ':' b=block {
447+
_PyAST_ExceptHandler(e, NULL, b, EXTRA) }
448+
| 'except' '*' e=expression 'as' t=NAME ':' b=block {
449+
_PyAST_ExceptHandler(e, ((expr_ty) t)->v.Name.id, b, EXTRA) }
446450
| invalid_except_star_stmt
447451
finally_block[asdl_stmt_seq*]:
448452
| invalid_finally_stmt
@@ -1356,15 +1360,15 @@ invalid_try_stmt:
13561360
| 'try' ':' block* except_star_block+ a='except' [expression ['as' NAME]] ':' {
13571361
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot have both 'except' and 'except*' on the same 'try'") }
13581362
invalid_except_stmt:
1359-
| 'except' a=expression ',' expressions ['as' NAME ] ':' {
1363+
| 'except' a=expression ',' expressions 'as' NAME ':' {
13601364
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized") }
13611365
| a='except' expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
13621366
| a='except' NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
13631367
| 'except' expression 'as' a=expression {
13641368
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
13651369
a, "cannot use except statement with %s", _PyPegen_get_expr_name(a)) }
13661370
invalid_except_star_stmt:
1367-
| 'except' '*' a=expression ',' expressions ['as' NAME ] ':' {
1371+
| 'except' '*' a=expression ',' expressions 'as' NAME ':' {
13681372
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized") }
13691373
| a='except' '*' expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
13701374
| a='except' '*' (NEWLINE | ':') { RAISE_SYNTAX_ERROR("expected one or more exception types") }

Lib/test/test_grammar.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,8 @@ def test_try(self):
14531453
try: 1/0
14541454
except (EOFError, TypeError, ZeroDivisionError): pass
14551455
try: 1/0
1456+
except EOFError, TypeError, ZeroDivisionError: pass
1457+
try: 1/0
14561458
except (EOFError, TypeError, ZeroDivisionError) as msg: pass
14571459
try: pass
14581460
finally: pass
@@ -1476,6 +1478,8 @@ def test_try_star(self):
14761478
try: 1/0
14771479
except* (EOFError, TypeError, ZeroDivisionError): pass
14781480
try: 1/0
1481+
except* EOFError, TypeError, ZeroDivisionError: pass
1482+
try: 1/0
14791483
except* (EOFError, TypeError, ZeroDivisionError) as msg: pass
14801484
try: pass
14811485
finally: pass

Lib/test/test_syntax.py

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,21 +1667,7 @@
16671667
SyntaxError: invalid syntax
16681668
16691669
Check that an multiple exception types with missing parentheses
1670-
raise a custom exception
1671-
1672-
>>> try:
1673-
... pass
1674-
... except A, B:
1675-
... pass
1676-
Traceback (most recent call last):
1677-
SyntaxError: multiple exception types must be parenthesized
1678-
1679-
>>> try:
1680-
... pass
1681-
... except A, B, C:
1682-
... pass
1683-
Traceback (most recent call last):
1684-
SyntaxError: multiple exception types must be parenthesized
1670+
raise a custom exception only when using 'as'
16851671
16861672
>>> try:
16871673
... pass
@@ -1700,20 +1686,6 @@
17001686
SyntaxError: multiple exception types must be parenthesized
17011687
17021688
1703-
>>> try:
1704-
... pass
1705-
... except* A, B:
1706-
... pass
1707-
Traceback (most recent call last):
1708-
SyntaxError: multiple exception types must be parenthesized
1709-
1710-
>>> try:
1711-
... pass
1712-
... except* A, B, C:
1713-
... pass
1714-
Traceback (most recent call last):
1715-
SyntaxError: multiple exception types must be parenthesized
1716-
17171689
>>> try:
17181690
... pass
17191691
... except* A, B, C as blech:

0 commit comments

Comments
 (0)