Skip to content

Commit 94b87fd

Browse files
committed
Handle functions defined under type-checking
1 parent 5feface commit 94b87fd

File tree

5 files changed

+24
-12
lines changed

5 files changed

+24
-12
lines changed

pylint/checkers/variables.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ def _uncertain_nodes_if_tests(
723723
name = other_node.name
724724
elif isinstance(other_node, (nodes.Import, nodes.ImportFrom)):
725725
name = node.name
726-
elif isinstance(other_node, nodes.ClassDef):
726+
elif isinstance(other_node, (nodes.FunctionDef, nodes.ClassDef)):
727727
name = other_node.name
728728
else:
729729
continue
@@ -1268,6 +1268,7 @@ def __init__(self, linter: PyLinter) -> None:
12681268
self._reported_type_checking_usage_scopes: dict[
12691269
str, list[nodes.LocalsDictNodeNG]
12701270
] = {}
1271+
self._nonlocal_names: set[str] = set()
12711272
self._postponed_evaluation_enabled = False
12721273

12731274
@utils.only_required_for_messages(
@@ -1434,6 +1435,9 @@ def leave_setcomp(self, _: nodes.SetComp) -> None:
14341435
def visit_functiondef(self, node: nodes.FunctionDef) -> None:
14351436
"""Visit function: update consumption analysis variable and check locals."""
14361437
self._to_consume.append(NamesConsumer(node, "function"))
1438+
self._nonlocal_names.update(
1439+
_flattened_scope_names(node.nodes_of_class(nodes.Nonlocal))
1440+
)
14371441
if not (
14381442
self.linter.is_message_enabled("redefined-outer-name")
14391443
or self.linter.is_message_enabled("redefined-builtin")
@@ -1483,6 +1487,7 @@ def visit_functiondef(self, node: nodes.FunctionDef) -> None:
14831487
def leave_functiondef(self, node: nodes.FunctionDef) -> None:
14841488
"""Leave function: check function's locals are consumed."""
14851489
self._check_metaclasses(node)
1490+
self._nonlocal_names = set()
14861491

14871492
if node.type_comment_returns:
14881493
self._store_type_annotation_node(node.type_comment_returns)
@@ -1874,12 +1879,18 @@ def _check_consumer(
18741879

18751880
# Skip postponed evaluation of annotations
18761881
# and unevaluated annotations inside a function body
1877-
if not (
1878-
self._postponed_evaluation_enabled
1879-
and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
1880-
) and not (
1881-
isinstance(stmt, nodes.AnnAssign)
1882-
and utils.get_node_first_ancestor_of_type(stmt, nodes.FunctionDef)
1882+
if (
1883+
not (
1884+
self._postponed_evaluation_enabled
1885+
and isinstance(stmt, (nodes.AnnAssign, nodes.FunctionDef))
1886+
)
1887+
and not (
1888+
isinstance(stmt, nodes.AnnAssign)
1889+
and utils.get_node_first_ancestor_of_type(
1890+
stmt, nodes.FunctionDef
1891+
)
1892+
)
1893+
and not node.name in self._nonlocal_names
18831894
):
18841895
self.add_message(
18851896
"used-before-assignment",
@@ -1964,6 +1975,8 @@ def _report_unfound_name_definition(
19641975
and node.scope() in self._reported_type_checking_usage_scopes[node.name]
19651976
):
19661977
return False
1978+
if node.name in self._nonlocal_names:
1979+
return False
19671980

19681981
confidence = HIGH
19691982
if node.name in current_consumer.names_under_always_false_test:

tests/functional/u/used/used_before_assignment.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ def outer_():
256256
def inner_try():
257257
try:
258258
nonlocal a
259-
print(a) # [used-before-assignment] FALSE POSITIVE
259+
print(a)
260260
a = 2
261261
print(a)
262262
except:
@@ -267,7 +267,7 @@ def inner_while():
267267
while i < 2:
268268
i += 1
269269
nonlocal a
270-
print(a) # [used-before-assignment] FALSE POSITIVE
270+
print(a)
271271
a = 2
272272
print(a)
273273

tests/functional/u/used/used_before_assignment.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,3 @@ used-before-assignment:184:10:184:18::Using variable 'ALL_DONE' before assignmen
1515
used-before-assignment:195:6:195:24::Using variable 'NOT_ALWAYS_DEFINED' before assignment:INFERENCE
1616
used-before-assignment:231:10:231:11::Using variable 'x' before assignment:CONTROL_FLOW
1717
possibly-used-before-assignment:245:10:245:15:__:Possibly using variable 'fail1' before assignment:CONTROL_FLOW
18-
used-before-assignment:259:18:259:19:outer_.inner_try:Using variable 'a' before assignment:HIGH
19-
used-before-assignment:270:18:270:19:outer_.inner_while:Using variable 'a' before assignment:HIGH

tests/functional/u/used/used_before_assignment_typing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def defined_in_elif_branch(self) -> calendar.Calendar: # [possibly-used-before-
173173

174174
def defined_in_else_branch(self) -> urlopen:
175175
print(zoneinfo) # [used-before-assignment]
176-
print(pprint())
176+
print(pprint()) # [used-before-assignment]
177177
print(collections()) # [used-before-assignment]
178178
return urlopen
179179

tests/functional/u/used/used_before_assignment_typing.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ used-before-assignment:153:20:153:28:VariableAnnotationsGuardedByTypeChecking:Us
66
possibly-used-before-assignment:170:40:170:48:TypeCheckingMultiBranch.defined_in_elif_branch:Possibly using variable 'calendar' before assignment:INFERENCE
77
possibly-used-before-assignment:171:14:171:20:TypeCheckingMultiBranch.defined_in_elif_branch:Possibly using variable 'bisect' before assignment:INFERENCE
88
used-before-assignment:175:14:175:22:TypeCheckingMultiBranch.defined_in_else_branch:Using variable 'zoneinfo' before assignment:INFERENCE
9+
used-before-assignment:176:14:176:20:TypeCheckingMultiBranch.defined_in_else_branch:Using variable 'pprint' before assignment:INFERENCE
910
used-before-assignment:177:14:177:25:TypeCheckingMultiBranch.defined_in_else_branch:Using variable 'collections' before assignment:INFERENCE
1011
possibly-used-before-assignment:180:43:180:48:TypeCheckingMultiBranch.defined_in_nested_if_else:Possibly using variable 'heapq' before assignment:INFERENCE
1112
used-before-assignment:184:39:184:44:TypeCheckingMultiBranch.defined_in_try_except:Using variable 'array' before assignment:INFERENCE

0 commit comments

Comments
 (0)