From 554f7f9d4fc03c8d76ae39977382802bc5cb77cf Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Sun, 3 Oct 2021 23:07:47 -0700 Subject: [PATCH] Fix case mismatching modules during namespace package search For example `from a import B` should not find a namespace package `a/B/`. Fix by using case aware isdir on fscache. --- mypy/fscache.py | 10 ++++++---- mypy/modulefinder.py | 2 +- test-data/unit/check-modules-case.test | 8 ++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/mypy/fscache.py b/mypy/fscache.py index 37f50f6228a4..0f60dc764499 100644 --- a/mypy/fscache.py +++ b/mypy/fscache.py @@ -220,12 +220,14 @@ def isfile_case(self, path: str, prefix: str) -> bool: res = False if res: # Also recursively check the other path components in case sensitive way. - res = self._exists_case(head, prefix) + res = self.exists_case(head, prefix) self.isfile_case_cache[path] = res return res - def _exists_case(self, path: str, prefix: str) -> bool: - """Helper to check path components in case sensitive fashion, up to prefix.""" + def exists_case(self, path: str, prefix: str) -> bool: + """Return whether path exists - checking path components in case sensitive + fashion, up to prefix. + """ if path in self.exists_case_cache: return self.exists_case_cache[path] head, tail = os.path.split(path) @@ -242,7 +244,7 @@ def _exists_case(self, path: str, prefix: str) -> bool: res = False if res: # Also recursively check other path components. - res = self._exists_case(head, prefix) + res = self.exists_case(head, prefix) self.exists_case_cache[path] = res return res diff --git a/mypy/modulefinder.py b/mypy/modulefinder.py index 78d2c6997b82..abcf99573434 100644 --- a/mypy/modulefinder.py +++ b/mypy/modulefinder.py @@ -373,7 +373,7 @@ def _find_module(self, id: str, use_typeshed: bool) -> ModuleSearchResult: # In namespace mode, register a potential namespace package if self.options and self.options.namespace_packages: - if fscache.isdir(base_path) and not has_init: + if fscache.exists_case(base_path, dir_prefix) and not has_init: near_misses.append((base_path, dir_prefix)) # No package, look for module. diff --git a/test-data/unit/check-modules-case.test b/test-data/unit/check-modules-case.test index bc2e91aacfdc..b9e48888fea3 100644 --- a/test-data/unit/check-modules-case.test +++ b/test-data/unit/check-modules-case.test @@ -1,6 +1,14 @@ -- Type checker test cases dealing with modules and imports on case-insensitive filesystems. [case testCaseSensitivityDir] +# flags: --no-namespace-packages +from a import B # E: Module "a" has no attribute "B" + +[file a/__init__.py] +[file a/b/__init__.py] + +[case testCaseSensitivityDirNamespacePackages] +# flags: --namespace-packages from a import B # E: Module "a" has no attribute "B" [file a/__init__.py]