Skip to content

Commit 56f8cf2

Browse files
committed
improve test coverage and documentation
1 parent 8263868 commit 56f8cf2

File tree

6 files changed

+165
-1
lines changed

6 files changed

+165
-1
lines changed

docs/source/command_line.rst

+23
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,29 @@ imports.
212212
By default, mypy will suppress any error messages generated within :pep:`561`
213213
compliant packages. Adding this flag will disable this behavior.
214214

215+
.. option:: --fast-module-lookup
216+
217+
The default logic used to scan through search paths to resolve imports has a
218+
quadratic worse-case behavior in some cases, which is for instance triggered
219+
by a large number of folders sharing a top-level namespace as in:
220+
221+
foo/
222+
company/
223+
foo/
224+
a.py
225+
bar/
226+
company/
227+
bar/
228+
b.py
229+
baz/
230+
company/
231+
baz/
232+
c.py
233+
...
234+
235+
If you are in this situation, you can enable an experimental fast path by
236+
setting the :option:`--fast-module-lookup` option.
237+
215238

216239
.. _platform-configuration:
217240

docs/source/running_mypy.rst

+1
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ same directory on the search path, only the stub file is used.
516516
(However, if the files are in different directories, the one found
517517
in the earlier directory is used.)
518518

519+
519520
Other advice and best practices
520521
*******************************
521522

mypy/main.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,7 @@ def add_invertible_flag(flag: str,
883883
group=code_group)
884884
add_invertible_flag(
885885
'--fast-module-lookup', default=False,
886-
help="Enable fast path for finding modules within input sources",
886+
help=argparse.SUPPRESS,
887887
group=code_group)
888888
code_group.add_argument(
889889
"--exclude",

mypy/modulefinder.py

+3
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ def clear(self) -> None:
195195
self.ns_ancestors.clear()
196196

197197
def find_module_via_source_set(self, id: str) -> Optional[ModuleSearchResult]:
198+
"""Fast path to find modules by looking through the input sources
199+
200+
This is only used when --fast-module-lookup is passed on the command line."""
198201
if not self.source_set:
199202
return None
200203

mypy/test/testcheck.py

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
'check-multiple-inheritance.test',
4747
'check-super.test',
4848
'check-modules.test',
49+
'check-modules-fast.test',
4950
'check-typevar-values.test',
5051
'check-unsupported.test',
5152
'check-unreachable-code.test',
+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
-- Type checker test cases dealing with module lookup edge cases
2+
-- to ensure that --fast-module-lookup matches regular lookup behavior
3+
4+
[case testModuleLookup]
5+
# flags: --fast-module-lookup
6+
import m
7+
reveal_type(m.a) # N: Revealed type is "m.A"
8+
9+
[file m.py]
10+
class A: pass
11+
a = A()
12+
13+
[case testModuleLookupStub]
14+
# flags: --fast-module-lookup
15+
import m
16+
reveal_type(m.a) # N: Revealed type is "m.A"
17+
18+
[file m.pyi]
19+
class A: pass
20+
a = A()
21+
22+
[case testModuleLookupFromImport]
23+
# flags: --fast-module-lookup
24+
from m import a
25+
reveal_type(a) # N: Revealed type is "m.A"
26+
27+
[file m.py]
28+
class A: pass
29+
a = A()
30+
31+
[case testModuleLookupStubFromImport]
32+
# flags: --fast-module-lookup
33+
from m import a
34+
reveal_type(a) # N: Revealed type is "m.A"
35+
36+
[file m.pyi]
37+
class A: pass
38+
a = A()
39+
40+
41+
[case testModuleLookupWeird]
42+
# flags: --fast-module-lookup
43+
from m import a
44+
reveal_type(a) # N: Revealed type is "builtins.object"
45+
reveal_type(a.b) # N: Revealed type is "m.a.B"
46+
47+
[file m.py]
48+
class A: pass
49+
a = A()
50+
51+
[file m/__init__.py]
52+
[file m/a.py]
53+
class B: pass
54+
b = B()
55+
56+
57+
[case testModuleLookupWeird2]
58+
# flags: --fast-module-lookup
59+
from m.a import b
60+
reveal_type(b) # N: Revealed type is "m.a.B"
61+
62+
[file m.py]
63+
class A: pass
64+
a = A()
65+
66+
[file m/__init__.py]
67+
[file m/a.py]
68+
class B: pass
69+
b = B()
70+
71+
72+
[case testModuleLookupWeird3]
73+
# flags: --fast-module-lookup
74+
from m.a import b
75+
reveal_type(b) # N: Revealed type is "m.a.B"
76+
77+
[file m.py]
78+
class A: pass
79+
a = A()
80+
[file m/__init__.py]
81+
class B: pass
82+
a = B()
83+
[file m/a.py]
84+
class B: pass
85+
b = B()
86+
87+
88+
[case testModuleLookupWeird4]
89+
# flags: --fast-module-lookup
90+
import m.a
91+
m.a.b # E: "str" has no attribute "b"
92+
93+
[file m.py]
94+
class A: pass
95+
a = A()
96+
[file m/__init__.py]
97+
class B: pass
98+
a = 'foo'
99+
b = B()
100+
[file m/a.py]
101+
class C: pass
102+
b = C()
103+
104+
105+
[case testModuleLookupWeird5]
106+
# flags: --fast-module-lookup
107+
import m.a as ma
108+
reveal_type(ma.b) # N: Revealed type is "m.a.C"
109+
110+
[file m.py]
111+
class A: pass
112+
a = A()
113+
[file m/__init__.py]
114+
class B: pass
115+
a = 'foo'
116+
b = B()
117+
[file m/a.py]
118+
class C: pass
119+
b = C()
120+
121+
122+
[case testModuleLookupWeird6]
123+
# flags: --fast-module-lookup
124+
from m.a import b
125+
reveal_type(b) # N: Revealed type is "m.a.C"
126+
127+
[file m.py]
128+
class A: pass
129+
a = A()
130+
[file m/__init__.py]
131+
class B: pass
132+
a = 'foo'
133+
b = B()
134+
[file m/a.py]
135+
class C: pass
136+
b = C()

0 commit comments

Comments
 (0)