Skip to content

bpo-35169: Improve error messages for forbidden assignments. #10342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Lib/test/test_dictcomps.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ def test_local_visibility(self):
self.assertEqual(v, "Local variable")

def test_illegal_assignment(self):
with self.assertRaisesRegex(SyntaxError, "can't assign"):
with self.assertRaisesRegex(SyntaxError, "cannot assign"):
compile("{x: y for y, x in ((1, 2), (3, 4))} = 5", "<test>",
"exec")

with self.assertRaisesRegex(SyntaxError, "can't assign"):
with self.assertRaisesRegex(SyntaxError, "cannot assign"):
compile("{x: y for y, x in ((1, 2), (3, 4))} += 5", "<test>",
"exec")

Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -1865,12 +1865,12 @@ def printsolution(self, x):
>>> def f(): (yield bar) = y
Traceback (most recent call last):
...
SyntaxError: can't assign to yield expression
SyntaxError: cannot assign to yield expression

>>> def f(): (yield bar) += y
Traceback (most recent call last):
...
SyntaxError: can't assign to yield expression
SyntaxError: cannot assign to yield expression


Now check some throw() conditions:
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_genexps.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,12 @@
>>> (y for y in (1,2)) = 10
Traceback (most recent call last):
...
SyntaxError: can't assign to generator expression
SyntaxError: cannot assign to generator expression

>>> (y for y in (1,2)) += 10
Traceback (most recent call last):
...
SyntaxError: can't assign to generator expression
SyntaxError: cannot assign to generator expression


########### Tests borrowed from or inspired by test_generators.py ############
Expand Down
117 changes: 87 additions & 30 deletions Lib/test/test_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,55 @@

>>> None = 1
Traceback (most recent call last):
SyntaxError: can't assign to keyword
SyntaxError: cannot assign to None

>>> obj.True = 1
Traceback (most recent call last):
SyntaxError: invalid syntax

>>> True = 1
Traceback (most recent call last):
SyntaxError: cannot assign to True

>>> obj.__debug__ = 1
Traceback (most recent call last):
SyntaxError: cannot assign to __debug__

>>> __debug__ = 1
Traceback (most recent call last):
SyntaxError: cannot assign to __debug__

>>> f() = 1
Traceback (most recent call last):
SyntaxError: can't assign to function call
SyntaxError: cannot assign to function call

>>> del f()
Traceback (most recent call last):
SyntaxError: can't delete function call
SyntaxError: cannot delete function call

>>> a + 1 = 2
Traceback (most recent call last):
SyntaxError: can't assign to operator
SyntaxError: cannot assign to operator

>>> (x for x in x) = 1
Traceback (most recent call last):
SyntaxError: can't assign to generator expression
SyntaxError: cannot assign to generator expression

>>> 1 = 1
Traceback (most recent call last):
SyntaxError: can't assign to literal
SyntaxError: cannot assign to literal

>>> "abc" = 1
Traceback (most recent call last):
SyntaxError: can't assign to literal
SyntaxError: cannot assign to literal

>>> b"" = 1
Traceback (most recent call last):
SyntaxError: can't assign to literal
SyntaxError: cannot assign to literal

>>> ... = 1
Traceback (most recent call last):
SyntaxError: cannot assign to Ellipsis

>>> `1` = 1
Traceback (most recent call last):
Expand All @@ -74,15 +94,31 @@

>>> (a, "b", c) = (1, 2, 3)
Traceback (most recent call last):
SyntaxError: can't assign to literal
SyntaxError: cannot assign to literal

>>> (a, True, c) = (1, 2, 3)
Traceback (most recent call last):
SyntaxError: cannot assign to True

>>> (a, __debug__, c) = (1, 2, 3)
Traceback (most recent call last):
SyntaxError: cannot assign to __debug__

>>> (a, *True, c) = (1, 2, 3)
Traceback (most recent call last):
SyntaxError: cannot assign to True

>>> (a, *__debug__, c) = (1, 2, 3)
Traceback (most recent call last):
SyntaxError: cannot assign to __debug__

>>> [a, b, c + 1] = [1, 2, 3]
Traceback (most recent call last):
SyntaxError: can't assign to operator
SyntaxError: cannot assign to operator

>>> a if 1 else b = 1
Traceback (most recent call last):
SyntaxError: can't assign to conditional expression
SyntaxError: cannot assign to conditional expression

From compiler_complex_args():

Expand Down Expand Up @@ -255,36 +291,45 @@

>>> f(lambda x: x[0] = 3)
Traceback (most recent call last):
SyntaxError: lambda cannot contain assignment
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?

The grammar accepts any test (basically, any expression) in the
keyword slot of a call site. Test a few different options.

>>> f(x()=2)
Traceback (most recent call last):
SyntaxError: keyword can't be an expression
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
>>> f(a or b=1)
Traceback (most recent call last):
SyntaxError: keyword can't be an expression
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
>>> f(x.y=1)
Traceback (most recent call last):
SyntaxError: keyword can't be an expression
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
>>> f((x)=2)
Traceback (most recent call last):
SyntaxError: keyword can't be an expression
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
>>> f(True=2)
Traceback (most recent call last):
SyntaxError: cannot assign to True
>>> f(__debug__=1)
Traceback (most recent call last):
SyntaxError: cannot assign to __debug__


More set_context():

>>> (x for x in x) += 1
Traceback (most recent call last):
SyntaxError: can't assign to generator expression
SyntaxError: cannot assign to generator expression
>>> None += 1
Traceback (most recent call last):
SyntaxError: can't assign to keyword
SyntaxError: cannot assign to None
>>> __debug__ += 1
Traceback (most recent call last):
SyntaxError: cannot assign to __debug__
>>> f() += 1
Traceback (most recent call last):
SyntaxError: can't assign to function call
SyntaxError: cannot assign to function call


Test continue in finally in weird combinations.
Expand Down Expand Up @@ -481,15 +526,15 @@
... pass
Traceback (most recent call last):
...
SyntaxError: can't assign to function call
SyntaxError: cannot assign to function call

>>> if 1:
... pass
... elif 1:
... x() = 1
Traceback (most recent call last):
...
SyntaxError: can't assign to function call
SyntaxError: cannot assign to function call

>>> if 1:
... x() = 1
Expand All @@ -499,7 +544,7 @@
... pass
Traceback (most recent call last):
...
SyntaxError: can't assign to function call
SyntaxError: cannot assign to function call

>>> if 1:
... pass
Expand All @@ -509,7 +554,7 @@
... pass
Traceback (most recent call last):
...
SyntaxError: can't assign to function call
SyntaxError: cannot assign to function call

>>> if 1:
... pass
Expand All @@ -519,7 +564,7 @@
... x() = 1
Traceback (most recent call last):
...
SyntaxError: can't assign to function call
SyntaxError: cannot assign to function call

Make sure that the old "raise X, Y[, Z]" form is gone:
>>> raise X, Y
Expand All @@ -539,21 +584,33 @@

>>> {1, 2, 3} = 42
Traceback (most recent call last):
SyntaxError: can't assign to literal
SyntaxError: cannot assign to set display

>>> {1: 2, 3: 4} = 42
Traceback (most recent call last):
SyntaxError: cannot assign to dict display

>>> f'{x}' = 42
Traceback (most recent call last):
SyntaxError: cannot assign to f-string expression

>>> f'{x}-{y}' = 42
Traceback (most recent call last):
SyntaxError: cannot assign to f-string expression

Corner-cases that used to fail to raise the correct error:

>>> def f(*, x=lambda __debug__:0): pass
Traceback (most recent call last):
SyntaxError: assignment to keyword
SyntaxError: cannot assign to __debug__

>>> def f(*args:(lambda __debug__:0)): pass
Traceback (most recent call last):
SyntaxError: assignment to keyword
SyntaxError: cannot assign to __debug__

>>> def f(**kwargs:(lambda __debug__:0)): pass
Traceback (most recent call last):
SyntaxError: assignment to keyword
SyntaxError: cannot assign to __debug__

>>> with (lambda *:0): pass
Traceback (most recent call last):
Expand All @@ -563,11 +620,11 @@

>>> def f(**__debug__): pass
Traceback (most recent call last):
SyntaxError: assignment to keyword
SyntaxError: cannot assign to __debug__

>>> def f(*xx, __debug__): pass
Traceback (most recent call last):
SyntaxError: assignment to keyword
SyntaxError: cannot assign to __debug__

"""

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved error messages for forbidden assignments.
Loading