From b4b336b75af6877bdf236344286b85b0ec4a7714 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Sun, 9 Jan 2022 23:33:56 +0000 Subject: [PATCH] PEP 679: Allow parentheses in assert statements --- pep-0679.rst | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 pep-0679.rst diff --git a/pep-0679.rst b/pep-0679.rst new file mode 100644 index 00000000000..e81756a3289 --- /dev/null +++ b/pep-0679.rst @@ -0,0 +1,176 @@ +PEP: 679 +Title: Allow parentheses in assert statements +Author: Pablo Galindo Salgado +Discussions-To: +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +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 +`_. + +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: