diff --git a/mypy/build.py b/mypy/build.py index 2a5bb16af7cab..4d6123762a3fe 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -2521,14 +2521,29 @@ def log_configuration(manager: BuildManager) -> None: """Output useful configuration information to LOG and TRACE""" manager.log() - configuration_vars = ( + configuration_vars = [ ("Mypy Version", __version__), ("Config File", (manager.options.config_file or "Default")), - ("Configured Executable", manager.options.python_executable), + ] + + src_pth_str = "Source Path" + src_pths = list(manager.source_set.source_paths.copy()) + src_pths.sort() + + if len(src_pths) > 1: + src_pth_str += "s" + configuration_vars.append((src_pth_str, " ".join(src_pths))) + elif len(src_pths) == 1: + configuration_vars.append((src_pth_str, src_pths.pop())) + else: + configuration_vars.append((src_pth_str, "None")) + + configuration_vars.extend([ + ("Configured Executable", manager.options.python_executable or "None"), ("Current Executable", sys.executable), ("Cache Dir", manager.options.cache_dir), ("Compiled", str(not __file__.endswith(".py"))), - ) + ]) for conf_name, conf_value in configuration_vars: manager.log("{:24}{}".format(conf_name + ":", conf_value)) diff --git a/mypy/config_parser.py b/mypy/config_parser.py index 0ee274abd1bcc..4721bc0b5f74f 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -79,6 +79,7 @@ def split_and_match_files(paths: str) -> List[str]: # These two are for backwards compatibility 'silent_imports': bool, 'almost_silent': bool, + 'no_site_packages': bool, 'plugins': lambda s: [p.strip() for p in s.split(',')], 'always_true': lambda s: [p.strip() for p in s.split(',')], 'always_false': lambda s: [p.strip() for p in s.split(',')], diff --git a/mypy/main.py b/mypy/main.py index 741527c2ba979..42430967dccd8 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -218,7 +218,7 @@ def infer_python_executable(options: Options, python_executable = special_opts.python_executable or options.python_executable if python_executable is None: - if not special_opts.no_executable: + if not special_opts.no_executable and not options.no_site_packages: python_executable = _python_executable_from_version(options.python_version) options.python_executable = python_executable @@ -839,7 +839,7 @@ def set_strict_flags() -> None: except PythonExecutableInferenceError as e: parser.error(str(e)) - if special_opts.no_executable: + if special_opts.no_executable or options.no_site_packages: options.python_executable = None # Paths listed in the config file will be ignored if any paths are passed on diff --git a/mypy/options.py b/mypy/options.py index 38072b821d156..f3b095d9449c2 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -77,6 +77,7 @@ def __init__(self) -> None: self.report_dirs = {} # type: Dict[str, str] # Show errors in PEP 561 packages/site-packages modules self.no_silence_site_packages = False + self.no_site_packages = False self.ignore_missing_imports = False self.follow_imports = 'normal' # normal|silent|skip|error # Whether to respect the follow_imports setting even for stub files. diff --git a/mypy/test/testpep561.py b/mypy/test/testpep561.py index bfb8f95ff5abe..a8eabd7702a16 100644 --- a/mypy/test/testpep561.py +++ b/mypy/test/testpep561.py @@ -1,6 +1,7 @@ from contextlib import contextmanager import os import pytest # type: ignore +import re import subprocess from subprocess import PIPE import sys @@ -72,7 +73,7 @@ def install_package(pkg: str, working_dir = os.path.join(package_path, pkg) with tempfile.TemporaryDirectory() as dir: if use_pip: - install_cmd = [python_executable, '-m', 'pip', 'install', '-b {}'.format(dir)] + install_cmd = [python_executable, '-m', 'pip', 'install', '-b', '{}'.format(dir)] if editable: install_cmd.append('-e') install_cmd.append('.') @@ -100,10 +101,11 @@ def test_pep561(testcase: DataDrivenTestCase) -> None: else: python = sys.executable assert python is not None, "Should be impossible" - pkgs, args = parse_pkgs(testcase.input[0]) + pkgs, pip_args = parse_pkgs(testcase.input[0]) + mypy_args = parse_mypy_args(testcase.input[1]) use_pip = True editable = False - for arg in args: + for arg in pip_args: if arg == 'no-pip': use_pip = False elif arg == 'editable': @@ -122,9 +124,14 @@ def test_pep561(testcase: DataDrivenTestCase) -> None: with open(program, 'w', encoding='utf-8') as f: for s in testcase.input: f.write('{}\n'.format(s)) - cmd_line = [program, '--no-incremental', '--no-error-summary'] + cmd_line = mypy_args + [program, '--no-incremental', '--no-error-summary'] if python_executable != sys.executable: cmd_line.append('--python-executable={}'.format(python_executable)) + if testcase.files != []: + for name, content in testcase.files: + if 'mypy.ini' in name: + with open('mypy.ini', 'w') as m: + m.write(content) output = [] # Type check the module out, err, returncode = mypy.api.run(cmd_line) @@ -153,6 +160,13 @@ def parse_pkgs(comment: str) -> Tuple[List[str], List[str]]: return ([pkg.strip() for pkg in pkgs_str.split(',')], [arg.strip() for arg in args]) +def parse_mypy_args(line: str) -> List[str]: + m = re.match('# flags: (.*)$', line) + if not m: + return [] # No args; mypy will spit out an error. + return m.group(1).split() + + @pytest.mark.skipif(sys.platform == 'darwin' and hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix, reason="Temporarily skip to avoid having a virtualenv within a venv.") diff --git a/test-data/unit/pep561.test b/test-data/unit/pep561.test index acc99c0e797b0..69549b97df462 100644 --- a/test-data/unit/pep561.test +++ b/test-data/unit/pep561.test @@ -1,3 +1,16 @@ +[case testTypedPkgNoSitePkgsIgnoredImports] +# pkgs: typedpkg +# flags: --no-site-packages +from typedpkg.sample import ex +from typedpkg import dne +a = ex(['']) +reveal_type(a) +[file mypy.ini] +\[mypy] +ignore_missing_imports = True +[out] +testTypedPkgNoSitePkgsIgnoredImports.py:6: note: Revealed type is 'Any' + [case testTypedPkgSimple] # pkgs: typedpkg from typedpkg.sample import ex @@ -7,6 +20,34 @@ reveal_type(a) [out] testTypedPkgSimple.py:5: note: Revealed type is 'builtins.tuple[builtins.str]' +[case testTypedPkg_config_nositepackages] +# pkgs: typedpkg +from typedpkg.sample import ex +from typedpkg import dne +a = ex(['']) +reveal_type(a) +[file mypy.ini] +\[mypy] +no_site_packages=True +[out] +testTypedPkg_config_nositepackages.py:2: error: Cannot find implementation or library stub for module named 'typedpkg.sample' +testTypedPkg_config_nositepackages.py:2: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports +testTypedPkg_config_nositepackages.py:3: error: Cannot find implementation or library stub for module named 'typedpkg' +testTypedPkg_config_nositepackages.py:5: note: Revealed type is 'Any' + +[case testTypedPkg_args_nositepackages] +# pkgs: typedpkg +# flags: --no-site-packages +from typedpkg.sample import ex +from typedpkg import dne +a = ex(['']) +reveal_type(a) +[out] +testTypedPkg_args_nositepackages.py:3: error: Cannot find implementation or library stub for module named 'typedpkg.sample' +testTypedPkg_args_nositepackages.py:3: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports +testTypedPkg_args_nositepackages.py:4: error: Cannot find implementation or library stub for module named 'typedpkg' +testTypedPkg_args_nositepackages.py:6: note: Revealed type is 'Any' + [case testTypedPkgStubs] # pkgs: typedpkg-stubs from typedpkg.sample import ex diff --git a/test.py b/test.py new file mode 100644 index 0000000000000..e69de29bb2d1d