Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 679 – New assert statement syntax with parentheses

Author:
Pablo Galindo Salgado <pablogsal at python.org>,Stan Ulbrych <stanulbrych at gmail.com>
Discussions-To:
Discourse thread
Status:
Rejected
Type:
Standards Track
Created:
07-Jan-2022
Python-Version:
3.15
Post-History:
08-Sep-2025,10-Jan-2022
Resolution:
24-Oct-2025

Table of Contents

Abstract

This PEP proposes allowing parentheses in the two-argument form ofassert.The interpreter will reinterpretassert(expr,msg) asassertexpr,msg,eliminating the common pitfall where such code was previously treated asasserting a two-elementtuple, which is always truthy.

Motivation

It is a common user mistake when using the form of theassertstatement that includes the error message to surround it with parentheses[1][2].This is because many beginners assumeassert is a function.The prominentunittest methods, particularlyassertTrue(),also require parentheses around the assertion and message.

Unfortunately, this mistake passes undetected as theassert will always pass[6], because it is interpreted as anassert statement where theexpression is a two-tuple, which always has truth-y value.The mistake also often occurs when extending the test or description beyond asingle line, as parentheses are a natural way to do that.

This is so common that aSyntaxWarning isemitted by the compiler since 3.10 and severalcode linters[3][4].

Additionally, some other statements in the language allow parenthesized formsin one way or another, for example,import statements(fromximport(a,b,c)) ordel statements (del(a,b,c)).

Allowing parentheses not only will remove the pitfall but also will allowusers and auto-formatters to format long assert statements over multiple linesin what the authors of this document believe will be a more natural way.Although it is possible to currently format longassert statementsover multiple lines with backslashes (as is recommended byPEP 8) or parentheses and a comma:

assert(veryverylongtest),("very very long ""error message")

the authors of this document believe the proposed parenthesized form is moreclear and intuitive, along with being more consistent with the formatting ofother grammar constructs:

assert(veryverylongtest,"very very long ""message")

Rationale

Due to backwards compatibility concerns (see section below), to inform usersof the new change of how what was previously a two element tuple is parsed,aSyntaxWarning with a message like"newassertionsyntax,willassertfirstelementoftuple"will be raised till Python 3.17. For example, when using the new syntax:

>>>assert('Petr'=='Pablo',"That doesn't look right!")<python-input-0>:0: SyntaxWarning: new assertion syntax, will assert first element of tupleTraceback (most recent call last):  File"<python-input-0>", line1, in<module>assert('Petr'=='Pablo',"That doesn't look right!")^^^^^^^^^^^^^^^^^AssertionError:That doesn't look right!

Note that improving syntax warnings in generalis out of the scope of this PEP.

Specification

The formal grammar of theassert statement will change to[8]:

|'assert''('expression','expression[',']')'&(NEWLINE|';')|'assert'a=expression[','expression]

Where the first line is the new form of the assert statement that allowsparentheses and will raise aSyntaxWarning till 3.17.The lookahead is needed to prevent the parser from eagerly capturing thetuple as the full statement, so statements likeassert(a,b)<=c,"something"are still parsed correctly.

Implementation Notes

This change can be implemented in the parser or in the compiler.The specification that aSyntaxWarning be raised informing usersof the new syntax complicates the implementation, as warningsshould be raised during compilation.

The authors believe that an ideal implementation would be in the parser[8],resulting inassert(x,y) having the same AST asassertx,y.This necessitates a two-step implementation plan, with a necessary temporarycompromise.

Implementing in the parser

It is not possible to have a pure parser implementation with the warningspecification.(Note that, without the warning specification the pure parser implementation isa small grammar change[5]).To raise the warning, the compiler mustbe aware of the new syntax, this means that an optional flag would be necessaryas otherwise the information is lost during parsing.As such, the AST of anassert with parentheses would look like so,with aparen_syntax=1 flag:

>>>print(ast.dump(ast.parse('assert(True, "Error message")'),indent=4))Module(    body=[        Assert(            test=Constant(value=True),            msg=Constant(value='Error message'),            paren_syntax=1)])

Implementing in the compiler

The new syntax can be implemented in the compiler by special casing tuplesof length two. This however, will have the side-effect of not modifying theAST whatsoever during the transition period while theSyntaxWarningis being emitted.

Once theSyntaxWarning is removed, the implementationcan be moved to the parser level, where the parenthesized form would beparsed directly into the same AST structure asassertexpression,message.This approach is more backwards-compatible, as the many tools that deal withASTs will have more time to adapt.

Backwards Compatibility

The change is not technically backwards compatible. Whether implemented initiallyin the parser or the compiler,assert(x,y),which is currently interpreted as an assert statement with a 2-tuple as thesubject and is always truth-y, will be interpreted asassertx,y.

On the other hand, assert statements of this kind always pass, so they areeffectively not doing anything in user code. The authors of this document thinkthat this backwards incompatibility nature is beneficial, as it will highlightthese cases in user code while before they will have passed unnoticed. This casehas already raised aSyntaxWarning since Python 3.10, so there has beena deprecation period of over 5 years.The continued raising of aSyntaxWarning should mitigate surprises.

The change will also result in changes to the AST ofassert(x,y),which currently is:

Module(    body=[        Assert(            test=Tuple(                elts=[                    Name(id='x', ctx=Load()),                    Name(id='y', ctx=Load())],                ctx=Load()))],    type_ignores=[])

the final implementation, in Python 3.18, will result in the following AST:

Module(    body=[        Assert(            test=Name(id='x', ctx=Load()),            msg=Name(id='y', ctx=Load()))],    type_ignores=[])

The problem with this is that the AST of the first form willtechnically be “incorrect” as we already have a specialized form for the AST ofan assert statement with a test and a message (the second one).Implementing initially in the compiler will delay this change, alleviatingbackwards compatibility concerns, as tools will have more time to adjust.

How to Teach This

The new form of theassert statement will be documented as part of the languagestandard.

When teaching the form with error message of theassert statement to users,now it can be noted that adding parentheses also work as expected, which allowsto break the statement over multiple lines.

Reference Implementation

A reference implementation in the parser can be found in thisbranchand reference implementation in the compiler can be found in thisbranch.

Rejected Ideas

Adding a syntax with a keyword

Everywhere else in Python syntax, the comma separates variable-length “lists”of homogeneous elements, like the the items of atuple orlist,parameters/arguments of functions, or import targets.After Python 3.0 introducedexcept...as,theassert statement remains as the only exception to this convention.

It’s possible that user confusion stems, at least partly, from an expectationthat comma-separated items are equivalent.Enclosing anassert statement’s expression and message inparentheses would visually bind them together even further.Makingassert look more similar to a function call encourages a wrongmentality.

As a possible solution, it was proposed[7] to replace the comma witha keyword, and the form would allow parentheses, for example:

assertconditionelse"message"assert(conditionelse"message")

The comma could then be slowly and carefully deprecated, starting withthe case where they appear in parentheses, which already raises aSyntaxWarning.

The authors of this PEP believe that adding a completely new syntax will,first and foremost, not solve the common beginner pitfall that this PEP aims topatch, and will not improve the formatting of assert statements across multiplelines, which the authors believe the proposed syntax improves.

Security Implications

There are no security implications for this change.

Acknowledgements

This change was originally discussed and proposed inpython/cpython#90325.

Many thanks to Petr Viktorin for his help during the drafting process of this PEP.

Footnotes

[1]
StackOverflow: “‘assert’ statement with or without parentheses”
[2]
/r/python: “Rant: use that second expression in assert! “
[3]
flake8: Rule F631
[4]
pylint: assert-on-tuple (W0199)
[5]
For the previous parser implementation, seepython/cpython#30247
[6]
During the updating of this PEP, an exception(assert(*(t:=()),)) was found, contradicting the warning.
[7]
[DPO] Pre-PEP: Assert-with: Dedicated syntax for assertion messages
[8] (1,2)
An edge case arises with constructs like:
>>>x=(0,)>>>assert(*x,"edge cases aren't fun:-(")

This form is currently parsed as a single tuple expression, notas a condition/message pair, and will need explicit handling inthe compiler.

Copyright

This document is placed in the public domain or under theCC0-1.0-Universal license, whichever is more permissive.


Source:https://github.com/python/peps/blob/main/peps/pep-0679.rst

Last modified:2025-10-24 08:11:50 GMT


[8]ページ先頭

©2009-2025 Movatter.jp