PEP 679: Allow parentheses in assert statements (GH-2220)
This commit is contained in:
parent
3d60b84e35
commit
7de72523c9
|
@ -0,0 +1,176 @@
|
|||
PEP: 679
|
||||
Title: Allow parentheses in assert statements
|
||||
Author: Pablo Galindo Salgado <pablogsal@python.org>
|
||||
Discussions-To: <email address or URL>
|
||||
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
|
||||
<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:
|
Loading…
Reference in New Issue