Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/whatsnew/fragments/10847.false_negative
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix ``used-before-assignment`` false negative when a variable has a bare type
annotation (without a value) and is only assigned inside ``except`` blocks.

Closes #10847
16 changes: 16 additions & 0 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,22 @@ def get_next_to_consume(self, node: nodes.Name) -> list[nodes.NodeNG] | None:
uncertain_nodes_set = set(uncertain_nodes)
found_nodes = [n for n in found_nodes if n not in uncertain_nodes_set]

# Treat bare type annotations (AnnAssign without a value) as uncertain
# when there are other uncertain definitions. A bare annotation like
# `x: int` does not actually assign a value, so it should not suppress
# possibly-used-before-assignment when the real assignments are uncertain
# (e.g., in except blocks).
if found_nodes and self.consumed_uncertain.get(name):
bare_annotations = [
n
for n in found_nodes
if isinstance(n.parent, nodes.AnnAssign) and n.parent.value is None
]
if bare_annotations:
self.consumed_uncertain[name] += bare_annotations
bare_set = set(bare_annotations)
found_nodes = [n for n in found_nodes if n not in bare_set]

return found_nodes

def _inferred_to_define_name_raise_or_return(
Expand Down
28 changes: 28 additions & 0 deletions tests/functional/u/used/used_before_assignment_type_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,31 @@ def loop_conditional_annotated_assignment():
data={"cat": "harf"}
token: str = data.get("cat") # [possibly-used-before-assignment]
print(token)


def bare_annotation_with_except_assignment(text):
"""A bare type annotation should not suppress used-before-assignment
when the only real assignments are in except blocks.

https://github.com/pylint-dev/pylint/issues/10847
"""
err: int
try:
result = int(text)
except ValueError:
err = 1
result = -1
if result < 0:
print(err) # [used-before-assignment]


def bare_annotation_with_value_and_except(text):
"""A type annotation with a value should suppress the warning."""
err: int = 0
try:
result = int(text)
except ValueError:
err = 1
result = -1
if result < 0:
print(err)
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ used-before-assignment:28:10:28:18:value_assignment_after_access:Using variable
undefined-variable:62:14:62:17:decorator_returning_incorrect_function.wrapper_with_type_and_no_value:Undefined variable 'var':HIGH
possibly-used-before-assignment:97:17:97:21:conditional_annotated_assignment:Possibly using variable 'data' before assignment:CONTROL_FLOW
possibly-used-before-assignment:108:17:108:21:loop_conditional_annotated_assignment:Possibly using variable 'data' before assignment:CONTROL_FLOW
used-before-assignment:125:14:125:17:bare_annotation_with_except_assignment:Using variable 'err' before assignment:CONTROL_FLOW