176 lines
5.6 KiB
ReStructuredText
176 lines
5.6 KiB
ReStructuredText
PEP: 679
|
|
Title: Allow parentheses in assert statements
|
|
Author: Pablo Galindo Salgado <pablogsal@python.org>
|
|
Discussions-To: https://discuss.python.org/t/pep-679-allow-parentheses-in-assert-statements/13003
|
|
Status: Draft
|
|
Type: Standards Track
|
|
Content-Type: text/x-rst
|
|
Created: 07-Jan-2022
|
|
Python-Version: 3.12
|
|
|
|
|
|
Abstract
|
|
========
|
|
|
|
This PEP proposes to allow parentheses surrounding the two-argument 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
|
|
==========
|
|
|
|
It is a common user mistake when using the form of the assert statement that includes
|
|
the error message to surround it with parentheses. Unfortunately, this mistake
|
|
passes undetected as the assert will always pass, because it 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 the test or description beyond a
|
|
single line, as parentheses are the natural way to do that.
|
|
|
|
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)``) and
|
|
``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 has 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 it 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 a specialized form for the AST of
|
|
an assert statement with a test 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 of 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, assert statements of this kind always pass, 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 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:
|