From 380006adbc6eb24e4b8029460a9956aa287e4ddb Mon Sep 17 00:00:00 2001 From: macbeth322 Date: Sat, 8 Sep 2018 22:29:33 -0400 Subject: [PATCH 1/6] support loading type hints from nested packages --- mypy/build.py | 29 +++++-- mypy/test/testpep561.py | 80 +++++++++++++++++++ .../macbeth_namespace/__init__.py | 2 + .../inside_namespace_package/__init__.py | 0 .../namespace_module.py | 2 + .../inside_namespace_package/py.typed | 0 test-data/packages/macbeth_namespace/setup.py | 9 +++ .../macbeth_nested/macbeth_nested/__init__.py | 0 .../macbeth_nested/nested_package/__init__.py | 0 .../nested_package/nested_module.py | 2 + .../macbeth_nested/nested_package/py.typed | 0 test-data/packages/macbeth_nested/setup.py | 9 +++ 12 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 test-data/packages/macbeth_namespace/macbeth_namespace/__init__.py create mode 100644 test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/__init__.py create mode 100644 test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/namespace_module.py create mode 100644 test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/py.typed create mode 100644 test-data/packages/macbeth_namespace/setup.py create mode 100644 test-data/packages/macbeth_nested/macbeth_nested/__init__.py create mode 100644 test-data/packages/macbeth_nested/macbeth_nested/nested_package/__init__.py create mode 100644 test-data/packages/macbeth_nested/macbeth_nested/nested_package/nested_module.py create mode 100644 test-data/packages/macbeth_nested/macbeth_nested/nested_package/py.typed create mode 100644 test-data/packages/macbeth_nested/setup.py diff --git a/mypy/build.py b/mypy/build.py index 080f7e5527a4..a542a918e5ef 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -895,6 +895,19 @@ def find_module(self, id: str, search_paths: SearchPaths, self.results[key] = self._find_module(id, search_paths, python_executable) return self.results[key] + def _find_module_non_stub_helper( + self, + components: List[str], + pkg_dir: str + ) -> Optional[str]: + fscache = self.fscache + for count in range(len(components)): + typed_file = os.path.join(pkg_dir, *components[:count+1], 'py.typed') + _print('BETA ', typed_file) + if fscache.isfile(typed_file): + return os.path.join(pkg_dir, *components[:-1]) + return None + def _find_module(self, id: str, search_paths: SearchPaths, python_executable: Optional[str]) -> Optional[str]: fscache = self.fscache @@ -934,9 +947,12 @@ def _find_module(self, id: str, search_paths: SearchPaths, third_party_stubs_dirs.append((path, False)) else: third_party_stubs_dirs.append((path, True)) - elif fscache.isfile(typed_file): - path = os.path.join(pkg_dir, dir_chain) - third_party_inline_dirs.append((path, True)) + non_stub_match = self._find_module_non_stub_helper( + components, + pkg_dir + ) + if non_stub_match: + third_party_inline_dirs.append((non_stub_match, True)) if self.options and self.options.use_builtins_fixtures: # Everything should be in fixtures. third_party_inline_dirs.clear() @@ -2356,11 +2372,13 @@ def find_module_and_diagnose(manager: BuildManager, if not (options.ignore_missing_imports or in_partial_package(id, manager)): module_not_found(manager, caller_line, caller_state, id) raise ModuleNotFound - else: + elif root_source: # If we can't find a root source it's always fatal. # TODO: This might hide non-fatal errors from # root sources processed earlier. raise CompileError(["mypy: can't find module '%s'" % id]) + else: + raise ModuleNotFound def exist_added_packages(suppressed: List[str], @@ -2678,7 +2696,8 @@ def load_graph(sources: List[BuildSource], manager: BuildManager, # they will be taken care of during fine grained update. See also # comment about this in `State.__init__()`. added = [] - for dep in st.ancestors + dependencies + st.suppressed: + all_deps_to_check = st.ancestors + dependencies + st.suppressed + for dep in all_deps_to_check: ignored = dep in st.suppressed and dep not in entry_points if ignored and dep not in added: manager.missing_modules.add(dep) diff --git a/mypy/test/testpep561.py b/mypy/test/testpep561.py index f0adc78e8b3b..3166845ac86d 100644 --- a/mypy/test/testpep561.py +++ b/mypy/test/testpep561.py @@ -21,6 +21,17 @@ reveal_type(a) """ +NAMESPACE_PROGRAM = """ +from macbeth_nested.nested_package.nested_module import nested_func +from macbeth_namespace.inside_namespace_package.namespace_module import namespace_func + +nested_func("abc") +namespace_func(False) + +nested_func(False) +namespace_func(2) +""" + def check_mypy_run(cmd_line: List[str], python_executable: str = sys.executable, @@ -192,6 +203,75 @@ def test_typedpkg_editable(self) -> None: venv_dir=venv_dir, ) +class TestPEP561Namespace(TestCase): + + @contextmanager + def virtualenv(self, + python_executable: str = sys.executable + ) -> Generator[Tuple[str, str], None, None]: + """Context manager that creates a virtualenv in a temporary directory + + returns the path to the created Python executable""" + # Sadly, we need virtualenv, as the Python 3 venv module does not support creating a venv + # for Python 2, and Python 2 does not have its own venv. + with tempfile.TemporaryDirectory() as venv_dir: + returncode, lines = run_command([sys.executable, + '-m', + 'virtualenv', + '-p{}'.format(python_executable), + venv_dir], cwd=os.getcwd()) + if returncode != 0: + err = '\n'.join(lines) + self.fail("Failed to create venv. Do you have virtualenv installed?\n" + err) + if sys.platform == 'win32': + yield venv_dir, os.path.abspath(os.path.join(venv_dir, 'Scripts', 'python')) + else: + yield venv_dir, os.path.abspath(os.path.join(venv_dir, 'bin', 'python')) + + def install_package(self, pkg: str, + python_executable: str = sys.executable, + use_pip: bool = True, + editable: bool = False) -> None: + """Context manager to temporarily install a package from test-data/packages/pkg/""" + working_dir = os.path.join(package_path, pkg) + if use_pip: + install_cmd = [python_executable, '-m', 'pip', 'install'] + if editable: + install_cmd.append('-e') + install_cmd.append('.') + else: + install_cmd = [python_executable, 'setup.py'] + if editable: + install_cmd.append('develop') + else: + install_cmd.append('install') + returncode, lines = run_command(install_cmd, cwd=working_dir) + if returncode != 0: + self.fail('\n'.join(lines)) + + def setUp(self) -> None: + self.temp_file_dir = tempfile.TemporaryDirectory() + self.tempfile = os.path.join(self.temp_file_dir.name, 'namespace_program.py') + with open(self.tempfile, 'w+') as file: + file.write(NAMESPACE_PROGRAM) + self.msg_bool_str = '{0}:8: error: Argument 1 to "nested_func" has incompatible type "bool"; expected "str"\n'.format(self.tempfile) + self.msg_int_bool = '{0}:9: error: Argument 1 to "namespace_func" has incompatible type "int"; expected "bool"\n'.format(self.tempfile) + + def tearDown(self) -> None: + self.temp_file_dir.cleanup() + + def test_nested_and_namespace(self) -> None: + with self.virtualenv() as venv: + venv_dir, python_executable = venv + self.install_package('macbeth_nested', python_executable) + self.install_package('macbeth_namespace', python_executable) + check_mypy_run( + [self.tempfile], + python_executable, + expected_out=self.msg_bool_str+self.msg_int_bool, + venv_dir=venv_dir, + ) + if __name__ == '__main__': main() diff --git a/test-data/packages/macbeth_namespace/macbeth_namespace/__init__.py b/test-data/packages/macbeth_namespace/macbeth_namespace/__init__.py new file mode 100644 index 000000000000..3ac255b8a577 --- /dev/null +++ b/test-data/packages/macbeth_namespace/macbeth_namespace/__init__.py @@ -0,0 +1,2 @@ +# namespace pkg +__import__("pkg_resources").declare_namespace(__name__) diff --git a/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/__init__.py b/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/namespace_module.py b/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/namespace_module.py new file mode 100644 index 000000000000..e63a2ee6e281 --- /dev/null +++ b/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/namespace_module.py @@ -0,0 +1,2 @@ +def namespace_func(a: bool) -> bool: + return not a diff --git a/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/py.typed b/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/py.typed new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/macbeth_namespace/setup.py b/test-data/packages/macbeth_namespace/setup.py new file mode 100644 index 000000000000..2dd6ce646a00 --- /dev/null +++ b/test-data/packages/macbeth_namespace/setup.py @@ -0,0 +1,9 @@ +from setuptools import setup, find_packages + +setup( + name='macbeth_namespace', + version='1.0.0', + packages=find_packages(), + zip_safe=False, + package_data={'macbeth_namespace.inside_namespace_package': ['py.typed']} +) diff --git a/test-data/packages/macbeth_nested/macbeth_nested/__init__.py b/test-data/packages/macbeth_nested/macbeth_nested/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/macbeth_nested/macbeth_nested/nested_package/__init__.py b/test-data/packages/macbeth_nested/macbeth_nested/nested_package/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/macbeth_nested/macbeth_nested/nested_package/nested_module.py b/test-data/packages/macbeth_nested/macbeth_nested/nested_package/nested_module.py new file mode 100644 index 000000000000..3d53af0e3240 --- /dev/null +++ b/test-data/packages/macbeth_nested/macbeth_nested/nested_package/nested_module.py @@ -0,0 +1,2 @@ +def nested_func(a: str) -> str: + return a + " nested" diff --git a/test-data/packages/macbeth_nested/macbeth_nested/nested_package/py.typed b/test-data/packages/macbeth_nested/macbeth_nested/nested_package/py.typed new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/macbeth_nested/setup.py b/test-data/packages/macbeth_nested/setup.py new file mode 100644 index 000000000000..e8d09f610132 --- /dev/null +++ b/test-data/packages/macbeth_nested/setup.py @@ -0,0 +1,9 @@ +from setuptools import setup, find_packages + +setup( + name='macbeth_nested', + version='1.0.0', + packages=find_packages(), + zip_safe=False, + package_data={'macbeth_nested.nested_package': ['py.typed']} +) From f1566b983916dd8b9cb7475fbfbc0d4d395422df Mon Sep 17 00:00:00 2001 From: macbeth322 Date: Sat, 8 Sep 2018 22:38:38 -0400 Subject: [PATCH 2/6] remove extra print statement --- mypy/build.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypy/build.py b/mypy/build.py index a542a918e5ef..714fb3dc1b26 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -903,7 +903,6 @@ def _find_module_non_stub_helper( fscache = self.fscache for count in range(len(components)): typed_file = os.path.join(pkg_dir, *components[:count+1], 'py.typed') - _print('BETA ', typed_file) if fscache.isfile(typed_file): return os.path.join(pkg_dir, *components[:-1]) return None From 8b5c2b8c0ace8a3657683ac651812bac24ac5505 Mon Sep 17 00:00:00 2001 From: macbeth322 Date: Sun, 9 Sep 2018 10:59:24 -0400 Subject: [PATCH 3/6] fix flake8 warnings --- mypy/build.py | 3 +-- mypy/test/testpep561.py | 13 ++++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/mypy/build.py b/mypy/build.py index 714fb3dc1b26..dd17592469e0 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -902,7 +902,7 @@ def _find_module_non_stub_helper( ) -> Optional[str]: fscache = self.fscache for count in range(len(components)): - typed_file = os.path.join(pkg_dir, *components[:count+1], 'py.typed') + typed_file = os.path.join(pkg_dir, *components[:count + 1], 'py.typed') if fscache.isfile(typed_file): return os.path.join(pkg_dir, *components[:-1]) return None @@ -926,7 +926,6 @@ def _find_module(self, id: str, search_paths: SearchPaths, # Third-party stub/typed packages for pkg_dir in search_paths.package_path: stub_name = components[0] + '-stubs' - typed_file = os.path.join(pkg_dir, components[0], 'py.typed') stub_dir = os.path.join(pkg_dir, stub_name) if fscache.isdir(stub_dir): stub_typed_file = os.path.join(stub_dir, 'py.typed') diff --git a/mypy/test/testpep561.py b/mypy/test/testpep561.py index 3166845ac86d..d183289bd752 100644 --- a/mypy/test/testpep561.py +++ b/mypy/test/testpep561.py @@ -203,6 +203,7 @@ def test_typedpkg_editable(self) -> None: venv_dir=venv_dir, ) + class TestPEP561Namespace(TestCase): @contextmanager @@ -254,8 +255,14 @@ def setUp(self) -> None: self.tempfile = os.path.join(self.temp_file_dir.name, 'namespace_program.py') with open(self.tempfile, 'w+') as file: file.write(NAMESPACE_PROGRAM) - self.msg_bool_str = '{0}:8: error: Argument 1 to "nested_func" has incompatible type "bool"; expected "str"\n'.format(self.tempfile) - self.msg_int_bool = '{0}:9: error: Argument 1 to "namespace_func" has incompatible type "int"; expected "bool"\n'.format(self.tempfile) + self.msg_bool_str = ( + '{0}:8: error: Argument 1 to "nested_func" has incompatible type "bool"; ' + 'expected "str"\n'.format(self.tempfile) + ) + self.msg_int_bool = ( + '{0}:9: error: Argument 1 to "namespace_func" has incompatible type "int"; ' + 'expected "bool"\n'.format(self.tempfile) + ) def tearDown(self) -> None: self.temp_file_dir.cleanup() @@ -268,7 +275,7 @@ def test_nested_and_namespace(self) -> None: check_mypy_run( [self.tempfile], python_executable, - expected_out=self.msg_bool_str+self.msg_int_bool, + expected_out=self.msg_bool_str + self.msg_int_bool, venv_dir=venv_dir, ) From 6f48b717c167fd7651a20577aa642895d96d359b Mon Sep 17 00:00:00 2001 From: macbeth322 Date: Sun, 9 Sep 2018 13:24:04 -0400 Subject: [PATCH 4/6] update tests to have more consistent names and acutally be namespace packages --- mypy/build.py | 16 ++++++++++------ mypy/test/testpep561.py | 14 +++++++------- .../inside_namespace_package/namespace_module.py | 2 -- test-data/packages/macbeth_namespace/setup.py | 9 --------- .../packages/typedpkg_namespace.alpha/setup.py | 10 ++++++++++ .../typedpkg_namespace}/__init__.py | 0 .../typedpkg_namespace/alpha}/__init__.py | 0 .../typedpkg_namespace/alpha/alpha_module.py | 2 ++ .../typedpkg_namespace/alpha}/py.typed | 0 .../{macbeth_nested => typedpkg_nested}/setup.py | 4 ++-- .../typedpkg_nested}/__init__.py | 0 .../typedpkg_nested}/nested_package/__init__.py | 0 .../nested_package/nested_module.py | 0 .../typedpkg_nested}/nested_package/py.typed | 0 14 files changed, 31 insertions(+), 26 deletions(-) delete mode 100644 test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/namespace_module.py delete mode 100644 test-data/packages/macbeth_namespace/setup.py create mode 100644 test-data/packages/typedpkg_namespace.alpha/setup.py rename test-data/packages/{macbeth_namespace/macbeth_namespace => typedpkg_namespace.alpha/typedpkg_namespace}/__init__.py (100%) rename test-data/packages/{macbeth_namespace/macbeth_namespace/inside_namespace_package => typedpkg_namespace.alpha/typedpkg_namespace/alpha}/__init__.py (100%) create mode 100644 test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/alpha_module.py rename test-data/packages/{macbeth_namespace/macbeth_namespace/inside_namespace_package => typedpkg_namespace.alpha/typedpkg_namespace/alpha}/py.typed (100%) rename test-data/packages/{macbeth_nested => typedpkg_nested}/setup.py (57%) rename test-data/packages/{macbeth_nested/macbeth_nested => typedpkg_nested/typedpkg_nested}/__init__.py (100%) rename test-data/packages/{macbeth_nested/macbeth_nested => typedpkg_nested/typedpkg_nested}/nested_package/__init__.py (100%) rename test-data/packages/{macbeth_nested/macbeth_nested => typedpkg_nested/typedpkg_nested}/nested_package/nested_module.py (100%) rename test-data/packages/{macbeth_nested/macbeth_nested => typedpkg_nested/typedpkg_nested}/nested_package/py.typed (100%) diff --git a/mypy/build.py b/mypy/build.py index dd17592469e0..84625857445c 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -899,12 +899,16 @@ def _find_module_non_stub_helper( self, components: List[str], pkg_dir: str - ) -> Optional[str]: + ) -> Optional[Tuple[str, bool]]: fscache = self.fscache - for count in range(len(components)): - typed_file = os.path.join(pkg_dir, *components[:count + 1], 'py.typed') - if fscache.isfile(typed_file): - return os.path.join(pkg_dir, *components[:-1]) + pkgs2check = ( + fscache.isfile(os.path.join(pkg_dir, *components[:count + 1], 'py.typed')) + for count in range(len(components)) + ) + if next(pkgs2check): + return os.path.join(pkg_dir, *components[:-1]), True + if any(pkgs2check): + return os.path.join(pkg_dir, *components[:-1]), False return None def _find_module(self, id: str, search_paths: SearchPaths, @@ -950,7 +954,7 @@ def _find_module(self, id: str, search_paths: SearchPaths, pkg_dir ) if non_stub_match: - third_party_inline_dirs.append((non_stub_match, True)) + third_party_inline_dirs.append(non_stub_match) if self.options and self.options.use_builtins_fixtures: # Everything should be in fixtures. third_party_inline_dirs.clear() diff --git a/mypy/test/testpep561.py b/mypy/test/testpep561.py index d183289bd752..30b9350246b0 100644 --- a/mypy/test/testpep561.py +++ b/mypy/test/testpep561.py @@ -22,14 +22,14 @@ """ NAMESPACE_PROGRAM = """ -from macbeth_nested.nested_package.nested_module import nested_func -from macbeth_namespace.inside_namespace_package.namespace_module import namespace_func +from typedpkg_nested.nested_package.nested_module import nested_func +from typedpkg_namespace.alpha.alpha_module import alpha_func nested_func("abc") -namespace_func(False) +alpha_func(False) nested_func(False) -namespace_func(2) +alpha_func(2) """ @@ -260,7 +260,7 @@ def setUp(self) -> None: 'expected "str"\n'.format(self.tempfile) ) self.msg_int_bool = ( - '{0}:9: error: Argument 1 to "namespace_func" has incompatible type "int"; ' + '{0}:9: error: Argument 1 to "alpha_func" has incompatible type "int"; ' 'expected "bool"\n'.format(self.tempfile) ) @@ -270,8 +270,8 @@ def tearDown(self) -> None: def test_nested_and_namespace(self) -> None: with self.virtualenv() as venv: venv_dir, python_executable = venv - self.install_package('macbeth_nested', python_executable) - self.install_package('macbeth_namespace', python_executable) + self.install_package('typedpkg_nested', python_executable) + self.install_package('typedpkg_namespace.alpha', python_executable) check_mypy_run( [self.tempfile], python_executable, diff --git a/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/namespace_module.py b/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/namespace_module.py deleted file mode 100644 index e63a2ee6e281..000000000000 --- a/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/namespace_module.py +++ /dev/null @@ -1,2 +0,0 @@ -def namespace_func(a: bool) -> bool: - return not a diff --git a/test-data/packages/macbeth_namespace/setup.py b/test-data/packages/macbeth_namespace/setup.py deleted file mode 100644 index 2dd6ce646a00..000000000000 --- a/test-data/packages/macbeth_namespace/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -from setuptools import setup, find_packages - -setup( - name='macbeth_namespace', - version='1.0.0', - packages=find_packages(), - zip_safe=False, - package_data={'macbeth_namespace.inside_namespace_package': ['py.typed']} -) diff --git a/test-data/packages/typedpkg_namespace.alpha/setup.py b/test-data/packages/typedpkg_namespace.alpha/setup.py new file mode 100644 index 000000000000..3bbf09fed6e7 --- /dev/null +++ b/test-data/packages/typedpkg_namespace.alpha/setup.py @@ -0,0 +1,10 @@ +from setuptools import setup, find_packages + +setup( + name='typedpkg_namespace.alpha', + version='1.0.0', + packages=find_packages(), + namespace_packages=['typedpkg_namespace'], + zip_safe=False, + package_data={'typedpkg_namespace.alpha': ['py.typed']} +) diff --git a/test-data/packages/macbeth_namespace/macbeth_namespace/__init__.py b/test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/__init__.py similarity index 100% rename from test-data/packages/macbeth_namespace/macbeth_namespace/__init__.py rename to test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/__init__.py diff --git a/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/__init__.py b/test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/__init__.py similarity index 100% rename from test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/__init__.py rename to test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/__init__.py diff --git a/test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/alpha_module.py b/test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/alpha_module.py new file mode 100644 index 000000000000..6aef88ac7004 --- /dev/null +++ b/test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/alpha_module.py @@ -0,0 +1,2 @@ +def alpha_func(a: bool) -> bool: + return not a diff --git a/test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/py.typed b/test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/py.typed similarity index 100% rename from test-data/packages/macbeth_namespace/macbeth_namespace/inside_namespace_package/py.typed rename to test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/py.typed diff --git a/test-data/packages/macbeth_nested/setup.py b/test-data/packages/typedpkg_nested/setup.py similarity index 57% rename from test-data/packages/macbeth_nested/setup.py rename to test-data/packages/typedpkg_nested/setup.py index e8d09f610132..791bae88ca60 100644 --- a/test-data/packages/macbeth_nested/setup.py +++ b/test-data/packages/typedpkg_nested/setup.py @@ -1,9 +1,9 @@ from setuptools import setup, find_packages setup( - name='macbeth_nested', + name='typedpkg_nested', version='1.0.0', packages=find_packages(), zip_safe=False, - package_data={'macbeth_nested.nested_package': ['py.typed']} + package_data={'typedpkg_nested.nested_package': ['py.typed']} ) diff --git a/test-data/packages/macbeth_nested/macbeth_nested/__init__.py b/test-data/packages/typedpkg_nested/typedpkg_nested/__init__.py similarity index 100% rename from test-data/packages/macbeth_nested/macbeth_nested/__init__.py rename to test-data/packages/typedpkg_nested/typedpkg_nested/__init__.py diff --git a/test-data/packages/macbeth_nested/macbeth_nested/nested_package/__init__.py b/test-data/packages/typedpkg_nested/typedpkg_nested/nested_package/__init__.py similarity index 100% rename from test-data/packages/macbeth_nested/macbeth_nested/nested_package/__init__.py rename to test-data/packages/typedpkg_nested/typedpkg_nested/nested_package/__init__.py diff --git a/test-data/packages/macbeth_nested/macbeth_nested/nested_package/nested_module.py b/test-data/packages/typedpkg_nested/typedpkg_nested/nested_package/nested_module.py similarity index 100% rename from test-data/packages/macbeth_nested/macbeth_nested/nested_package/nested_module.py rename to test-data/packages/typedpkg_nested/typedpkg_nested/nested_package/nested_module.py diff --git a/test-data/packages/macbeth_nested/macbeth_nested/nested_package/py.typed b/test-data/packages/typedpkg_nested/typedpkg_nested/nested_package/py.typed similarity index 100% rename from test-data/packages/macbeth_nested/macbeth_nested/nested_package/py.typed rename to test-data/packages/typedpkg_nested/typedpkg_nested/nested_package/py.typed From b5dc6b7dbe57275119a0319409c0431a4dec28c5 Mon Sep 17 00:00:00 2001 From: macbeth322 Date: Sun, 9 Sep 2018 16:05:43 -0400 Subject: [PATCH 5/6] fix arg spreading --- mypy/build.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mypy/build.py b/mypy/build.py index 84625857445c..117bc2729a94 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -902,8 +902,9 @@ def _find_module_non_stub_helper( ) -> Optional[Tuple[str, bool]]: fscache = self.fscache pkgs2check = ( - fscache.isfile(os.path.join(pkg_dir, *components[:count + 1], 'py.typed')) - for count in range(len(components)) + fscache.isfile( + os.path.join(os.path.join(pkg_dir, *components[:count + 1]), 'py.typed') + ) for count in range(len(components)) ) if next(pkgs2check): return os.path.join(pkg_dir, *components[:-1]), True From 983b6eb44d27f4ea6bcf7a4091b78c748e82d9f9 Mon Sep 17 00:00:00 2001 From: macbeth322 Date: Tue, 25 Sep 2018 19:51:04 -0400 Subject: [PATCH 6/6] condense some lines; rewrite _find_module_non_stub_helper; reuse unit test structure --- mypy/build.py | 37 +++------ mypy/test/testpep561.py | 81 ++++--------------- .../setup.py | 0 .../typedpkg_namespace/__init__.py | 0 .../typedpkg_namespace/alpha/__init__.py | 0 .../typedpkg_namespace/alpha/alpha_module.py | 0 .../typedpkg_namespace/alpha/py.typed | 0 7 files changed, 27 insertions(+), 91 deletions(-) rename test-data/packages/{typedpkg_namespace.alpha => typedpkg_namespace-alpha}/setup.py (100%) rename test-data/packages/{typedpkg_namespace.alpha => typedpkg_namespace-alpha}/typedpkg_namespace/__init__.py (100%) rename test-data/packages/{typedpkg_namespace.alpha => typedpkg_namespace-alpha}/typedpkg_namespace/alpha/__init__.py (100%) rename test-data/packages/{typedpkg_namespace.alpha => typedpkg_namespace-alpha}/typedpkg_namespace/alpha/alpha_module.py (100%) rename test-data/packages/{typedpkg_namespace.alpha => typedpkg_namespace-alpha}/typedpkg_namespace/alpha/py.typed (100%) diff --git a/mypy/build.py b/mypy/build.py index 460fbe7bbbed..d258256d156e 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -841,7 +841,8 @@ def stats_summary(self) -> Mapping[str, object]: # Package dirs are a two-tuple of path to search and whether to verify the module -PackageDirs = List[Tuple[str, bool]] +OnePackageDir = Tuple[str, bool] +PackageDirs = List[OnePackageDir] class FindModuleCache: @@ -896,21 +897,13 @@ def find_module(self, id: str, search_paths: SearchPaths, self.results[key] = self._find_module(id, search_paths, python_executable) return self.results[key] - def _find_module_non_stub_helper( - self, - components: List[str], - pkg_dir: str - ) -> Optional[Tuple[str, bool]]: - fscache = self.fscache - pkgs2check = ( - fscache.isfile( - os.path.join(os.path.join(pkg_dir, *components[:count + 1]), 'py.typed') - ) for count in range(len(components)) - ) - if next(pkgs2check): - return os.path.join(pkg_dir, *components[:-1]), True - if any(pkgs2check): - return os.path.join(pkg_dir, *components[:-1]), False + def _find_module_non_stub_helper(self, components: List[str], + pkg_dir: str) -> Optional[OnePackageDir]: + dir_path = pkg_dir + for index, component in enumerate(components): + dir_path = os.path.join(dir_path, component) + if self.fscache.isfile(os.path.join(dir_path, 'py.typed')): + return os.path.join(pkg_dir, *components[:-1]), index == 0 return None def _find_module(self, id: str, search_paths: SearchPaths, @@ -927,8 +920,8 @@ def _find_module(self, id: str, search_paths: SearchPaths, # We have two sets of folders so that we collect *all* stubs folders and # put them in the front of the search path - third_party_inline_dirs = [] - third_party_stubs_dirs = [] + third_party_inline_dirs = [] # type: PackageDirs + third_party_stubs_dirs = [] # type: PackageDirs # Third-party stub/typed packages for pkg_dir in search_paths.package_path: stub_name = components[0] + '-stubs' @@ -951,10 +944,7 @@ def _find_module(self, id: str, search_paths: SearchPaths, third_party_stubs_dirs.append((path, False)) else: third_party_stubs_dirs.append((path, True)) - non_stub_match = self._find_module_non_stub_helper( - components, - pkg_dir - ) + non_stub_match = self._find_module_non_stub_helper(components, pkg_dir) if non_stub_match: third_party_inline_dirs.append(non_stub_match) if self.options and self.options.use_builtins_fixtures: @@ -2700,8 +2690,7 @@ def load_graph(sources: List[BuildSource], manager: BuildManager, # they will be taken care of during fine grained update. See also # comment about this in `State.__init__()`. added = [] - all_deps_to_check = st.ancestors + dependencies + st.suppressed - for dep in all_deps_to_check: + for dep in st.ancestors + dependencies + st.suppressed: ignored = dep in st.suppressed and dep not in entry_points if ignored and dep not in added: manager.missing_modules.add(dep) diff --git a/mypy/test/testpep561.py b/mypy/test/testpep561.py index 30b9350246b0..066a15bca977 100644 --- a/mypy/test/testpep561.py +++ b/mypy/test/testpep561.py @@ -106,6 +106,10 @@ def setUp(self) -> None: self.tempfile = os.path.join(self.temp_file_dir.name, 'simple.py') with open(self.tempfile, 'w+') as file: file.write(SIMPLE_PROGRAM) + self.namespace_tempfile = os.path.join(self.temp_file_dir.name, 'namespace_program.py') + with open(self.namespace_tempfile, 'w+') as file: + file.write(NAMESPACE_PROGRAM) + self.msg_dne = \ "{}:3: error: Module 'typedpkg' has no attribute 'dne'\n".format(self.tempfile) self.msg_list = \ @@ -113,6 +117,13 @@ def setUp(self) -> None: self.msg_tuple = \ "{}:5: error: Revealed type is 'builtins.tuple[builtins.str]'\n".format(self.tempfile) + self.namespace_msg_bool_str = ( + '{0}:8: error: Argument 1 to "nested_func" has incompatible type "bool"; ' + 'expected "str"\n'.format(self.namespace_tempfile)) + self.namespace_msg_int_bool = ( + '{0}:9: error: Argument 1 to "alpha_func" has incompatible type "int"; ' + 'expected "bool"\n'.format(self.namespace_tempfile)) + def tearDown(self) -> None: self.temp_file_dir.cleanup() @@ -203,79 +214,15 @@ def test_typedpkg_editable(self) -> None: venv_dir=venv_dir, ) - -class TestPEP561Namespace(TestCase): - - @contextmanager - def virtualenv(self, - python_executable: str = sys.executable - ) -> Generator[Tuple[str, str], None, None]: - """Context manager that creates a virtualenv in a temporary directory - - returns the path to the created Python executable""" - # Sadly, we need virtualenv, as the Python 3 venv module does not support creating a venv - # for Python 2, and Python 2 does not have its own venv. - with tempfile.TemporaryDirectory() as venv_dir: - returncode, lines = run_command([sys.executable, - '-m', - 'virtualenv', - '-p{}'.format(python_executable), - venv_dir], cwd=os.getcwd()) - if returncode != 0: - err = '\n'.join(lines) - self.fail("Failed to create venv. Do you have virtualenv installed?\n" + err) - if sys.platform == 'win32': - yield venv_dir, os.path.abspath(os.path.join(venv_dir, 'Scripts', 'python')) - else: - yield venv_dir, os.path.abspath(os.path.join(venv_dir, 'bin', 'python')) - - def install_package(self, pkg: str, - python_executable: str = sys.executable, - use_pip: bool = True, - editable: bool = False) -> None: - """Context manager to temporarily install a package from test-data/packages/pkg/""" - working_dir = os.path.join(package_path, pkg) - if use_pip: - install_cmd = [python_executable, '-m', 'pip', 'install'] - if editable: - install_cmd.append('-e') - install_cmd.append('.') - else: - install_cmd = [python_executable, 'setup.py'] - if editable: - install_cmd.append('develop') - else: - install_cmd.append('install') - returncode, lines = run_command(install_cmd, cwd=working_dir) - if returncode != 0: - self.fail('\n'.join(lines)) - - def setUp(self) -> None: - self.temp_file_dir = tempfile.TemporaryDirectory() - self.tempfile = os.path.join(self.temp_file_dir.name, 'namespace_program.py') - with open(self.tempfile, 'w+') as file: - file.write(NAMESPACE_PROGRAM) - self.msg_bool_str = ( - '{0}:8: error: Argument 1 to "nested_func" has incompatible type "bool"; ' - 'expected "str"\n'.format(self.tempfile) - ) - self.msg_int_bool = ( - '{0}:9: error: Argument 1 to "alpha_func" has incompatible type "int"; ' - 'expected "bool"\n'.format(self.tempfile) - ) - - def tearDown(self) -> None: - self.temp_file_dir.cleanup() - def test_nested_and_namespace(self) -> None: with self.virtualenv() as venv: venv_dir, python_executable = venv self.install_package('typedpkg_nested', python_executable) - self.install_package('typedpkg_namespace.alpha', python_executable) + self.install_package('typedpkg_namespace-alpha', python_executable) check_mypy_run( - [self.tempfile], + [self.namespace_tempfile], python_executable, - expected_out=self.msg_bool_str + self.msg_int_bool, + expected_out=self.namespace_msg_bool_str + self.namespace_msg_int_bool, venv_dir=venv_dir, ) diff --git a/test-data/packages/typedpkg_namespace.alpha/setup.py b/test-data/packages/typedpkg_namespace-alpha/setup.py similarity index 100% rename from test-data/packages/typedpkg_namespace.alpha/setup.py rename to test-data/packages/typedpkg_namespace-alpha/setup.py diff --git a/test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/__init__.py b/test-data/packages/typedpkg_namespace-alpha/typedpkg_namespace/__init__.py similarity index 100% rename from test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/__init__.py rename to test-data/packages/typedpkg_namespace-alpha/typedpkg_namespace/__init__.py diff --git a/test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/__init__.py b/test-data/packages/typedpkg_namespace-alpha/typedpkg_namespace/alpha/__init__.py similarity index 100% rename from test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/__init__.py rename to test-data/packages/typedpkg_namespace-alpha/typedpkg_namespace/alpha/__init__.py diff --git a/test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/alpha_module.py b/test-data/packages/typedpkg_namespace-alpha/typedpkg_namespace/alpha/alpha_module.py similarity index 100% rename from test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/alpha_module.py rename to test-data/packages/typedpkg_namespace-alpha/typedpkg_namespace/alpha/alpha_module.py diff --git a/test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/py.typed b/test-data/packages/typedpkg_namespace-alpha/typedpkg_namespace/alpha/py.typed similarity index 100% rename from test-data/packages/typedpkg_namespace.alpha/typedpkg_namespace/alpha/py.typed rename to test-data/packages/typedpkg_namespace-alpha/typedpkg_namespace/alpha/py.typed