diff --git a/mypy/main.py b/mypy/main.py index 6361e68b9403..188e8c2fcb9f 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -763,7 +763,7 @@ def add_invertible_flag(flag: str, search_paths = SearchPaths((os.getcwd(),), tuple(mypy_path() + options.mypy_path), (), ()) targets = [] # TODO: use the same cache that the BuildManager will - cache = FindModuleCache(search_paths, fscache) + cache = FindModuleCache(search_paths, fscache, options, special_opts.packages) for p in special_opts.packages: if os.sep in p or os.altsep and os.altsep in p: fail("Package name '{}' cannot have a slash in it.".format(p), diff --git a/mypy/modulefinder.py b/mypy/modulefinder.py index 1cbdf7a04604..f054319b5d54 100644 --- a/mypy/modulefinder.py +++ b/mypy/modulefinder.py @@ -64,7 +64,8 @@ class FindModuleCache: def __init__(self, search_paths: SearchPaths, fscache: Optional[FileSystemCache] = None, - options: Optional[Options] = None) -> None: + options: Optional[Options] = None, + ns_packages: Optional[List[str]] = None) -> None: self.search_paths = search_paths self.fscache = fscache or FileSystemCache() # Cache for get_toplevel_possibilities: @@ -74,6 +75,7 @@ def __init__(self, self.results = {} # type: Dict[str, Optional[str]] self.ns_ancestors = {} # type: Dict[str, str] self.options = options + self.ns_packages = ns_packages or [] # type: List[str] def clear(self) -> None: self.results.clear() @@ -307,6 +309,13 @@ def find_modules_recursive(self, module: str) -> List[BuildSource]: if mod not in hits: hits.add(mod) result += self.find_modules_recursive(module + '.' + mod) + elif os.path.isdir(module_path) and module in self.ns_packages: + # Even more subtler: handle recursive decent into PEP 420 + # namespace packages that are explicitly listed on the command + # line with -p/--packages. + for item in sorted(self.fscache.listdir(module_path)): + if os.path.isdir(os.path.join(module_path, item)): + result += self.find_modules_recursive(module + '.' + item) return result diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test index 0be634c9d2a9..3e24056e2d2b 100644 --- a/test-data/unit/cmdline.test +++ b/test-data/unit/cmdline.test @@ -1124,6 +1124,19 @@ p/a.py:4: error: Argument 1 to "foo" has incompatible type "str"; expected "int" p/b/__init__.py:5: error: Argument 1 to "bar" has incompatible type "str"; expected "int" c.py:2: error: Argument 1 to "bar" has incompatible type "str"; expected "int" +[case testSrcPEP420Packages] +# cmd: mypy -p anamespace --namespace-packages +[file mypy.ini] +[[mypy]] +mypy_path = src +[file src/setup.cfg] +[file src/anamespace/foo/__init__.py] +[file src/anamespace/foo/bar.py] +def bar(a: int, b: int) -> str: + return a + b +[out] +src/anamespace/foo/bar.py:2: error: Incompatible return value type (got "int", expected "str") + [case testFollowImportStubs1] # cmd: mypy main.py [file mypy.ini]