Skip to content

Commit df5ebb5

Browse files
jacobtylerwallsPierre-Sassoulas
authored andcommitted
Fix used-before-assignment for variable annotations guarded by TYPE_CHECKING (#7810)
1 parent 1baf4be commit df5ebb5

File tree

4 files changed

+39
-8
lines changed

4 files changed

+39
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix a false positive for ``used-before-assignment`` for imports guarded by
2+
``typing.TYPE_CHECKING`` later used in variable annotations.
3+
4+
Closes #7609

pylint/checkers/variables.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -1998,12 +1998,22 @@ def _is_variable_violation(
19981998
)
19991999

20002000
# Look for type checking definitions inside a type checking guard.
2001-
if isinstance(defstmt, (nodes.Import, nodes.ImportFrom)):
2001+
# Relevant for function annotations only, not variable annotations (AnnAssign)
2002+
if (
2003+
isinstance(defstmt, (nodes.Import, nodes.ImportFrom))
2004+
and isinstance(defstmt.parent, nodes.If)
2005+
and defstmt.parent.test.as_string() in TYPING_TYPE_CHECKS_GUARDS
2006+
):
20022007
defstmt_parent = defstmt.parent
20032008

2004-
if (
2005-
isinstance(defstmt_parent, nodes.If)
2006-
and defstmt_parent.test.as_string() in TYPING_TYPE_CHECKS_GUARDS
2009+
maybe_annotation = utils.get_node_first_ancestor_of_type(
2010+
node, nodes.AnnAssign
2011+
)
2012+
if not (
2013+
maybe_annotation
2014+
and utils.get_node_first_ancestor_of_type(
2015+
maybe_annotation, nodes.FunctionDef
2016+
)
20072017
):
20082018
# Exempt those definitions that are used inside the type checking
20092019
# guard or that are defined in both type checking guard branches.

tests/functional/u/used/used_before_assignment_typing.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
# pylint: disable=missing-function-docstring
33

44

5-
from typing import List, Optional
5+
from typing import List, Optional, TYPE_CHECKING
66

7+
if TYPE_CHECKING:
8+
import datetime
79

810
class MyClass:
911
"""Type annotation or default values for first level methods can't refer to their own class"""
@@ -74,3 +76,17 @@ def function(self, var: int) -> None:
7476

7577
def other_function(self) -> None:
7678
_x: MyThirdClass = self
79+
80+
81+
class VariableAnnotationsGuardedByTypeChecking: # pylint: disable=too-few-public-methods
82+
"""Class to test conditional imports guarded by TYPE_CHECKING then used in
83+
local (function) variable annotations, which are not evaluated at runtime.
84+
85+
See: https://github.com/PyCQA/pylint/issues/7609
86+
"""
87+
88+
still_an_error: datetime.date # [used-before-assignment]
89+
90+
def print_date(self, date) -> None:
91+
date: datetime.date = date
92+
print(date)
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
undefined-variable:12:21:12:28:MyClass.incorrect_typing_method:Undefined variable 'MyClass':UNDEFINED
2-
undefined-variable:17:26:17:33:MyClass.incorrect_nested_typing_method:Undefined variable 'MyClass':UNDEFINED
3-
undefined-variable:22:20:22:27:MyClass.incorrect_default_method:Undefined variable 'MyClass':UNDEFINED
1+
undefined-variable:14:21:14:28:MyClass.incorrect_typing_method:Undefined variable 'MyClass':UNDEFINED
2+
undefined-variable:19:26:19:33:MyClass.incorrect_nested_typing_method:Undefined variable 'MyClass':UNDEFINED
3+
undefined-variable:24:20:24:27:MyClass.incorrect_default_method:Undefined variable 'MyClass':UNDEFINED
4+
used-before-assignment:88:20:88:28:VariableAnnotationsGuardedByTypeChecking:Using variable 'datetime' before assignment:HIGH

0 commit comments

Comments
 (0)