Skip to content

Commit 25684e7

Browse files
authored
gh-100746: Improve test_named_expressions.py (#116713)
1 parent 7f418fb commit 25684e7

File tree

1 file changed

+68
-2
lines changed

1 file changed

+68
-2
lines changed

Lib/test/test_named_expressions.py

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,72 @@ def test_named_expression_invalid_set_comprehension_iterable_expression(self):
298298
with self.assertRaisesRegex(SyntaxError, msg):
299299
exec(f"lambda: {code}", {}) # Function scope
300300

301+
def test_named_expression_invalid_rebinding_dict_comprehension_iteration_variable(self):
302+
cases = [
303+
("Key reuse", 'i', "{(i := 0): 1 for i in range(5)}"),
304+
("Value reuse", 'i', "{1: (i := 0) for i in range(5)}"),
305+
("Both reuse", 'i', "{(i := 0): (i := 0) for i in range(5)}"),
306+
("Nested reuse", 'j', "{{(j := 0): 1 for i in range(5)} for j in range(5)}"),
307+
("Reuse inner loop target", 'j', "{(j := 0): 1 for i in range(5) for j in range(5)}"),
308+
("Unpacking key reuse", 'i', "{(i := 0): 1 for i, j in {(0, 1)}}"),
309+
("Unpacking value reuse", 'i', "{1: (i := 0) for i, j in {(0, 1)}}"),
310+
("Reuse in loop condition", 'i', "{i+1: 1 for i in range(5) if (i := 0)}"),
311+
("Unreachable reuse", 'i', "{(False or (i:=0)): 1 for i in range(5)}"),
312+
("Unreachable nested reuse", 'i',
313+
"{i: j for i in range(5) for j in range(5) if True or (i:=10)}"),
314+
# Regression tests from https://github.com/python/cpython/issues/87447
315+
("Complex expression: a", "a",
316+
"{(a := 1): 1 for a, (*b, c[d+e::f(g)], h.i) in j}"),
317+
("Complex expression: b", "b",
318+
"{(b := 1): 1 for a, (*b, c[d+e::f(g)], h.i) in j}"),
319+
]
320+
for case, target, code in cases:
321+
msg = f"assignment expression cannot rebind comprehension iteration variable '{target}'"
322+
with self.subTest(case=case):
323+
with self.assertRaisesRegex(SyntaxError, msg):
324+
exec(code, {}) # Module scope
325+
with self.assertRaisesRegex(SyntaxError, msg):
326+
exec(code, {}, {}) # Class scope
327+
with self.assertRaisesRegex(SyntaxError, msg):
328+
exec(f"lambda: {code}", {}) # Function scope
329+
330+
def test_named_expression_invalid_rebinding_dict_comprehension_inner_loop(self):
331+
cases = [
332+
("Inner reuse", 'j', "{i: 1 for i in range(5) if (j := 0) for j in range(5)}"),
333+
("Inner unpacking reuse", 'j', "{i: 1 for i in range(5) if (j := 0) for j, k in {(0, 1)}}"),
334+
]
335+
for case, target, code in cases:
336+
msg = f"comprehension inner loop cannot rebind assignment expression target '{target}'"
337+
with self.subTest(case=case):
338+
with self.assertRaisesRegex(SyntaxError, msg):
339+
exec(code, {}) # Module scope
340+
with self.assertRaisesRegex(SyntaxError, msg):
341+
exec(code, {}, {}) # Class scope
342+
with self.assertRaisesRegex(SyntaxError, msg):
343+
exec(f"lambda: {code}", {}) # Function scope
344+
345+
def test_named_expression_invalid_dict_comprehension_iterable_expression(self):
346+
cases = [
347+
("Top level", "{i: 1 for i in (i := range(5))}"),
348+
("Inside tuple", "{i: 1 for i in (2, 3, i := range(5))}"),
349+
("Inside list", "{i: 1 for i in [2, 3, i := range(5)]}"),
350+
("Different name", "{i: 1 for i in (j := range(5))}"),
351+
("Lambda expression", "{i: 1 for i in (lambda:(j := range(5)))()}"),
352+
("Inner loop", "{i: 1 for i in range(5) for j in (i := range(5))}"),
353+
("Nested comprehension", "{i: 1 for i in {j: 2 for j in (k := range(5))}}"),
354+
("Nested comprehension condition", "{i: 1 for i in {j: 2 for j in range(5) if (j := True)}}"),
355+
("Nested comprehension body", "{i: 1 for i in {(j := True) for j in range(5)}}"),
356+
]
357+
msg = "assignment expression cannot be used in a comprehension iterable expression"
358+
for case, code in cases:
359+
with self.subTest(case=case):
360+
with self.assertRaisesRegex(SyntaxError, msg):
361+
exec(code, {}) # Module scope
362+
with self.assertRaisesRegex(SyntaxError, msg):
363+
exec(code, {}, {}) # Class scope
364+
with self.assertRaisesRegex(SyntaxError, msg):
365+
exec(f"lambda: {code}", {}) # Function scope
366+
301367
def test_named_expression_invalid_mangled_class_variables(self):
302368
code = """class Foo:
303369
def bar(self):
@@ -361,7 +427,7 @@ def test_named_expression_assignment_09(self):
361427

362428
def test_named_expression_assignment_10(self):
363429
if (match := 10) == 10:
364-
pass
430+
self.assertEqual(match, 10)
365431
else: self.fail("variable was not assigned using named expression")
366432

367433
def test_named_expression_assignment_11(self):
@@ -403,7 +469,7 @@ def test_named_expression_assignment_14(self):
403469

404470
def test_named_expression_assignment_15(self):
405471
while a := False:
406-
pass # This will not run
472+
self.fail("While body executed") # This will not run
407473

408474
self.assertEqual(a, False)
409475

0 commit comments

Comments
 (0)