Skip to content

Commit be59d58

Browse files
birthdaysgiftsigmavirus24pre-commit-ci[bot]
authored
Add linting for imports under if TYPE_CHECKING: block (#205)
* Add linting for imports under `if TYPE_CHECKING:` block * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Ian Stapleton Cordasco <graffatcolmingov@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 25df6e4 commit be59d58

27 files changed

+438
-5
lines changed

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ Limitations
7373
-----------
7474

7575
Currently these checks are limited to module scope imports only.
76-
Conditional imports in module scope will also be ignored.
76+
Conditional imports in module scope will be ignored except imports
77+
under ```if TYPE_CHECKING:``` block.
7778

7879
Classification of an imported module is achieved by checking the
7980
module against a stdlib list and then if there is no match against the

flake8_import_order/__init__.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,16 @@
3232

3333
ClassifiedImport = namedtuple(
3434
"ClassifiedImport",
35-
["type", "is_from", "modules", "names", "lineno", "level", "package"],
35+
[
36+
"type",
37+
"is_from",
38+
"modules",
39+
"names",
40+
"lineno",
41+
"level",
42+
"package",
43+
"type_checking",
44+
],
3645
)
3746
NewLine = namedtuple("NewLine", ["lineno"])
3847

@@ -85,8 +94,13 @@ def __init__(self, application_import_names, application_package_names):
8594
self.application_import_names = frozenset(application_import_names)
8695
self.application_package_names = frozenset(application_package_names)
8796

97+
def generic_visit(self, node):
98+
for child in ast.iter_child_nodes(node):
99+
child.parent = node
100+
return super().generic_visit(node)
101+
88102
def visit_Import(self, node): # noqa: N802
89-
if node.col_offset == 0:
103+
if node.col_offset == 0 or self._type_checking_import(node):
90104
modules = [alias.name for alias in node.names]
91105
types_ = {self._classify_type(module) for module in modules}
92106
if len(types_) == 1:
@@ -101,11 +115,12 @@ def visit_Import(self, node): # noqa: N802
101115
node.lineno,
102116
0,
103117
root_package_name(modules[0]),
118+
self._type_checking_import(node),
104119
)
105120
self.imports.append(classified_import)
106121

107122
def visit_ImportFrom(self, node): # noqa: N802
108-
if node.col_offset == 0:
123+
if node.col_offset == 0 or self._type_checking_import(node):
109124
module = node.module or ""
110125
if node.level > 0:
111126
type_ = ImportType.APPLICATION_RELATIVE
@@ -120,9 +135,16 @@ def visit_ImportFrom(self, node): # noqa: N802
120135
node.lineno,
121136
node.level,
122137
root_package_name(module),
138+
self._type_checking_import(node),
123139
)
124140
self.imports.append(classified_import)
125141

142+
def _type_checking_import(self, node):
143+
return (
144+
isinstance(node.parent, ast.If)
145+
and node.parent.test.id == "TYPE_CHECKING"
146+
)
147+
126148
def _classify_type(self, module):
127149
package_names = get_package_names(module)
128150

flake8_import_order/styles.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ def check(self):
4242
def _check(self, previous_import, previous, current_import):
4343
yield from self._check_I666(current_import)
4444
yield from self._check_I101(current_import)
45+
if (
46+
previous_import is not None
47+
and not previous_import.type_checking
48+
and current_import.type_checking
49+
):
50+
yield from self._check_I300(previous_import, current_import)
51+
previous_import = None
4552
if previous_import is not None:
4653
yield from self._check_I100(previous_import, current_import)
4754
yield from self._check_I201(
@@ -70,6 +77,14 @@ def _check_I101(self, current_import): # noqa: N802
7077
"Should be {}".format(corrected),
7178
)
7279

80+
def _check_I300(self, previous_import, current_import): # noqa: N802
81+
if current_import.lineno - previous_import.lineno != 3:
82+
yield Error(
83+
current_import.lineno,
84+
"I300",
85+
"TYPE_CHECKING block should have one newline above.",
86+
)
87+
7388
def _check_I100(self, previous_import, current_import): # noqa: N802
7489
previous_key = self.import_key(previous_import)
7590
current_key = self.import_key(current_import)

tests/test_cases/additional_newline.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,28 @@
2222
from . import A
2323

2424
from . import B # I202
25+
26+
if TYPE_CHECKING:
27+
import ast
28+
# This comment should not trigger a I202 (not a newline)
29+
import os
30+
31+
import signal # I202
32+
33+
import X
34+
from X import B, b, \
35+
C, d
36+
37+
from Y import A # I202
38+
from Y import (
39+
B, b,
40+
C, d,
41+
)
42+
from Z import A
43+
44+
import flake8_import_order
45+
46+
import tests # I202
47+
from . import A
48+
49+
from . import B # I202

tests/test_cases/additional_newline_cryptography.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,20 @@
1414
from . import A
1515

1616
from . import B # I202
17+
18+
if TYPE_CHECKING:
19+
import ast
20+
21+
import signal # I202
22+
23+
import X
24+
25+
import Y
26+
27+
import flake8_import_order
28+
29+
import tests
30+
31+
from . import A
32+
33+
from . import B # I202

tests/test_cases/additional_newline_edited.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,29 @@
2323
from . import A
2424

2525
from . import B # I202
26+
27+
if TYPE_CHECKING:
28+
import ast
29+
# This comment should not trigger a I202 (not a newline)
30+
import os
31+
32+
import signal # I202
33+
34+
import X
35+
from X import B, b, \
36+
C, d
37+
38+
from Y import A # I202
39+
from Y import (
40+
B, b,
41+
C, d,
42+
)
43+
from Z import A
44+
45+
import flake8_import_order
46+
47+
import tests # I202
48+
49+
from . import A
50+
51+
from . import B # I202

tests/test_cases/complete_appnexus.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,38 @@
3232
from .. import B
3333
from ..A import A
3434
from ..B import B
35+
36+
if TYPE_CHECKING:
37+
import ast
38+
from functools import *
39+
import os
40+
from os import path
41+
import StringIO
42+
import sys
43+
44+
import X
45+
from X import *
46+
from X import A
47+
from X import B, b, C, d
48+
import Y
49+
from Y import *
50+
from Y import A
51+
from Y import B, C, D
52+
from Y import e
53+
import Z
54+
from Z import A
55+
from Z.A import A
56+
from Z.A.B import A
57+
58+
from localpackage import A, b
59+
60+
import flake8_import_order
61+
from flake8_import_order import *
62+
from . import A
63+
from . import B
64+
from .A import A
65+
from .B import B
66+
from .. import A
67+
from .. import B
68+
from ..A import A
69+
from ..B import B

tests/test_cases/complete_cryptography.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,45 @@
4040
from .. import B
4141
from ..A import A
4242
from ..B import B
43+
44+
if TYPE_CHECKING:
45+
import ast
46+
import os
47+
import sys
48+
from functools import *
49+
from os import path
50+
51+
import X
52+
from X import *
53+
from X import A
54+
from X import B, C, D
55+
56+
import Y
57+
from Y import *
58+
from Y import A
59+
from Y import B, C, D
60+
61+
import Z
62+
from Z import A
63+
from Z.A import A
64+
from Z.A.B import A
65+
66+
import localpackage
67+
68+
import flake8_import_order
69+
from flake8_import_order import *
70+
from flake8_import_order import A
71+
from flake8_import_order import B
72+
73+
import tests
74+
from tests import A
75+
from tests import B
76+
77+
from . import A
78+
from . import B
79+
from .A import A
80+
from .B import B
81+
from .. import A
82+
from .. import B
83+
from ..A import A
84+
from ..B import B

tests/test_cases/complete_edited.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,41 @@
3535
from .. import B
3636
from ..A import A
3737
from ..B import B
38+
39+
if TYPE_CHECKING:
40+
import ast
41+
import os
42+
import StringIO
43+
import sys
44+
from functools import *
45+
from os import path
46+
47+
import X
48+
import Y
49+
import Z
50+
from X import *
51+
from X import A
52+
from X import B, b, C, d
53+
from Y import *
54+
from Y import A
55+
from Y import B, C, D
56+
from Y import e
57+
from Z import A
58+
from Z.A import A
59+
from Z.A.B import A
60+
61+
import localpackage
62+
63+
from localpackage import A, b
64+
65+
import flake8_import_order
66+
from flake8_import_order import *
67+
68+
from . import A
69+
from . import B
70+
from .A import A
71+
from .B import B
72+
from .. import A
73+
from .. import B
74+
from ..A import A
75+
from ..B import B

tests/test_cases/complete_google.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,37 @@
3131
from .. import B
3232
from ..A import A
3333
from ..B import B
34+
35+
if TYPE_CHECKING:
36+
import ast
37+
from functools import *
38+
import os
39+
from os import path
40+
import StringIO
41+
import sys
42+
43+
import localpackage
44+
import X
45+
from X import *
46+
from X import A
47+
from X import B, b, C, d
48+
import Y
49+
from Y import *
50+
from Y import A
51+
from Y import B, C, D
52+
from Y import e
53+
import Z
54+
from Z import A
55+
from Z.A import A
56+
from Z.A.B import A
57+
58+
import flake8_import_order
59+
from flake8_import_order import *
60+
from . import A
61+
from . import B
62+
from .A import A
63+
from .B import B
64+
from .. import A
65+
from .. import B
66+
from ..A import A
67+
from ..B import B

0 commit comments

Comments
 (0)