@@ -102,10 +102,13 @@ def test_named_expression_invalid_16(self):
102102 with self .assertRaisesRegex (SyntaxError , "invalid syntax" ):
103103 exec (code , {}, {})
104104
105+ # TODO: RUSTPYTHON
106+ @unittest .expectedFailure
105107 def test_named_expression_invalid_17 (self ):
106108 code = "[i := 0, j := 1 for i, j in [(1, 2), (3, 4)]]"
107109
108- with self .assertRaisesRegex (SyntaxError , "invalid syntax" ):
110+ with self .assertRaisesRegex (SyntaxError ,
111+ "did you forget parentheses around the comprehension target?" ):
109112 exec (code , {}, {})
110113
111114 def test_named_expression_invalid_in_class_body (self ):
@@ -119,7 +122,7 @@ def test_named_expression_invalid_in_class_body(self):
119122
120123 # TODO: RUSTPYTHON
121124 @unittest .expectedFailure # wrong error message
122- def test_named_expression_invalid_rebinding_comprehension_iteration_variable (self ):
125+ def test_named_expression_invalid_rebinding_list_comprehension_iteration_variable (self ):
123126 cases = [
124127 ("Local reuse" , 'i' , "[i := 0 for i in range(5)]" ),
125128 ("Nested reuse" , 'j' , "[[(j := 0) for i in range(5)] for j in range(5)]" ),
@@ -138,7 +141,7 @@ def test_named_expression_invalid_rebinding_comprehension_iteration_variable(sel
138141
139142 # TODO: RUSTPYTHON
140143 @unittest .expectedFailure # wrong error message
141- def test_named_expression_invalid_rebinding_comprehension_inner_loop (self ):
144+ def test_named_expression_invalid_rebinding_list_comprehension_inner_loop (self ):
142145 cases = [
143146 ("Inner reuse" , 'j' , "[i for i in range(5) if (j := 0) for j in range(5)]" ),
144147 ("Inner unpacking reuse" , 'j' , "[i for i in range(5) if (j := 0) for j, k in [(0, 1)]]" ),
@@ -153,7 +156,7 @@ def test_named_expression_invalid_rebinding_comprehension_inner_loop(self):
153156 with self .assertRaisesRegex (SyntaxError , msg ):
154157 exec (f"lambda: { code } " , {}) # Function scope
155158
156- def test_named_expression_invalid_comprehension_iterable_expression (self ):
159+ def test_named_expression_invalid_list_comprehension_iterable_expression (self ):
157160 cases = [
158161 ("Top level" , "[i for i in (i := range(5))]" ),
159162 ("Inside tuple" , "[i for i in (2, 3, i := range(5))]" ),
@@ -175,6 +178,64 @@ def test_named_expression_invalid_comprehension_iterable_expression(self):
175178 with self .assertRaisesRegex (SyntaxError , msg ):
176179 exec (f"lambda: { code } " , {}) # Function scope
177180
181+ # TODO: RUSTPYTHON
182+ @unittest .expectedFailure
183+ def test_named_expression_invalid_rebinding_set_comprehension_iteration_variable (self ):
184+ cases = [
185+ ("Local reuse" , 'i' , "{i := 0 for i in range(5)}" ),
186+ ("Nested reuse" , 'j' , "{{(j := 0) for i in range(5)} for j in range(5)}" ),
187+ ("Reuse inner loop target" , 'j' , "{(j := 0) for i in range(5) for j in range(5)}" ),
188+ ("Unpacking reuse" , 'i' , "{i := 0 for i, j in {(0, 1)}}" ),
189+ ("Reuse in loop condition" , 'i' , "{i+1 for i in range(5) if (i := 0)}" ),
190+ ("Unreachable reuse" , 'i' , "{False or (i:=0) for i in range(5)}" ),
191+ ("Unreachable nested reuse" , 'i' ,
192+ "{(i, j) for i in range(5) for j in range(5) if True or (i:=10)}" ),
193+ ]
194+ for case , target , code in cases :
195+ msg = f"assignment expression cannot rebind comprehension iteration variable '{ target } '"
196+ with self .subTest (case = case ):
197+ with self .assertRaisesRegex (SyntaxError , msg ):
198+ exec (code , {}, {})
199+
200+ # TODO: RUSTPYTHON
201+ @unittest .expectedFailure
202+ def test_named_expression_invalid_rebinding_set_comprehension_inner_loop (self ):
203+ cases = [
204+ ("Inner reuse" , 'j' , "{i for i in range(5) if (j := 0) for j in range(5)}" ),
205+ ("Inner unpacking reuse" , 'j' , "{i for i in range(5) if (j := 0) for j, k in {(0, 1)}}" ),
206+ ]
207+ for case , target , code in cases :
208+ msg = f"comprehension inner loop cannot rebind assignment expression target '{ target } '"
209+ with self .subTest (case = case ):
210+ with self .assertRaisesRegex (SyntaxError , msg ):
211+ exec (code , {}) # Module scope
212+ with self .assertRaisesRegex (SyntaxError , msg ):
213+ exec (code , {}, {}) # Class scope
214+ with self .assertRaisesRegex (SyntaxError , msg ):
215+ exec (f"lambda: { code } " , {}) # Function scope
216+
217+ def test_named_expression_invalid_set_comprehension_iterable_expression (self ):
218+ cases = [
219+ ("Top level" , "{i for i in (i := range(5))}" ),
220+ ("Inside tuple" , "{i for i in (2, 3, i := range(5))}" ),
221+ ("Inside list" , "{i for i in {2, 3, i := range(5)}}" ),
222+ ("Different name" , "{i for i in (j := range(5))}" ),
223+ ("Lambda expression" , "{i for i in (lambda:(j := range(5)))()}" ),
224+ ("Inner loop" , "{i for i in range(5) for j in (i := range(5))}" ),
225+ ("Nested comprehension" , "{i for i in {j for j in (k := range(5))}}" ),
226+ ("Nested comprehension condition" , "{i for i in {j for j in range(5) if (j := True)}}" ),
227+ ("Nested comprehension body" , "{i for i in {(j := True) for j in range(5)}}" ),
228+ ]
229+ msg = "assignment expression cannot be used in a comprehension iterable expression"
230+ for case , code in cases :
231+ with self .subTest (case = case ):
232+ with self .assertRaisesRegex (SyntaxError , msg ):
233+ exec (code , {}) # Module scope
234+ with self .assertRaisesRegex (SyntaxError , msg ):
235+ exec (code , {}, {}) # Class scope
236+ with self .assertRaisesRegex (SyntaxError , msg ):
237+ exec (f"lambda: { code } " , {}) # Function scope
238+
178239
179240class NamedExpressionAssignmentTest (unittest .TestCase ):
180241
@@ -279,6 +340,29 @@ def test_named_expression_assignment_16(self):
279340 fib = {(c := a ): (a := b ) + (b := a + c ) - b for __ in range (6 )}
280341 self .assertEqual (fib , {1 : 2 , 2 : 3 , 3 : 5 , 5 : 8 , 8 : 13 , 13 : 21 })
281342
343+ # TODO: RUSTPYTHON, SyntaxError
344+ # def test_named_expression_assignment_17(self):
345+ # a = [1]
346+ # element = a[b:=0]
347+ # self.assertEqual(b, 0)
348+ # self.assertEqual(element, a[0])
349+
350+ # TODO: RUSTPYTHON, SyntaxError
351+ # def test_named_expression_assignment_18(self):
352+ # class TwoDimensionalList:
353+ # def __init__(self, two_dimensional_list):
354+ # self.two_dimensional_list = two_dimensional_list
355+
356+ # def __getitem__(self, index):
357+ # return self.two_dimensional_list[index[0]][index[1]]
358+
359+ # a = TwoDimensionalList([[1], [2]])
360+ # element = a[b:=0, c:=0]
361+ # self.assertEqual(b, 0)
362+ # self.assertEqual(c, 0)
363+ # self.assertEqual(element, a.two_dimensional_list[b][c])
364+
365+
282366
283367class NamedExpressionScopeTest (unittest .TestCase ):
284368
@@ -325,16 +409,6 @@ def test_named_expression_scope_06(self):
325409 self .assertEqual (res , [[0 , 1 , 2 ], [0 , 1 , 2 ]])
326410 self .assertEqual (spam , 2 )
327411
328- # modified version of test_named_expression_scope_6, where locals
329- # assigned before to make them known in scop. THis is required due
330- # to some shortcommings in RPs name handling.
331- def test_named_expression_scope_06_rp_modified (self ):
332- spam = 0
333- res = [[spam := i for i in range (3 )] for j in range (2 )]
334-
335- self .assertEqual (res , [[0 , 1 , 2 ], [0 , 1 , 2 ]])
336- self .assertEqual (spam , 2 )
337-
338412 def test_named_expression_scope_07 (self ):
339413 len (lines := [1 , 2 ])
340414
@@ -372,18 +446,6 @@ def test_named_expression_scope_10(self):
372446 self .assertEqual (a , 1 )
373447 self .assertEqual (b , [1 , 1 ])
374448
375- # modified version of test_named_expression_scope_10, where locals
376- # assigned before to make them known in scop. THis is required due
377- # to some shortcommings in RPs name handling.
378- def test_named_expression_scope_10_rp_modified (self ):
379- a = 0
380- b = 0
381- res = [b := [a := 1 for i in range (2 )] for j in range (2 )]
382-
383- self .assertEqual (res , [[1 , 1 ], [1 , 1 ]])
384- self .assertEqual (b , [1 , 1 ])
385- self .assertEqual (a , 1 )
386-
387449 def test_named_expression_scope_11 (self ):
388450 res = [j := i for i in range (5 )]
389451
@@ -543,6 +605,15 @@ def g():
543605 self .assertEqual (nonlocal_var , None )
544606 f ()
545607
608+ def test_named_expression_scope_in_genexp (self ):
609+ a = 1
610+ b = [1 , 2 , 3 , 4 ]
611+ genexp = (c := i + a for i in b )
612+
613+ self .assertNotIn ("c" , locals ())
614+ for idx , elem in enumerate (genexp ):
615+ self .assertEqual (elem , b [idx ] + a )
616+
546617
547618if __name__ == "__main__" :
548619 unittest .main ()
0 commit comments