From 26b41f7fac292829291bc168728847e44f5f7dde Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Mon, 30 Sep 2024 23:11:11 +0100 Subject: [PATCH 1/5] PEP 790: Removing the parentheses requirement from except expressions --- peps/pep-0790.rst | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 peps/pep-0790.rst diff --git a/peps/pep-0790.rst b/peps/pep-0790.rst new file mode 100644 index 00000000000..c0abb7405f4 --- /dev/null +++ b/peps/pep-0790.rst @@ -0,0 +1,137 @@ +PEP: 790 +Title: Removing the parentheses requirement from ``except`` expressions +Author: Pablo Galindo , Brett Cannon +PEP-Delegate: TBD +Discussions-To: xxxx +Status: Draft +Type: Standards Track +Created: 30-Sep-2024 +Python-Version: 3.14 + + +Abstract +======== + +This PEP [1]_ proposes to allow unparenthesized ``except`` blocks in Python's exception handling syntax. Currently, when catching multiple exceptions, parentheses are required around the exception types. This was a Python 2 remnant. This PEP suggests allowing the omission of these parentheses, simplifying the syntax, making it more consistent with other parts of the syntax that make parentheses optional, and improving readability in certain cases. + + +Motivation +========== + +The current syntax for catching multiple exceptions requires parentheses in the ``except`` expression: :: + + try: + ... + except (ExceptionA, ExceptionB, ExceptionC): + ... + +While this syntax is clear and unambiguous, it can be seen as unnecessarily verbose in some cases, especially when catching a large number of exceptions. By allowing the omission of parentheses, we can simplify the syntax: :: + + try: + ... + except ExceptionA, ExceptionB, ExceptionC: + ... + +This change would bring the syntax more in line with other comma-separated lists in Python, such as function arguments, generator expressions inside of a function call, and tuple literals, where parentheses are optional. + + +Rationale +========= + +The decision to allow unparenthesized ``except`` blocks is based on the following considerations: + +1. Simplicity: Removing the requirement for parentheses simplifies the syntax, making it more consistent with other parts of the language. + +2. Readability: In cases where many exceptions are being caught, the removal of parentheses can improve readability by reducing visual clutter. + +3. Consistency: This change makes the ``except`` clause more consistent with other parts of Python where unambiguous, comma-separated lists don't require parentheses. + +Specification +============= + +The syntax for the except clause will be modified to allow an unparenthesized list of exception types. The grammar will be updated as follows: :: + + except_block[excepthandler_ty]: + | invalid_except_stmt_indent + | 'except' e=expressions t=['as' z=NAME { z }] ':' b=block { + _PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, 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=expressions t=['as' z=NAME { z }] ':' b=block { + _PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) } + | invalid_except_star_stmt + + +This allows both the current parenthesized syntax and the new unparenthesized syntax: :: + + try: + ... + except (ExceptionA, ExceptionB): # Still valid + ... + except ExceptionC, ExceptionD: # New syntax + ... + +The semantics of exception handling remain unchanged. The interpreter will catch any of the listed exceptions, regardless of whether they are parenthesized or not. + + +Backwards Compatibility +======================= + +This change is fully backwards compatible. All existing code using parenthesized ``except`` blocks will continue to work without modification. The new syntax is purely additive and does not break any existing code. + + +Security Implications +===================== + +There are no known security implications for this change. The semantics of exception handling remain the same, and this is purely a syntactic change. + + +How to Teach This +================= + +For new Python users, the unparenthesized syntax can be taught as the standard way to catch multiple exceptions: :: + + try: + risky_operation() + except ValueError, TypeError, OSError: + handle_errors() + +For experienced users, it can be introduced as a new, optional syntax that can be used interchangeably with the parenthesized version. Documentation should note that both forms are equivalent: :: + + # These are equivalent: + except (ValueError, TypeError): + ... + + except ValueError, TypeError: + ... + +It should be emphasized that this is purely a syntactic change and does not affect the behaviour of exception handling. + + +Reference Implementation +======================== + +A proof-of-concept implementation is available at https://github.com/pablogsal/cpython/commits/notuples/. This implementation modifies the Python parser to accept the new syntax and ensures that it behaves identically to the parenthesized version. + + +Rejected Ideas +============== + +1. Allowing mixed parenthesized and unparenthesized syntax: :: + + except (ValueError, TypeError), OSError: + +This was rejected due to the potential for confusion and to maintain a clear distinction between the two styles. + +Footnotes +========= + +.. [1] Originally named "Parenthetically Speaking, We Don't Need 'Em" + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive. From 5f9ec8ceb87293b75ddf896c6f38e58a553d600a Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Tue, 1 Oct 2024 00:25:41 +0100 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- peps/pep-0790.rst | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/peps/pep-0790.rst b/peps/pep-0790.rst index c0abb7405f4..73ed18ed17d 100644 --- a/peps/pep-0790.rst +++ b/peps/pep-0790.rst @@ -1,5 +1,5 @@ PEP: 790 -Title: Removing the parentheses requirement from ``except`` expressions +Title: Allow ``except`` expressions without parentheses Author: Pablo Galindo , Brett Cannon PEP-Delegate: TBD Discussions-To: xxxx @@ -18,14 +18,18 @@ This PEP [1]_ proposes to allow unparenthesized ``except`` blocks in Python's ex Motivation ========== -The current syntax for catching multiple exceptions requires parentheses in the ``except`` expression: :: +The current syntax for catching multiple exceptions requires parentheses in the ``except`` expression: + +.. code-block:: python try: ... except (ExceptionA, ExceptionB, ExceptionC): ... -While this syntax is clear and unambiguous, it can be seen as unnecessarily verbose in some cases, especially when catching a large number of exceptions. By allowing the omission of parentheses, we can simplify the syntax: :: +While this syntax is clear and unambiguous, it can be seen as unnecessarily verbose in some cases, especially when catching a large number of exceptions. By allowing the omission of parentheses, we can simplify the syntax: + +.. code-block:: python try: ... @@ -49,7 +53,9 @@ The decision to allow unparenthesized ``except`` blocks is based on the followin Specification ============= -The syntax for the except clause will be modified to allow an unparenthesized list of exception types. The grammar will be updated as follows: :: +The syntax for the except clause will be modified to allow an unparenthesized list of exception types. The grammar will be updated as follows: + +.. code-block:: peg except_block[excepthandler_ty]: | invalid_except_stmt_indent @@ -64,7 +70,9 @@ The syntax for the except clause will be modified to allow an unparenthesized li | invalid_except_star_stmt -This allows both the current parenthesized syntax and the new unparenthesized syntax: :: +This allows both the current parenthesized syntax and the new unparenthesized syntax: + +.. code-block:: python try: ... @@ -91,14 +99,18 @@ There are no known security implications for this change. The semantics of excep How to Teach This ================= -For new Python users, the unparenthesized syntax can be taught as the standard way to catch multiple exceptions: :: +For new Python users, the unparenthesized syntax can be taught as the standard way to catch multiple exceptions: + +.. code-block:: python try: risky_operation() except ValueError, TypeError, OSError: handle_errors() -For experienced users, it can be introduced as a new, optional syntax that can be used interchangeably with the parenthesized version. Documentation should note that both forms are equivalent: :: +For experienced users, it can be introduced as a new, optional syntax that can be used interchangeably with the parenthesized version. Documentation should note that both forms are equivalent: + +.. code-block:: python # These are equivalent: except (ValueError, TypeError): @@ -119,11 +131,16 @@ A proof-of-concept implementation is available at https://github.com/pablogsal/c Rejected Ideas ============== -1. Allowing mixed parenthesized and unparenthesized syntax: :: +1. Allowing mixed parenthesized and unparenthesized syntax: + + .. code-block:: python - except (ValueError, TypeError), OSError: + try: + ... + except (ValueError, TypeError), OSError: + ... -This was rejected due to the potential for confusion and to maintain a clear distinction between the two styles. + This was rejected due to the potential for confusion and to maintain a clear distinction between the two styles. Footnotes ========= From 3b2cbb5f6e32c4d27fb9ca422da51b70abef65ec Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Tue, 1 Oct 2024 19:06:21 +0100 Subject: [PATCH 3/5] Update peps/pep-0790.rst Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- peps/pep-0790.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0790.rst b/peps/pep-0790.rst index 73ed18ed17d..b1ca9ed65ee 100644 --- a/peps/pep-0790.rst +++ b/peps/pep-0790.rst @@ -1,4 +1,4 @@ -PEP: 790 +PEP: 758 Title: Allow ``except`` expressions without parentheses Author: Pablo Galindo , Brett Cannon PEP-Delegate: TBD From df0b18a88d8284a886051b7379f6b46500055a45 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 1 Oct 2024 20:29:58 +0100 Subject: [PATCH 4/5] Reformat doc, add codeowners, rename pep, address feedback Signed-off-by: Pablo Galindo --- .github/CODEOWNERS | 1 + peps/{pep-0790.rst => pep-0758.rst} | 91 +++++++++++++++++++++++------ 2 files changed, 73 insertions(+), 19 deletions(-) rename peps/{pep-0790.rst => pep-0758.rst} (53%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 36b5fbed6d0..2c99583b4cc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -638,6 +638,7 @@ peps/pep-0753.rst @warsaw # ... peps/pep-0756.rst @vstinner peps/pep-0757.rst @vstinner +peps/pep-0758.rst @pablogsal @brettcannon peps/pep-0789.rst @njsmith # ... peps/pep-0801.rst @warsaw diff --git a/peps/pep-0790.rst b/peps/pep-0758.rst similarity index 53% rename from peps/pep-0790.rst rename to peps/pep-0758.rst index b1ca9ed65ee..fe1aa055271 100644 --- a/peps/pep-0790.rst +++ b/peps/pep-0758.rst @@ -1,8 +1,7 @@ PEP: 758 -Title: Allow ``except`` expressions without parentheses +Title: Allow ``except`` and ``except*`` expressions without parentheses Author: Pablo Galindo , Brett Cannon PEP-Delegate: TBD -Discussions-To: xxxx Status: Draft Type: Standards Track Created: 30-Sep-2024 @@ -12,13 +11,20 @@ Python-Version: 3.14 Abstract ======== -This PEP [1]_ proposes to allow unparenthesized ``except`` blocks in Python's exception handling syntax. Currently, when catching multiple exceptions, parentheses are required around the exception types. This was a Python 2 remnant. This PEP suggests allowing the omission of these parentheses, simplifying the syntax, making it more consistent with other parts of the syntax that make parentheses optional, and improving readability in certain cases. +This PEP [1]_ proposes to allow unparenthesized ``except`` and ``except*`` +blocks in Python's exception handling syntax. Currently, when catching multiple +exceptions, parentheses are required around the exception types. This was a +Python 2 remnant. This PEP suggests allowing the omission of these parentheses, +simplifying the syntax, making it more consistent with other parts of the syntax +that make parentheses optional, and improving readability in certain cases. Motivation ========== -The current syntax for catching multiple exceptions requires parentheses in the ``except`` expression: +The current syntax for catching multiple exceptions requires parentheses in the +``except`` expression (equivalently for the ``except*`` expression). For +example: .. code-block:: python @@ -27,7 +33,9 @@ The current syntax for catching multiple exceptions requires parentheses in the except (ExceptionA, ExceptionB, ExceptionC): ... -While this syntax is clear and unambiguous, it can be seen as unnecessarily verbose in some cases, especially when catching a large number of exceptions. By allowing the omission of parentheses, we can simplify the syntax: +While this syntax is clear and unambiguous, it can be seen as unnecessarily +verbose in some cases, especially when catching a large number of exceptions. By +allowing the omission of parentheses, we can simplify the syntax: .. code-block:: python @@ -36,24 +44,49 @@ While this syntax is clear and unambiguous, it can be seen as unnecessarily verb except ExceptionA, ExceptionB, ExceptionC: ... -This change would bring the syntax more in line with other comma-separated lists in Python, such as function arguments, generator expressions inside of a function call, and tuple literals, where parentheses are optional. +This change would bring the syntax more in line with other comma-separated lists +in Python, such as function arguments, generator expressions inside of a +function call, and tuple literals, where parentheses are optional. + +The same change would apply to ``except*`` expressions. For example: + +.. code-block:: python + + try: + ... + except* ExceptionA, ExceptionB, ExceptionC: + ... + +Both forms will also allow the use of the ``as`` clause to capture the exception +instance as before: + +.. code-block:: python + + try: + ... + except ExceptionA, ExceptionB, ExceptionC as e: + ... Rationale ========= -The decision to allow unparenthesized ``except`` blocks is based on the following considerations: +The decision to allow unparenthesized ``except`` blocks is based on the +following considerations: -1. Simplicity: Removing the requirement for parentheses simplifies the syntax, making it more consistent with other parts of the language. +1. Simplicity: Removing the requirement for parentheses simplifies the syntax, +making it more consistent with other parts of the language. -2. Readability: In cases where many exceptions are being caught, the removal of parentheses can improve readability by reducing visual clutter. +2. Readability: In cases where many exceptions are being caught, the removal of +parentheses can improve readability by reducing visual clutter. 3. Consistency: This change makes the ``except`` clause more consistent with other parts of Python where unambiguous, comma-separated lists don't require parentheses. Specification ============= -The syntax for the except clause will be modified to allow an unparenthesized list of exception types. The grammar will be updated as follows: +The syntax for the except clause will be modified to allow an unparenthesized +list of exception types. The grammar will be updated as follows: .. code-block:: peg @@ -70,7 +103,8 @@ The syntax for the except clause will be modified to allow an unparenthesized li | invalid_except_star_stmt -This allows both the current parenthesized syntax and the new unparenthesized syntax: +This allows both the current parenthesized syntax and the new unparenthesized +syntax: .. code-block:: python @@ -81,25 +115,37 @@ This allows both the current parenthesized syntax and the new unparenthesized sy except ExceptionC, ExceptionD: # New syntax ... -The semantics of exception handling remain unchanged. The interpreter will catch any of the listed exceptions, regardless of whether they are parenthesized or not. +The semantics of exception handling remain unchanged. The interpreter will catch +any of the listed exceptions, regardless of whether they are parenthesized or +not. Backwards Compatibility ======================= -This change is fully backwards compatible. All existing code using parenthesized ``except`` blocks will continue to work without modification. The new syntax is purely additive and does not break any existing code. +This change is fully backwards compatible. All existing code using parenthesized +``except`` and ``except*`` blocks will continue to work without modification. +The new syntax is purely additive and does not break any existing code. + +It's worth noting that in Python 2 the unparenthesized syntax was allowed with +two eleements, but had different semantics, in which the first element of the +list was used as the exception type and the second element as the capture +variable. This change does not reintroduce the Python 2 semantics, and the +unparenthesized syntax will behave identically to the parenthesized version. Security Implications ===================== -There are no known security implications for this change. The semantics of exception handling remain the same, and this is purely a syntactic change. +There are no known security implications for this change. The semantics of +exception handling remain the same, and this is purely a syntactic change. How to Teach This ================= -For new Python users, the unparenthesized syntax can be taught as the standard way to catch multiple exceptions: +For new Python users, the unparenthesized syntax can be taught as the standard +way to catch multiple exceptions: .. code-block:: python @@ -108,7 +154,9 @@ For new Python users, the unparenthesized syntax can be taught as the standard w except ValueError, TypeError, OSError: handle_errors() -For experienced users, it can be introduced as a new, optional syntax that can be used interchangeably with the parenthesized version. Documentation should note that both forms are equivalent: +For experienced users, it can be introduced as a new, optional syntax that can +be used interchangeably with the parenthesized version. Documentation should +note that both forms are equivalent: .. code-block:: python @@ -119,13 +167,17 @@ For experienced users, it can be introduced as a new, optional syntax that can b except ValueError, TypeError: ... -It should be emphasized that this is purely a syntactic change and does not affect the behaviour of exception handling. +It should be emphasized that this is purely a syntactic change and does not +affect the behaviour of exception handling. Reference Implementation ======================== -A proof-of-concept implementation is available at https://github.com/pablogsal/cpython/commits/notuples/. This implementation modifies the Python parser to accept the new syntax and ensures that it behaves identically to the parenthesized version. +A proof-of-concept implementation is available at +https://github.com/pablogsal/cpython/commits/notuples/. This implementation +modifies the Python parser to accept the new syntax and ensures that it behaves +identically to the parenthesized version. Rejected Ideas @@ -140,7 +192,8 @@ Rejected Ideas except (ValueError, TypeError), OSError: ... - This was rejected due to the potential for confusion and to maintain a clear distinction between the two styles. + This was rejected due to the potential for confusion and to maintain a clear + distinction between the two styles. Footnotes ========= From e9c7c1a33f6cf1dd7d1f16d65da262e8d86fd0c6 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 1 Oct 2024 13:44:45 -0700 Subject: [PATCH 5/5] Update peps/pep-0758.rst Co-authored-by: Alex Waygood --- peps/pep-0758.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0758.rst b/peps/pep-0758.rst index fe1aa055271..df3efa0e0c9 100644 --- a/peps/pep-0758.rst +++ b/peps/pep-0758.rst @@ -128,7 +128,7 @@ This change is fully backwards compatible. All existing code using parenthesized The new syntax is purely additive and does not break any existing code. It's worth noting that in Python 2 the unparenthesized syntax was allowed with -two eleements, but had different semantics, in which the first element of the +two elements, but had different semantics, in which the first element of the list was used as the exception type and the second element as the capture variable. This change does not reintroduce the Python 2 semantics, and the unparenthesized syntax will behave identically to the parenthesized version.