Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c2ac662

Browse filesBrowse files
authored
gh-131831: Implement PEP 758 – Allow except and except* expressions without parentheses (#131833)
1 parent 053c285 commit c2ac662
Copy full SHA for c2ac662

File tree

7 files changed

+377
-266
lines changed
Filter options

7 files changed

+377
-266
lines changed

‎Doc/reference/compound_stmts.rst

Copy file name to clipboardExpand all lines: Doc/reference/compound_stmts.rst
+4-1Lines 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:: next
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

Copy file name to clipboardExpand all lines: Doc/whatsnew/3.14.rst
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,33 @@ If you encounter :exc:`NameError`\s or pickling errors coming out of
9090
New features
9191
============
9292

93+
.. _whatsnew314-pep758:
94+
95+
PEP 758 – Allow except and except* expressions without parentheses
96+
------------------------------------------------------------------
97+
98+
The :keyword:`except` and :keyword:`except* <except_star>` expressions now allow
99+
parentheses to be omitted when there are multiple exception types and the ``as`` clause is not used.
100+
For example the following expressions are now valid:
101+
102+
.. code-block:: python
103+
104+
try:
105+
release_new_sleep_token_album()
106+
except AlbumNotFound, SongsTooGoodToBeReleased:
107+
print("Sorry, no new album this year.")
108+
109+
# The same applies to except* (for exception groups):
110+
try:
111+
release_new_sleep_token_album()
112+
except* AlbumNotFound, SongsTooGoodToBeReleased:
113+
print("Sorry, no new album this year.")
114+
115+
Check :pep:`758` for more details.
116+
117+
(Contributed by Pablo Galindo and Brett Cannon in :gh:`131831`.)
118+
119+
93120
.. _whatsnew314-pep649:
94121

95122
PEP 649: deferred evaluation of annotations

‎Grammar/python.gram

Copy file name to clipboardExpand all lines: Grammar/python.gram
+12-8Lines changed: 12 additions & 8 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,16 +1360,16 @@ 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 ] ':' {
1360-
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized") }
1363+
| 'except' a=expression ',' expressions 'as' NAME ':' {
1364+
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized when using 'as'") }
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 ] ':' {
1368-
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized") }
1371+
| 'except' '*' a=expression ',' expressions 'as' NAME ':' {
1372+
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized when using 'as'") }
13691373
| a='except' '*' expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
13701374
| a='except' '*' (NEWLINE | ':') { RAISE_SYNTAX_ERROR("expected one or more exception types") }
13711375
| 'except' '*' expression 'as' a=expression {

‎Lib/test/test_grammar.py

Copy file name to clipboardExpand all lines: Lib/test/test_grammar.py
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,8 @@ def test_try(self):
13751375
try: 1/0
13761376
except (EOFError, TypeError, ZeroDivisionError): pass
13771377
try: 1/0
1378+
except EOFError, TypeError, ZeroDivisionError: pass
1379+
try: 1/0
13781380
except (EOFError, TypeError, ZeroDivisionError) as msg: pass
13791381
try: pass
13801382
finally: pass
@@ -1398,6 +1400,8 @@ def test_try_star(self):
13981400
try: 1/0
13991401
except* (EOFError, TypeError, ZeroDivisionError): pass
14001402
try: 1/0
1403+
except* EOFError, TypeError, ZeroDivisionError: pass
1404+
try: 1/0
14011405
except* (EOFError, TypeError, ZeroDivisionError) as msg: pass
14021406
try: pass
14031407
finally: pass

‎Lib/test/test_syntax.py

Copy file name to clipboardExpand all lines: Lib/test/test_syntax.py
+5-33Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,28 +1667,14 @@
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
16881674
... except A, B, C as blech:
16891675
... pass
16901676
Traceback (most recent call last):
1691-
SyntaxError: multiple exception types must be parenthesized
1677+
SyntaxError: multiple exception types must be parenthesized when using 'as'
16921678
16931679
>>> try:
16941680
... pass
@@ -1697,29 +1683,15 @@
16971683
... finally:
16981684
... pass
16991685
Traceback (most recent call last):
1700-
SyntaxError: multiple exception types must be parenthesized
1686+
SyntaxError: multiple exception types must be parenthesized when using 'as'
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:
17201692
... pass
17211693
Traceback (most recent call last):
1722-
SyntaxError: multiple exception types must be parenthesized
1694+
SyntaxError: multiple exception types must be parenthesized when using 'as'
17231695
17241696
>>> try:
17251697
... pass
@@ -1728,7 +1700,7 @@
17281700
... finally:
17291701
... pass
17301702
Traceback (most recent call last):
1731-
SyntaxError: multiple exception types must be parenthesized
1703+
SyntaxError: multiple exception types must be parenthesized when using 'as'
17321704
17331705
Custom exception for 'except*' without an exception type
17341706
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add support for optionally dropping grouping parentheses when using multiple
2+
exception types as per :pep:`758`. Patch by Pablo Galindo

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.