8
8
from mypy .modulefinder import BuildSource , PYTHON_EXTENSIONS
9
9
from mypy .fscache import FileSystemCache
10
10
from mypy .options import Options
11
+ from mypy .util import normalise_package_root
11
12
12
13
PY_EXTENSIONS = tuple (PYTHON_EXTENSIONS ) # type: Final
13
14
@@ -24,7 +25,7 @@ def create_source_list(paths: Sequence[str], options: Options,
24
25
Raises InvalidSourceList on errors.
25
26
"""
26
27
fscache = fscache or FileSystemCache ()
27
- finder = SourceFinder (fscache )
28
+ finder = SourceFinder (fscache , explicit_package_roots = options . package_root or None )
28
29
29
30
sources = []
30
31
for path in paths :
@@ -34,7 +35,7 @@ def create_source_list(paths: Sequence[str], options: Options,
34
35
name , base_dir = finder .crawl_up (path )
35
36
sources .append (BuildSource (path , name , None , base_dir ))
36
37
elif fscache .isdir (path ):
37
- sub_sources = finder .find_sources_in_dir (path , explicit_package_roots = None )
38
+ sub_sources = finder .find_sources_in_dir (path )
38
39
if not sub_sources and not allow_empty_dir :
39
40
raise InvalidSourceList (
40
41
"There are no .py[i] files in directory '{}'" .format (path )
@@ -59,26 +60,26 @@ def keyfunc(name: str) -> Tuple[int, str]:
59
60
60
61
61
62
class SourceFinder :
62
- def __init__ (self , fscache : FileSystemCache ) -> None :
63
+ def __init__ (self , fscache : FileSystemCache , explicit_package_roots : Optional [ List [ str ]] ) -> None :
63
64
self .fscache = fscache
64
- # A cache for package names, mapping from directory path to module id and base dir
65
- self .package_cache = {} # type: Dict[str, Tuple[str, str]]
65
+ self .explicit_package_roots = explicit_package_roots
66
66
67
- def find_sources_in_dir (
68
- self , path : str , explicit_package_roots : Optional [List [str ]]
69
- ) -> List [BuildSource ]:
70
- if explicit_package_roots is None :
67
+ def is_package_root (self , path : str ) -> bool :
68
+ assert self .explicit_package_roots
69
+ return normalise_package_root (path ) in self .explicit_package_roots
70
+
71
+ def find_sources_in_dir (self , path : str ) -> List [BuildSource ]:
72
+ if self .explicit_package_roots is None :
71
73
mod_prefix , root_dir = self .crawl_up_dir (path )
72
74
else :
73
75
mod_prefix = os .path .basename (path )
74
76
root_dir = os .path .dirname (path ) or "."
75
77
if mod_prefix :
76
78
mod_prefix += "."
77
- return self .find_sources_in_dir_helper (path , mod_prefix , root_dir , explicit_package_roots )
79
+ return self .find_sources_in_dir_helper (path , mod_prefix , root_dir )
78
80
79
81
def find_sources_in_dir_helper (
80
- self , dir_path : str , mod_prefix : str , root_dir : str ,
81
- explicit_package_roots : Optional [List [str ]]
82
+ self , dir_path : str , mod_prefix : str , root_dir : str
82
83
) -> List [BuildSource ]:
83
84
assert not mod_prefix or mod_prefix .endswith ("." )
84
85
@@ -87,8 +88,8 @@ def find_sources_in_dir_helper(
87
88
# Alternatively, if we aren't given explicit package roots and we don't have an __init__
88
89
# file, recursively explore this directory as a new package root.
89
90
if (
90
- (explicit_package_roots is not None and dir_path in explicit_package_roots )
91
- or (explicit_package_roots is None and init_file is None )
91
+ (self . explicit_package_roots is not None and self . is_package_root ( dir_path ) )
92
+ or (self . explicit_package_roots is None and init_file is None )
92
93
):
93
94
mod_prefix = ""
94
95
root_dir = dir_path
@@ -109,7 +110,7 @@ def find_sources_in_dir_helper(
109
110
110
111
if self .fscache .isdir (path ):
111
112
sub_sources = self .find_sources_in_dir_helper (
112
- path , mod_prefix + name + '.' , root_dir , explicit_package_roots
113
+ path , mod_prefix + name + '.' , root_dir
113
114
)
114
115
if sub_sources :
115
116
seen .add (name )
@@ -126,10 +127,12 @@ def find_sources_in_dir_helper(
126
127
return sources
127
128
128
129
def crawl_up (self , path : str ) -> Tuple [str , str ]:
129
- """Given a .py[i] filename, return module and base directory
130
+ """Given a .py[i] filename, return module and base directory.
130
131
131
- We crawl up the path until we find a directory without
132
- __init__.py[i], or until we run out of path components.
132
+ If we are given explicit package roots, we crawl up until we find one (or run out of
133
+ path components).
134
+
135
+ Otherwise, we crawl up the path until we find an directory without __init__.py[i]
133
136
"""
134
137
parent , filename = os .path .split (path )
135
138
module_name = strip_py (filename ) or os .path .basename (filename )
@@ -142,27 +145,30 @@ def crawl_up(self, path: str) -> Tuple[str, str]:
142
145
return module , base_dir
143
146
144
147
def crawl_up_dir (self , dir : str ) -> Tuple [str , str ]:
145
- """Given a directory name, return the corresponding module name and base directory
146
-
147
- Use package_cache to cache results.
148
- """
149
- if dir in self .package_cache :
150
- return self .package_cache [dir ]
151
-
148
+ """Given a directory name, return the corresponding module name and base directory."""
152
149
parent_dir , base = os .path .split (dir )
153
- if not dir or not self . get_init_file ( dir ) or not base :
150
+ if not dir or not base :
154
151
module = ''
155
152
base_dir = dir or '.'
156
- else :
157
- # Ensure that base is a valid python module name
158
- if base .endswith ('-stubs' ):
159
- base = base [:- 6 ] # PEP-561 stub-only directory
160
- if not base .isidentifier ():
161
- raise InvalidSourceList ('{} is not a valid Python package name' .format (base ))
162
- parent_module , base_dir = self .crawl_up_dir (parent_dir )
163
- module = module_join (parent_module , base )
164
-
165
- self .package_cache [dir ] = module , base_dir
153
+ return module , base_dir
154
+
155
+ if self .explicit_package_roots is None and not self .get_init_file (dir ):
156
+ module = ''
157
+ base_dir = dir or '.'
158
+ return module , base_dir
159
+
160
+ # Ensure that base is a valid python module name
161
+ if base .endswith ('-stubs' ):
162
+ base = base [:- 6 ] # PEP-561 stub-only directory
163
+ if not base .isidentifier ():
164
+ raise InvalidSourceList ('{} is not a valid Python package name' .format (base ))
165
+
166
+ if self .explicit_package_roots is not None :
167
+ if self .is_package_root (parent_dir ):
168
+ return base , parent_dir
169
+
170
+ parent_module , base_dir = self .crawl_up_dir (parent_dir )
171
+ module = module_join (parent_module , base )
166
172
return module , base_dir
167
173
168
174
def get_init_file (self , dir : str ) -> Optional [str ]:
@@ -176,8 +182,6 @@ def get_init_file(self, dir: str) -> Optional[str]:
176
182
f = os .path .join (dir , '__init__' + ext )
177
183
if self .fscache .isfile (f ):
178
184
return f
179
- if ext == '.py' and self .fscache .init_under_package_root (f ):
180
- return f
181
185
return None
182
186
183
187
0 commit comments