@@ -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