Skip to content

Commit 1cbc3d8

Browse files
Fix false negative for calling module-level function before definition (#8494)
1 parent 87a4d67 commit 1cbc3d8

File tree

5 files changed

+29
-19
lines changed

5 files changed

+29
-19
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Emit ``used-before-assignment`` when calling module-level functions before definition.
2+
3+
Closes #1144

pylint/checkers/variables.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -218,17 +218,11 @@ class C: ...
218218
return node.lineno < defframe.lineno # type: ignore[no-any-return]
219219
if not isinstance(node.parent, (nodes.FunctionDef, nodes.Arguments)):
220220
return False
221-
elif any(
222-
not isinstance(f, (nodes.ClassDef, nodes.Module)) for f in (frame, defframe)
223-
):
224-
# Not interested in other frames, since they are already
225-
# not in a global scope.
226-
return False
227221

228222
break_scopes = []
229-
for current_scope in (scope, def_scope):
223+
for current_scope in (scope or frame, def_scope):
230224
# Look for parent scopes. If there is anything different
231-
# than a module or a class scope, then they frames don't
225+
# than a module or a class scope, then the frames don't
232226
# share a global scope.
233227
parent_scope = current_scope
234228
while parent_scope:
@@ -239,7 +233,7 @@ class C: ...
239233
parent_scope = parent_scope.parent.scope()
240234
else:
241235
break
242-
if break_scopes and len(set(break_scopes)) != 1:
236+
if len(set(break_scopes)) > 1:
243237
# Store different scopes than expected.
244238
# If the stored scopes are, in fact, the very same, then it means
245239
# that the two frames (frame and defframe) share the same scope,

tests/functional/u/used/used_before_assignment.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@ def inner():
1414
outer()
1515

1616

17+
class ClassWithProperty: # pylint: disable=too-few-public-methods
18+
"""This test depends on earlier and later defined module-level functions."""
19+
prop = property(redefine_time_import) # [used-before-assignment]
20+
prop_defined_earlier = property(outer)
21+
22+
23+
calculate(1.01, 2) # [used-before-assignment]
24+
def calculate(value1: int, value2: float) -> int:
25+
return value1 + value2
26+
27+
1728
# pylint: disable=unused-import, wrong-import-position, import-outside-toplevel, reimported, redefined-outer-name, global-statement
1829
import time
1930
def redefine_time_import():
Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
used-before-assignment:5:19:5:22::Using variable 'MSG' before assignment:HIGH
22
used-before-assignment:7:20:7:24::Using variable 'MSG2' before assignment:HIGH
33
used-before-assignment:10:4:10:9:outer:Using variable 'inner' before assignment:HIGH
4-
used-before-assignment:20:10:20:14:redefine_time_import:Using variable 'time' before assignment:HIGH
5-
used-before-assignment:34:3:34:7::Using variable 'VAR2' before assignment:CONTROL_FLOW
6-
used-before-assignment:52:3:52:7::Using variable 'VAR4' before assignment:CONTROL_FLOW
7-
used-before-assignment:67:3:67:7::Using variable 'VAR6' before assignment:CONTROL_FLOW
8-
used-before-assignment:102:6:102:11::Using variable 'VAR10' before assignment:CONTROL_FLOW
9-
used-before-assignment:133:10:133:14::Using variable 'SALE' before assignment:CONTROL_FLOW
10-
used-before-assignment:165:10:165:18::Using variable 'ALL_DONE' before assignment:CONTROL_FLOW
4+
used-before-assignment:19:20:19:40:ClassWithProperty:Using variable 'redefine_time_import' before assignment:HIGH
5+
used-before-assignment:23:0:23:9::Using variable 'calculate' before assignment:HIGH
6+
used-before-assignment:31:10:31:14:redefine_time_import:Using variable 'time' before assignment:HIGH
7+
used-before-assignment:45:3:45:7::Using variable 'VAR2' before assignment:CONTROL_FLOW
8+
used-before-assignment:63:3:63:7::Using variable 'VAR4' before assignment:CONTROL_FLOW
9+
used-before-assignment:78:3:78:7::Using variable 'VAR6' before assignment:CONTROL_FLOW
10+
used-before-assignment:113:6:113:11::Using variable 'VAR10' before assignment:CONTROL_FLOW
11+
used-before-assignment:144:10:144:14::Using variable 'SALE' before assignment:CONTROL_FLOW
12+
used-before-assignment:176:10:176:18::Using variable 'ALL_DONE' before assignment:CONTROL_FLOW
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
used-before-assignment:6:14:6:15:invalid:Using variable 'a' before assignment:HIGH
2-
used-before-assignment:8:14:8:15:invalid:Using variable 'b' before assignment:HIGH
3-
used-before-assignment:9:10:9:11:invalid:Using variable 'c' before assignment:HIGH
1+
used-before-assignment:6:14:6:15:invalid:Using variable 'a' before assignment:HIGH
2+
used-before-assignment:8:14:8:15:invalid:Using variable 'b' before assignment:HIGH
3+
used-before-assignment:9:10:9:11:invalid:Using variable 'c' before assignment:HIGH

0 commit comments

Comments
 (0)