@@ -105,7 +105,8 @@ def test_named_expression_invalid_16(self):
105
105
def test_named_expression_invalid_17 (self ):
106
106
code = "[i := 0, j := 1 for i, j in [(1, 2), (3, 4)]]"
107
107
108
- with self .assertRaisesRegex (SyntaxError , "invalid syntax" ):
108
+ with self .assertRaisesRegex (SyntaxError ,
109
+ "did you forget parentheses around the comprehension target?" ):
109
110
exec (code , {}, {})
110
111
111
112
def test_named_expression_invalid_in_class_body (self ):
@@ -119,7 +120,7 @@ def test_named_expression_invalid_in_class_body(self):
119
120
120
121
# TODO: RUSTPYTHON
121
122
@unittest .expectedFailure # wrong error message
122
- def test_named_expression_invalid_rebinding_comprehension_iteration_variable (self ):
123
+ def test_named_expression_invalid_rebinding_list_comprehension_iteration_variable (self ):
123
124
cases = [
124
125
("Local reuse" , 'i' , "[i := 0 for i in range(5)]" ),
125
126
("Nested reuse" , 'j' , "[[(j := 0) for i in range(5)] for j in range(5)]" ),
@@ -138,7 +139,7 @@ def test_named_expression_invalid_rebinding_comprehension_iteration_variable(sel
138
139
139
140
# TODO: RUSTPYTHON
140
141
@unittest .expectedFailure # wrong error message
141
- def test_named_expression_invalid_rebinding_comprehension_inner_loop (self ):
142
+ def test_named_expression_invalid_rebinding_list_comprehension_inner_loop (self ):
142
143
cases = [
143
144
("Inner reuse" , 'j' , "[i for i in range(5) if (j := 0) for j in range(5)]" ),
144
145
("Inner unpacking reuse" , 'j' , "[i for i in range(5) if (j := 0) for j, k in [(0, 1)]]" ),
@@ -153,7 +154,7 @@ def test_named_expression_invalid_rebinding_comprehension_inner_loop(self):
153
154
with self .assertRaisesRegex (SyntaxError , msg ):
154
155
exec (f"lambda: { code } " , {}) # Function scope
155
156
156
- def test_named_expression_invalid_comprehension_iterable_expression (self ):
157
+ def test_named_expression_invalid_list_comprehension_iterable_expression (self ):
157
158
cases = [
158
159
("Top level" , "[i for i in (i := range(5))]" ),
159
160
("Inside tuple" , "[i for i in (2, 3, i := range(5))]" ),
@@ -175,6 +176,60 @@ def test_named_expression_invalid_comprehension_iterable_expression(self):
175
176
with self .assertRaisesRegex (SyntaxError , msg ):
176
177
exec (f"lambda: { code } " , {}) # Function scope
177
178
179
+ def test_named_expression_invalid_rebinding_set_comprehension_iteration_variable (self ):
180
+ cases = [
181
+ ("Local reuse" , 'i' , "{i := 0 for i in range(5)}" ),
182
+ ("Nested reuse" , 'j' , "{{(j := 0) for i in range(5)} for j in range(5)}" ),
183
+ ("Reuse inner loop target" , 'j' , "{(j := 0) for i in range(5) for j in range(5)}" ),
184
+ ("Unpacking reuse" , 'i' , "{i := 0 for i, j in {(0, 1)}}" ),
185
+ ("Reuse in loop condition" , 'i' , "{i+1 for i in range(5) if (i := 0)}" ),
186
+ ("Unreachable reuse" , 'i' , "{False or (i:=0) for i in range(5)}" ),
187
+ ("Unreachable nested reuse" , 'i' ,
188
+ "{(i, j) for i in range(5) for j in range(5) if True or (i:=10)}" ),
189
+ ]
190
+ for case , target , code in cases :
191
+ msg = f"assignment expression cannot rebind comprehension iteration variable '{ target } '"
192
+ with self .subTest (case = case ):
193
+ with self .assertRaisesRegex (SyntaxError , msg ):
194
+ exec (code , {}, {})
195
+
196
+ def test_named_expression_invalid_rebinding_set_comprehension_inner_loop (self ):
197
+ cases = [
198
+ ("Inner reuse" , 'j' , "{i for i in range(5) if (j := 0) for j in range(5)}" ),
199
+ ("Inner unpacking reuse" , 'j' , "{i for i in range(5) if (j := 0) for j, k in {(0, 1)}}" ),
200
+ ]
201
+ for case , target , code in cases :
202
+ msg = f"comprehension inner loop cannot rebind assignment expression target '{ target } '"
203
+ with self .subTest (case = case ):
204
+ with self .assertRaisesRegex (SyntaxError , msg ):
205
+ exec (code , {}) # Module scope
206
+ with self .assertRaisesRegex (SyntaxError , msg ):
207
+ exec (code , {}, {}) # Class scope
208
+ with self .assertRaisesRegex (SyntaxError , msg ):
209
+ exec (f"lambda: { code } " , {}) # Function scope
210
+
211
+ def test_named_expression_invalid_set_comprehension_iterable_expression (self ):
212
+ cases = [
213
+ ("Top level" , "{i for i in (i := range(5))}" ),
214
+ ("Inside tuple" , "{i for i in (2, 3, i := range(5))}" ),
215
+ ("Inside list" , "{i for i in {2, 3, i := range(5)}}" ),
216
+ ("Different name" , "{i for i in (j := range(5))}" ),
217
+ ("Lambda expression" , "{i for i in (lambda:(j := range(5)))()}" ),
218
+ ("Inner loop" , "{i for i in range(5) for j in (i := range(5))}" ),
219
+ ("Nested comprehension" , "{i for i in {j for j in (k := range(5))}}" ),
220
+ ("Nested comprehension condition" , "{i for i in {j for j in range(5) if (j := True)}}" ),
221
+ ("Nested comprehension body" , "{i for i in {(j := True) for j in range(5)}}" ),
222
+ ]
223
+ msg = "assignment expression cannot be used in a comprehension iterable expression"
224
+ for case , code in cases :
225
+ with self .subTest (case = case ):
226
+ with self .assertRaisesRegex (SyntaxError , msg ):
227
+ exec (code , {}) # Module scope
228
+ with self .assertRaisesRegex (SyntaxError , msg ):
229
+ exec (code , {}, {}) # Class scope
230
+ with self .assertRaisesRegex (SyntaxError , msg ):
231
+ exec (f"lambda: { code } " , {}) # Function scope
232
+
178
233
179
234
class NamedExpressionAssignmentTest (unittest .TestCase ):
180
235
@@ -279,6 +334,27 @@ def test_named_expression_assignment_16(self):
279
334
fib = {(c := a ): (a := b ) + (b := a + c ) - b for __ in range (6 )}
280
335
self .assertEqual (fib , {1 : 2 , 2 : 3 , 3 : 5 , 5 : 8 , 8 : 13 , 13 : 21 })
281
336
337
+ def test_named_expression_assignment_17 (self ):
338
+ a = [1 ]
339
+ element = a [b := 0 ]
340
+ self .assertEqual (b , 0 )
341
+ self .assertEqual (element , a [0 ])
342
+
343
+ def test_named_expression_assignment_18 (self ):
344
+ class TwoDimensionalList :
345
+ def __init__ (self , two_dimensional_list ):
346
+ self .two_dimensional_list = two_dimensional_list
347
+
348
+ def __getitem__ (self , index ):
349
+ return self .two_dimensional_list [index [0 ]][index [1 ]]
350
+
351
+ a = TwoDimensionalList ([[1 ], [2 ]])
352
+ element = a [b := 0 , c := 0 ]
353
+ self .assertEqual (b , 0 )
354
+ self .assertEqual (c , 0 )
355
+ self .assertEqual (element , a .two_dimensional_list [b ][c ])
356
+
357
+
282
358
283
359
class NamedExpressionScopeTest (unittest .TestCase ):
284
360
@@ -325,16 +401,6 @@ def test_named_expression_scope_06(self):
325
401
self .assertEqual (res , [[0 , 1 , 2 ], [0 , 1 , 2 ]])
326
402
self .assertEqual (spam , 2 )
327
403
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
-
338
404
def test_named_expression_scope_07 (self ):
339
405
len (lines := [1 , 2 ])
340
406
@@ -372,18 +438,6 @@ def test_named_expression_scope_10(self):
372
438
self .assertEqual (a , 1 )
373
439
self .assertEqual (b , [1 , 1 ])
374
440
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
-
387
441
def test_named_expression_scope_11 (self ):
388
442
res = [j := i for i in range (5 )]
389
443
@@ -543,6 +597,15 @@ def g():
543
597
self .assertEqual (nonlocal_var , None )
544
598
f ()
545
599
600
+ def test_named_expression_scope_in_genexp (self ):
601
+ a = 1
602
+ b = [1 , 2 , 3 , 4 ]
603
+ genexp = (c := i + a for i in b )
604
+
605
+ self .assertNotIn ("c" , locals ())
606
+ for idx , elem in enumerate (genexp ):
607
+ self .assertEqual (elem , b [idx ] + a )
608
+
546
609
547
610
if __name__ == "__main__" :
548
611
unittest .main ()
0 commit comments