diff --git a/mypy/build.py b/mypy/build.py index 1196356d5bb8b..40fc0d2ca38c1 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -15,6 +15,7 @@ import gc import json import os +import pathlib import platform import re import stat @@ -605,6 +606,31 @@ def __init__(self, data_dir: str, self.fscache = fscache self.find_module_cache = FindModuleCache(self.search_paths, self.fscache, self.options, source_set=self.source_set) + for module in CORE_BUILTIN_MODULES: + if options.use_builtins_fixtures: + continue + if module == "_importlib_modulespec": + continue + path = self.find_module_cache.find_module(module) + if not isinstance(path, str): + raise CompileError([ + f"Failed to find builtin module {module}, perhaps typeshed is broken?", + ]) + if is_typeshed_file(path): + continue + if is_stub_package_file(path): + continue + if options.custom_typeshed_dir is not None: + custom_typeshed_dir = os.path.abspath(options.custom_typeshed_dir) + parent_dir = os.path.dirname(path) + if os.path.commonpath((parent_dir, custom_typeshed_dir)) == custom_typeshed_dir: + continue + + raise CompileError([ + f'mypy: "{os.path.relpath(path)}" shadows library module "{module}"', + f'note: A user-defined top-level module with name "{module}" is not supported' + ]) + self.metastore = create_metastore(options) # a mapping from source files to their corresponding shadow files @@ -2459,15 +2485,6 @@ def find_module_and_diagnose(manager: BuildManager, if is_sub_path(result, dir): # Silence errors in site-package dirs and typeshed follow_imports = 'silent' - if (id in CORE_BUILTIN_MODULES - and not is_typeshed_file(result) - and not is_stub_package_file(result) - and not options.use_builtins_fixtures - and not options.custom_typeshed_dir): - raise CompileError([ - f'mypy: "{os.path.relpath(result)}" shadows library module "{id}"', - f'note: A user-defined top-level module with name "{id}" is not supported' - ]) return (result, follow_imports) else: # Could not find a module. Typically the reason is a diff --git a/mypy/test/testgraph.py b/mypy/test/testgraph.py index 7d32db2b1c1c4..1a52fa8a221d0 100644 --- a/mypy/test/testgraph.py +++ b/mypy/test/testgraph.py @@ -38,6 +38,7 @@ def test_scc(self) -> None: def _make_manager(self) -> BuildManager: errors = Errors() options = Options() + options.use_builtins_fixtures = True fscache = FileSystemCache() search_paths = SearchPaths((), (), (), ()) manager = BuildManager( diff --git a/mypy/util.py b/mypy/util.py index 03db281ef6152..35dd0429f9c4b 100644 --- a/mypy/util.py +++ b/mypy/util.py @@ -51,6 +51,8 @@ "__init__", "__new__", "__call__", "__init_subclass__", "__class_getitem__", )) +TYPESHED_DIR: Final = os.path.join(os.path.dirname(__file__), 'typeshed') + def is_dunder(name: str, exclude_special: bool = False) -> bool: """Returns whether name is a dunder name. @@ -745,8 +747,7 @@ def format_error( def is_typeshed_file(file: str) -> bool: - # gross, but no other clear way to tell - return 'typeshed' in os.path.abspath(file).split(os.sep) + return os.path.commonpath((TYPESHED_DIR, os.path.abspath(file))) == TYPESHED_DIR def is_stub_package_file(file: str) -> bool: @@ -754,7 +755,7 @@ def is_stub_package_file(file: str) -> bool: if not file.endswith('.pyi'): return False return any(component.endswith('-stubs') - for component in os.path.abspath(file).split(os.sep)) + for component in os.path.split(os.path.abspath(file))) def unnamed_function(name: Optional[str]) -> bool: diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test index 3b3b64c038c14..0fbc8a5e3dd7d 100644 --- a/test-data/unit/cmdline.test +++ b/test-data/unit/cmdline.test @@ -1425,3 +1425,22 @@ b\.c \d+ # cmd: mypy --enable-incomplete-features a.py [file a.py] pass + +[case testShadowTypingModuleEarlyLoad] +# cmd: mypy . +from typing import Union + +def foo(a: Union[int, str]) -> str: + return str +[file typing.py] +import sys +import os +del sys.modules["typing"] +path = sys.path +sys.path.remove(os.getcwd()) +from typing import * +sys.path = path +[out] +mypy: "tmp/typing.py" shadows library module "typing" +note: A user-defined top-level module with name "typing" is not supported +== Return code: 2