Skip to content

Commit 7e44744

Browse files
jacobtylerwallsPierre-Sassoulas
authored andcommitted
Prevent unused-import for if t.TYPE_CHECKING
1 parent ac6615a commit 7e44744

File tree

4 files changed

+66
-10
lines changed

4 files changed

+66
-10
lines changed

doc/whatsnew/2/2.14/full.rst

+10
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ Release date: TBA
2222

2323
Closes #6802
2424

25+
* Fixed false positives for ``unused-import`` when aliasing ``typing`` e.g. as ``t``
26+
and guarding imports under ``t.TYPE_CHECKING``.
27+
28+
Closes #3846
29+
30+
* Fixed a false positive regression in 2.13 for ``used-before-assignment`` where it is safe to rely
31+
on a name defined only in an ``except`` block because the ``else`` block returned.
32+
33+
Closes #6790
34+
2535
* Fixed the use of abbreviations for some special options on the command line.
2636

2737
Closes #6810

pylint/checkers/utils.py

+28-8
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
from astroid.context import InferenceContext
2424
from astroid.exceptions import AstroidError
2525

26-
from pylint.constants import TYPING_TYPE_CHECKS_GUARDS
27-
2826
if TYPE_CHECKING:
2927
from pylint.checkers import BaseChecker
3028

@@ -1778,12 +1776,34 @@ def get_node_first_ancestor_of_type_and_its_child(
17781776

17791777

17801778
def in_type_checking_block(node: nodes.NodeNG) -> bool:
1781-
"""Check if a node is guarded by a TYPE_CHECKS guard."""
1782-
return any(
1783-
isinstance(ancestor, nodes.If)
1784-
and ancestor.test.as_string() in TYPING_TYPE_CHECKS_GUARDS
1785-
for ancestor in node.node_ancestors()
1786-
)
1779+
"""Check if a node is guarded by a TYPE_CHECKING guard."""
1780+
for ancestor in node.node_ancestors():
1781+
if not isinstance(ancestor, nodes.If):
1782+
continue
1783+
if isinstance(ancestor.test, nodes.Name):
1784+
if ancestor.test.name != "TYPE_CHECKING":
1785+
continue
1786+
maybe_import_from = ancestor.test.lookup(ancestor.test.name)[1][0]
1787+
if (
1788+
isinstance(maybe_import_from, nodes.ImportFrom)
1789+
and maybe_import_from.modname == "typing"
1790+
):
1791+
return True
1792+
inferred = safe_infer(ancestor.test)
1793+
if isinstance(inferred, nodes.Const) and inferred.value is False:
1794+
return True
1795+
elif isinstance(ancestor.test, nodes.Attribute):
1796+
if ancestor.test.attrname != "TYPE_CHECKING":
1797+
continue
1798+
inferred_module = safe_infer(ancestor.test.expr)
1799+
if (
1800+
isinstance(inferred_module, nodes.Module)
1801+
and inferred_module.name == "typing"
1802+
and inferred_module.pytype() == "builtins.module"
1803+
):
1804+
return True
1805+
1806+
return False
17871807

17881808

17891809
@lru_cache()

tests/functional/u/unused/unused_import.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,18 @@ class SomeClass(object):
1717
SomeOtherName = SomeOtherName
1818

1919
from never import __all__
20-
# pylint: disable=wrong-import-order,ungrouped-imports
20+
# pylint: disable=wrong-import-order,ungrouped-imports,reimported
2121
import typing
2222
from typing import TYPE_CHECKING
23+
import typing as t
2324

2425

2526
if typing.TYPE_CHECKING:
2627
import collections
2728
if TYPE_CHECKING:
2829
import itertools
30+
if t.TYPE_CHECKING:
31+
import xml
2932

3033

3134
def get_ordered_dict() -> 'collections.OrderedDict':
@@ -65,3 +68,22 @@ def blop(self):
6568
if TYPE_CHECKING:
6669
if sys.version_info >= (3, 6, 2):
6770
from typing import NoReturn
71+
72+
# Pathological cases
73+
from io import TYPE_CHECKING # pylint: disable=no-name-in-module
74+
import trace as t
75+
import astroid as typing
76+
TYPE_CHECKING = "red herring"
77+
78+
if TYPE_CHECKING:
79+
import unittest # [unused-import]
80+
if t.TYPE_CHECKING: # pylint: disable=no-member
81+
import uuid # [unused-import]
82+
if typing.TYPE_CHECKING: # pylint: disable=no-member
83+
import warnings # [unused-import]
84+
if typing.TYPE_CHECKING_WITH_MAGIC: # pylint: disable=no-member
85+
import compileall # [unused-import]
86+
87+
TYPE_CHECKING = False
88+
if TYPE_CHECKING:
89+
import zoneinfo

tests/functional/u/unused/unused_import.txt

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@ unused-import:9:0:9:51::Unused OrderedDict imported from collections:UNDEFINED
77
unused-import:9:0:9:51::Unused deque imported from collections:UNDEFINED
88
unused-import:10:0:10:22::Unused import re:UNDEFINED
99
unused-import:13:0:13:40::Unused SomeOtherName imported from fake:UNDEFINED
10-
unused-import:45:0:45:9::Unused import os:UNDEFINED
10+
unused-import:48:0:48:9::Unused import os:UNDEFINED
11+
unused-import:79:4:79:19::Unused import unittest:UNDEFINED
12+
unused-import:81:4:81:15::Unused import uuid:UNDEFINED
13+
unused-import:83:4:83:19::Unused import warnings:UNDEFINED
14+
unused-import:85:4:85:21::Unused import compileall:UNDEFINED

0 commit comments

Comments
 (0)