2
2
Should emit:
3
3
B023 - on lines 12, 13, 16, 28, 29, 30, 31, 40, 42, 50, 51, 52, 53, 61, 68.
4
4
"""
5
+ from functools import reduce
5
6
6
7
functions = []
7
8
z = 0
8
-
9
9
for x in range (3 ):
10
10
y = x + 1
11
11
# Subject to late-binding problems
@@ -25,10 +25,10 @@ def f_ok_1(x):
25
25
26
26
27
27
def check_inside_functions_too ():
28
- ls = [lambda : x for x in range (2 )]
29
- st = {lambda : x for x in range (2 )}
30
- gn = (lambda : x for x in range (2 ))
31
- dt = {x : lambda : x for x in range (2 )}
28
+ ls = [lambda : x for x in range (2 )] # error
29
+ st = {lambda : x for x in range (2 )} # error
30
+ gn = (lambda : x for x in range (2 )) # error
31
+ dt = {x : lambda : x for x in range (2 )} # error
32
32
33
33
34
34
async def pointless_async_iterable ():
@@ -37,28 +37,28 @@ async def pointless_async_iterable():
37
37
38
38
async def container_for_problems ():
39
39
async for x in pointless_async_iterable ():
40
- functions .append (lambda : x )
40
+ functions .append (lambda : x ) # error
41
41
42
- [lambda : x async for x in pointless_async_iterable ()]
42
+ [lambda : x async for x in pointless_async_iterable ()] # error
43
43
44
44
45
45
a = 10
46
46
b = 0
47
47
while True :
48
48
a = a_ = a - 1
49
49
b += 1
50
- functions .append (lambda : a )
51
- functions .append (lambda : a_ )
52
- functions .append (lambda : b )
53
- functions .append (lambda : c ) # not a name error because of late binding!
50
+ functions .append (lambda : a ) # error
51
+ functions .append (lambda : a_ ) # error
52
+ functions .append (lambda : b ) # error
53
+ functions .append (lambda : c ) # error, but not a name error due to late binding
54
54
c : bool = a > 3
55
55
if not c :
56
56
break
57
57
58
58
# Nested loops should not duplicate reports
59
59
for j in range (2 ):
60
60
for k in range (3 ):
61
- lambda : j * k
61
+ lambda : j * k # error
62
62
63
63
64
64
for j , k , l in [(1 , 2 , 3 )]:
@@ -76,3 +76,87 @@ def f():
76
76
77
77
def explicit_capture (captured = var ):
78
78
return captured
79
+
80
+
81
+ # `query` is defined in the function, so also defining it in the loop should be OK.
82
+ for name in ["a" , "b" ]:
83
+ query = name
84
+
85
+ def myfunc (x ):
86
+ query = x
87
+ query_post = x
88
+ _ = query
89
+ _ = query_post
90
+
91
+ query_post = name # in case iteration order matters
92
+
93
+
94
+ # Bug here because two dict comprehensions reference `name`, one of which is inside
95
+ # the lambda. This should be totally fine, of course.
96
+ _ = {
97
+ k : v
98
+ for k , v in reduce (
99
+ lambda data , event : merge_mappings (
100
+ [data , {name : f (caches , data , event ) for name , f in xx }]
101
+ ),
102
+ events ,
103
+ {name : getattr (group , name ) for name in yy },
104
+ ).items ()
105
+ if k in backfill_fields
106
+ }
107
+
108
+
109
+ # OK to define lambdas if they're immediately consumed, typically as the `key=`
110
+ # argument or in a consumed `filter()` (even if a comprehension is better style)
111
+ for x in range (2 ):
112
+ # It's not a complete get-out-of-linting-free construct - these should fail:
113
+ min ([None , lambda : x ], key = repr )
114
+ sorted ([None , lambda : x ], key = repr )
115
+ any (filter (bool , [None , lambda : x ]))
116
+ list (filter (bool , [None , lambda : x ]))
117
+ all (reduce (bool , [None , lambda : x ]))
118
+
119
+ # But all these ones should be OK:
120
+ min (range (3 ), key = lambda y : x * y )
121
+ max (range (3 ), key = lambda y : x * y )
122
+ sorted (range (3 ), key = lambda y : x * y )
123
+
124
+ any (filter (lambda y : x < y , range (3 )))
125
+ all (filter (lambda y : x < y , range (3 )))
126
+ set (filter (lambda y : x < y , range (3 )))
127
+ list (filter (lambda y : x < y , range (3 )))
128
+ tuple (filter (lambda y : x < y , range (3 )))
129
+ sorted (filter (lambda y : x < y , range (3 )))
130
+ frozenset (filter (lambda y : x < y , range (3 )))
131
+
132
+ any (reduce (lambda y : x | y , range (3 )))
133
+ all (reduce (lambda y : x | y , range (3 )))
134
+ set (reduce (lambda y : x | y , range (3 )))
135
+ list (reduce (lambda y : x | y , range (3 )))
136
+ tuple (reduce (lambda y : x | y , range (3 )))
137
+ sorted (reduce (lambda y : x | y , range (3 )))
138
+ frozenset (reduce (lambda y : x | y , range (3 )))
139
+
140
+ import functools
141
+
142
+ any (functools .reduce (lambda y : x | y , range (3 )))
143
+ all (functools .reduce (lambda y : x | y , range (3 )))
144
+ set (functools .reduce (lambda y : x | y , range (3 )))
145
+ list (functools .reduce (lambda y : x | y , range (3 )))
146
+ tuple (functools .reduce (lambda y : x | y , range (3 )))
147
+ sorted (functools .reduce (lambda y : x | y , range (3 )))
148
+ frozenset (functools .reduce (lambda y : x | y , range (3 )))
149
+
150
+ # OK because the lambda which references a loop variable is defined in a `return`
151
+ # statement, and after we return the loop variable can't be redefined.
152
+ # In principle we could do something fancy with `break`, but it's not worth it.
153
+ def iter_f (names ):
154
+ for name in names :
155
+ if exists (name ):
156
+ return lambda : name if exists (name ) else None
157
+
158
+ if foo (name ):
159
+ return [lambda : name ] # false alarm, should be fixed?
160
+
161
+ if False :
162
+ return [lambda : i for i in range (3 )] # error
0 commit comments