Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix undefined-variable for Python 3.12 generic type syntax #10135

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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/9335.false_positive
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix false positives for ``undefined-variable`` for classes using Python 3.12
generic type syntax.

Closes #9335
16 changes: 15 additions & 1 deletion pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,11 @@ def _should_node_be_skipped(
if utils.is_ancestor_name(consumer.node, node) or (
not is_start_index and self._ignore_class_scope(node)
):
if any(
node.name == param.name.name for param in consumer.node.type_params
):
return False

return True

# Ignore inner class scope for keywords in class definition
Expand Down Expand Up @@ -1952,7 +1957,9 @@ def _check_consumer(
)
return (VariableVisitConsumerAction.RETURN, found_nodes)

elif isinstance(defstmt, nodes.ClassDef):
elif (
isinstance(defstmt, nodes.ClassDef) and defnode not in defframe.type_params
):
return self._is_first_level_self_reference(node, defstmt, found_nodes)

elif isinstance(defnode, nodes.NamedExpr):
Expand Down Expand Up @@ -2334,6 +2341,13 @@ def _is_variable_violation(
maybe_before_assign = defnode.value is node or any(
anc is defnode.value for anc in node.node_ancestors()
)
elif (
isinstance(defframe, nodes.ClassDef)
and defnode in defframe.type_params
):
# Generic on parent class:
# class Child[_T](Parent[_T])
maybe_before_assign = False

return maybe_before_assign, annotation_return, use_outer_definition

Expand Down
4 changes: 2 additions & 2 deletions tests/functional/g/generic_class_syntax_py312.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
class Entity[_T: float]:
last_update: int | None = None

def __init__(self, data: _T) -> None: # [undefined-variable] # false-positive
def __init__(self, data: _T) -> None:
self.data = data


Expand All @@ -28,6 +28,6 @@ def __init__(self):
self.update_interval = 0


class Child[_T](Parent[_T]): # [undefined-variable] # false-positive
class Child[_T](Parent[_T]):
def func(self):
self.update_interval = None
2 changes: 0 additions & 2 deletions tests/functional/g/generic_class_syntax_py312.txt

This file was deleted.

3 changes: 2 additions & 1 deletion tests/functional/u/undefined/undefined_variable_py312.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ def f[T](a: T) -> T:
print(a)

class ChildClass[T, *Ts, **P]:
...
def __init__(self, value: T):
self.value = value
Loading