-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
PEP 679: Allow parentheses in assert statements
- Loading branch information
Showing
1 changed file
with
175 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
PEP: 679 | ||
Title: Allow parentheses in assert statements | ||
Author: Pablo Galindo Salgado <[email protected]> | ||
Discussions-To: <email address or URL> | ||
Status: Draft | ||
Type: Standards Track | ||
Created: 07-Jan-2022 | ||
Python-Version: 3.11 | ||
|
||
|
||
Abstract | ||
======== | ||
|
||
This pep proposes to allow parentheses surrounding the two-subject form of | ||
assert statements. This will cause the interpreter to reinterpret what before | ||
would have been an assert with a two-element tuple that will always be True | ||
(``assert (expression, message)``) to an assert statement with a subject and a | ||
failure message, equivalent to the statement with the parentheses removed | ||
(``assert expression, message``). | ||
|
||
|
||
Motivation | ||
========== | ||
|
||
Is a common user mistake when using the form of the assert stamens that includes | ||
the error message to surround it by parentheses. Unfortunately, this mistake | ||
passes undetected as the assert will always pass due the the fact that is | ||
interpreted as an assert statement where the expression is a two-tuple, which | ||
always has truth-y value. | ||
|
||
The mistake most often happens when extending thing or description beyond a | ||
single line on assert statements as () are the natural way to do that and as it | ||
is with assert being a statement. | ||
|
||
This is so common that a ``SyntaxWarning`` is `now emitted by the compiler | ||
<https://bugs.python.org/issue35029>`_. | ||
|
||
Additionally, some other statements in the language allow parenthesized forms | ||
in one way or another like ``import`` statements (``from x import (a,b,c)``), ``del`` | ||
statements (``del (a,b,c)``). | ||
|
||
Allowing parentheses not only will remove the common mistake but also will allow | ||
users and auto-formatters to format long assert statements over multiple lines | ||
in what the authors of this document believe will be a more natural way. | ||
Although is possible to currently format long ``assert`` statements over | ||
multiple lines as:: | ||
|
||
assert ( | ||
very very long | ||
expression | ||
), ( | ||
"very very long " | ||
"message" | ||
) | ||
|
||
the authors of this document believe the parenthesized form is more clear and more consistent with | ||
the formatting of other grammar constructs:: | ||
|
||
assert ( | ||
very very long | ||
expression, | ||
|
||
"very very long " | ||
"message", | ||
) | ||
|
||
This change have been originally discussed and proposed in [bpo-46167]_. | ||
|
||
Rationale | ||
========= | ||
|
||
This change can be implemented in the parser or in the compiler. We have | ||
selected implementing this change in the parser because doing in in the compiler | ||
will require re-interpreting the AST of an assert statement with a two-tuple:: | ||
|
||
Module( | ||
body=[ | ||
Assert( | ||
test=Tuple( | ||
elts=[ | ||
Name(id='x', ctx=Load()), | ||
Name(id='y', ctx=Load())], | ||
ctx=Load()))], | ||
type_ignores=[]) | ||
|
||
as the AST of an assert statement with an expression and a message:: | ||
|
||
Module( | ||
body=[ | ||
Assert( | ||
test=Name(id='x', ctx=Load()), | ||
msg=Name(id='y', ctx=Load()))], | ||
type_ignores=[]) | ||
|
||
The problem with this approach is that the AST of the first form will | ||
technically be "incorrect" as we already have an specialized form for the AST of | ||
an assert statement with an expression and a message (the second one). This | ||
means that many tools that deal with ASTs will need to be aware of this change | ||
in semantics, which will be confusing as there is already a correct form that | ||
better expresses the new meaning. | ||
|
||
Specification | ||
============= | ||
|
||
This PEP proposes changing the grammar from the ``assert`` statement to: :: | ||
|
||
| 'assert' '(' expression ',' expression [','] ')' &(NEWLINE | ';') | ||
| 'assert' a=expression [',' expression ] | ||
|
||
Where the first line is the new form of the assert statement that allows | ||
parentheses. The lookahead is needed so statements like ``assert (a, b) <= c, | ||
"something"`` are still parsed correctly and to prevent the parser to eagerly | ||
capture the tuple as the full statement. | ||
|
||
Optionally, new "invalid" rule can be added to produce custom syntax errors to | ||
cover tuples with 0, 1, 3 or more elements. | ||
|
||
|
||
Backwards Compatibility | ||
======================= | ||
|
||
The change is not technically backwards compatible, as parsing ``assert (x,y)`` | ||
is currently interpreted as an assert statement with a 2-tuple as the subject, | ||
while after this change it will be interpreted as ``assert x,y``. | ||
|
||
On the other hand, this kind of assert statements are always true so they are | ||
effectively not doing anything in user code. The authors of this document think | ||
that this backwards incompatibility nature is beneficial, as it will highlight | ||
these cases in user code while before they will have passed unnoticed (assuming that | ||
these cases still exist is because users are ignoring syntax warnings). | ||
|
||
Security Implications | ||
===================== | ||
|
||
There are no security implications for this change. | ||
|
||
|
||
How to Teach This | ||
================= | ||
|
||
The new form of the ``assert`` statement will be documented as part of the language | ||
standard. | ||
|
||
When teaching the form with error message of the ``assert`` statement to users, | ||
now it can be noted that adding parentheses also work as expected, which allows to break | ||
the statement over multiple lines. | ||
|
||
|
||
Reference Implementation | ||
======================== | ||
|
||
A proposed draft PR with the change exist in [GH-30247]_. | ||
|
||
|
||
References | ||
========== | ||
|
||
.. [bpo-46167] https://bugs.python.org/issue46167 | ||
.. [GH-30247] https://github.com/python/cpython/pull/30247 | ||
Copyright | ||
========= | ||
|
||
This document is placed in the public domain or under the | ||
CC0-1.0-Universal license, whichever is more permissive. | ||
|
||
.. | ||
Local Variables: | ||
mode: indented-text | ||
indent-tabs-mode: nil | ||
sentence-end-double-space: t | ||
fill-column: 70 | ||
coding: utf-8 | ||
End: |