diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index 99f7d5b58409..a50499649794 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -8,17 +8,21 @@ summary of command line flags can always be printed using the ``-h`` flag (or its long form ``--help``):: $ mypy -h - usage: mypy [-h] [-v] [-V] [--python-version x.y] [--platform PLATFORM] [-2] - [--ignore-missing-imports] + usage: mypy [-h] [-v] [-V] [--python-version x.y] + [--python-executable PYTHON_EXECUTABLE] [--platform PLATFORM] [-2] + [--ignore-missing-imports] [--no-site-packages] [--follow-imports {normal,silent,skip,error}] - [--disallow-any-{unimported,expr,decorated,explicit,generics}] - [--disallow-untyped-calls] [--disallow-untyped-defs] + [--disallow-any-unimported] [--disallow-any-expr] + [--disallow-any-decorated] [--disallow-any-explicit] + [--disallow-any-generics] [--disallow-untyped-calls] + [--disallow-untyped-defs] [--disallow-incomplete-defs] [--check-untyped-defs] [--disallow-subclassing-any] - [--warn-incomplete-stub] [--warn-redundant-casts] - [--no-warn-no-return] [--warn-return-any] [--warn-unused-ignores] + [--warn-incomplete-stub] [--disallow-untyped-decorators] + [--warn-redundant-casts] [--no-warn-no-return] [--warn-return-any] + [--warn-unused-ignores] [--warn-unused-configs] [--show-error-context] [--no-implicit-optional] [-i] - [--quick-and-dirty] [--cache-dir DIR] [--skip-version-check] - [--strict-optional] + [--quick-and-dirty] [--cache-dir DIR] [--cache-fine-grained] + [--skip-version-check] [--strict-optional] [--strict-optional-whitelist [GLOB [GLOB ...]]] [--junit-xml JUNIT_XML] [--pdb] [--show-traceback] [--stats] [--inferstats] [--custom-typing MODULE] @@ -28,9 +32,9 @@ flag (or its long form ``--help``):: [--shadow-file SOURCE_FILE SHADOW_FILE] [--any-exprs-report DIR] [--cobertura-xml-report DIR] [--html-report DIR] [--linecount-report DIR] [--linecoverage-report DIR] - [--memory-xml-report DIR] - [--txt-report DIR] [--xml-report DIR] [--xslt-html-report DIR] - [--xslt-txt-report DIR] [-m MODULE] [-c PROGRAM_TEXT] [-p PACKAGE] + [--memory-xml-report DIR] [--txt-report DIR] [--xml-report DIR] + [--xslt-html-report DIR] [--xslt-txt-report DIR] [-m MODULE] + [-c PROGRAM_TEXT] [-p PACKAGE] [files [files ...]] (etc., too long to show everything here) @@ -366,11 +370,29 @@ Here are some more useful flags: updates the cache, but regular incremental mode ignores cache files written by quick mode. +- ``--python-executable EXECUTABLE`` will have mypy collect type information + from `PEP 561`_ compliant + packages installed for the Python executable ``EXECUTABLE``. If not provided, + mypy will use PEP 561 compliant packages installed for the Python executable + running mypy. See :ref:`installed-packages` for more on making PEP 561 + compliant packages. This flag will attempt to set ``--python-version`` if not + already set. + - ``--python-version X.Y`` will make mypy typecheck your code as if it were run under Python version X.Y. Without this option, mypy will default to using whatever version of Python is running mypy. Note that the ``-2`` and ``--py2`` flags are aliases for ``--python-version 2.7``. See - :ref:`version_and_platform_checks` for more about this feature. + :ref:`version_and_platform_checks` for more about this feature. This flag + will attempt to find a Python executable of the corresponding version to + search for `PEP 561`_ compliant + packages. If you'd like to disable this, see ``--no-site-packages`` below. + +- ``--no-site-packages`` will disable searching for + `PEP 561`_ compliant packages. + This will also disable searching for a usable Python executable. Use this + flag if mypy cannot find a Python executable for the version of Python being + checked, and you don't need to use PEP 561 typed packages. Otherwise, use + ``--python-executable``. - ``--platform PLATFORM`` will make mypy typecheck your code as if it were run under the the given operating system. Without this option, mypy will @@ -453,6 +475,9 @@ For the remaining flags you can read the full ``mypy -h`` output. Command line flags are liable to change between releases. + +.. _PEP 561: https://www.python.org/dev/peps/pep-0561/ + .. _integrating-mypy: Integrating mypy into another Python application diff --git a/docs/source/index.rst b/docs/source/index.rst index 90cc74941da8..582c1c4ee1b8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -30,6 +30,7 @@ Mypy is a static type checker for Python. command_line config_file python36 + installed_packages faq cheat_sheet cheat_sheet_py3 diff --git a/docs/source/installed_packages.rst b/docs/source/installed_packages.rst new file mode 100644 index 000000000000..01384f508e18 --- /dev/null +++ b/docs/source/installed_packages.rst @@ -0,0 +1,114 @@ +.. _installed-packages: + +Using Installed Packages +======================== + +`PEP 561 `_ specifies how to mark +a package as supporting type checking. Below is a summary of how to create +PEP 561 compatible packages and have mypy use them in type checking. + +Making PEP 561 compatible packages +********************************** + +Packages that must be imported at runtime and supply type information should +put a ``py.typed`` in their package directory. For example, with a directory +structure as follows: + +.. code-block:: text + + setup.py + package_a/ + __init__.py + lib.py + py.typed + +the setup.py might look like: + +.. code-block:: python + + from distutils.core import setup + + setup( + name="SuperPackageA", + author="Me", + version="0.1", + package_data={"package_a": ["py.typed"]}, + packages=["package_a"] + ) + +Some packages have a mix of stub files and runtime files. These packages also require +a ``py.typed`` file. An example can be seen below: + +.. code-block:: text + + setup.py + package_b/ + __init__.py + lib.py + lib.pyi + py.typed + +the setup.py might look like: + +.. code-block:: python + + from distutils.core import setup + + setup( + name="SuperPackageB", + author="Me", + version="0.1", + package_data={"package_b": ["py.typed", "lib.pyi"]}, + packages=["package_b"] + ) + +In this example, both ``lib.py`` and ``lib.pyi`` exist. At runtime, ``lib.py`` +will be used, however mypy will use ``lib.pyi``. + +If the package is stub-only (not imported at runtime), the package should have +a prefix of the runtime package name and a suffix of ``-stubs``. +A ``py.typed`` file is not needed for stub-only packages. For example, if we +had stubs for ``package_c``, we might do the following: + +.. code-block:: text + + setup.py + package_c-stubs/ + __init__.pyi + lib.pyi + +the setup.py might look like: + +.. code-block:: python + + from distutils.core import setup + + setup( + name="SuperPackageC", + author="Me", + version="0.1", + package_data={"package_c-stubs": ["__init__.pyi", "lib.pyi"]}, + packages=["package_c-stubs"] + ) + +Using PEP 561 compatible packages with mypy +******************************************* + +Generally, you do not need to do anything to use installed packages for the +Python executable used to run mypy. They should be automatically picked up by +mypy and used for type checking. + +By default, mypy searches for packages installed for the Python executable +running mypy. It is highly unlikely you want this situation if you have +installed typed packages in another Python's package directory. + +Generally, you can use the ``--python-version`` flag and mypy will try to find +the correct package directory. If that fails, you can use the +``--python-executable`` flag to point to the exact executable, and mypy will +find packages installed for that Python executable. + +Note that mypy does not support some more advanced import features, such as zip +imports, namespace packages, and custom import hooks. + +If you do not want to use typed packages, use the ``--no-site-packages`` flag +to disable searching. \ No newline at end of file diff --git a/mypy/build.py b/mypy/build.py index ac8436ee10af..e756f5fbe743 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -14,6 +14,7 @@ import collections import contextlib from distutils.sysconfig import get_python_lib +import functools import gc import hashlib import json @@ -21,6 +22,7 @@ import re import site import stat +import subprocess import sys import time from os.path import dirname, basename @@ -683,7 +685,7 @@ def correct_rel_imp(imp: Union[ImportFrom, ImportAll]) -> str: def is_module(self, id: str) -> bool: """Is there a file in the file system corresponding to module id?""" - return find_module(id, self.lib_path) is not None + return find_module(id, self.lib_path, self.options.python_executable) is not None def parse_file(self, id: str, path: str, source: str, ignore_errors: bool) -> MypyFile: """Parse the source of a file with the given name. @@ -796,8 +798,8 @@ def remove_cwd_prefix_from_path(p: str) -> str: return p -# Cache find_module: (id, lib_path) -> result. -find_module_cache = {} # type: Dict[Tuple[str, Tuple[str, ...]], Optional[str]] +# Cache find_module: id -> result. +find_module_cache = {} # type: Dict[Tuple[str, Optional[str], Tuple[str, ...]], Optional[str]] # Cache some repeated work within distinct find_module calls: finding which # elements of lib_path have even the subdirectory they'd need for the module @@ -861,59 +863,134 @@ def is_file(path: str) -> bool: return res -def find_module(id: str, lib_path_arg: Iterable[str]) -> Optional[str]: +USER_SITE_PACKAGES = \ + 'from __future__ import print_function; import site; print(site.getusersitepackages());' \ + 'print(*site.getsitepackages(), sep="\\n")' +VIRTUALENV_SITE_PACKAGES = \ + 'from distutils.sysconfig import get_python_lib; print(get_python_lib())' + + +def call_python(python_executable: str, command: str) -> str: + return subprocess.check_output([python_executable, '-c', command], + stderr=subprocess.PIPE).decode() + + +@functools.lru_cache(maxsize=None) +def get_site_packages_dirs(python_executable: str) -> List[str]: + """Find package directories for given python.""" + if python_executable == sys.executable: + # Use running Python's package dirs + if hasattr(site, 'getusersitepackages') and hasattr(site, 'getsitepackages'): + user_dir = site.getusersitepackages() + return site.getsitepackages() + [user_dir] + # If site doesn't have get(user)sitepackages, we are running in a + # virtualenv, and should fall back to get_python_lib + return [get_python_lib()] + else: + # Use subprocess to get the package directory of given Python + # executable + try: + output = call_python(python_executable, USER_SITE_PACKAGES) + except subprocess.CalledProcessError: + # if no paths are found (raising a CalledProcessError), we fall back on sysconfig, + # the python executable is likely in a virtual environment, thus lacking + # needed site methods + output = call_python(python_executable, VIRTUALENV_SITE_PACKAGES) + return [line for line in output.splitlines() if os.path.isdir(line)] + + +def find_base_dirs(lib_path: Tuple[str, ...], dir_chain: str, components: List[str], + site_packages_dirs: List[str]) -> Tuple[str, ...]: + # If we're looking for a module like 'foo.bar.baz', it's likely that most of the + # many elements of lib_path don't even have a subdirectory 'foo/bar'. Discover + # that only once and cache it for when we look for modules like 'foo.bar.blah' + # that will require the same subdirectory. + # TODO (ethanhs): refactor to use lru_cache on each of these searches + dirs = find_module_dir_cache.get((dir_chain, lib_path), []) + if not dirs: + # Regular packages on the PATH + for pathitem in lib_path: + # e.g., '/usr/lib/python3.4/foo/bar' + isdir = find_module_isdir_cache.get((pathitem, dir_chain)) + if isdir is None: + dir = os.path.normpath(os.path.join(pathitem, dir_chain)) + isdir = os.path.isdir(dir) + find_module_isdir_cache[pathitem, dir_chain] = isdir + if isdir: + dirs.append(dir) + find_module_dir_cache[dir_chain, lib_path] = dirs + third_party_dirs = [] + # Third-party stub/typed packages + for pkg_dir in site_packages_dirs: + 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 os.path.isdir(stub_dir): + stub_components = [stub_name] + components[1:] + path = os.path.join(pkg_dir, *stub_components[:-1]) + if os.path.isdir(path): + third_party_dirs.append(path) + elif os.path.isfile(typed_file): + path = os.path.join(pkg_dir, dir_chain) + third_party_dirs.append(path) + + return tuple(third_party_dirs + + find_module_dir_cache[dir_chain, lib_path]) + + +def find_module_in_base_dirs(id: str, candidate_base_dirs: Iterable[str], + last_component: str) -> Optional[str]: + # If we're looking for a module like 'foo.bar.baz', then candidate_base_dirs now + # contains just the subdirectories 'foo/bar' that actually exist under the + # elements of lib_path. This is probably much shorter than lib_path itself. + # Now just look for 'baz.pyi', 'baz/__init__.py', etc., inside those directories. + seplast = os.sep + last_component + sepinit = os.sep + '__init__' + for base_dir in candidate_base_dirs: + base_path = base_dir + seplast # so e.g. '/usr/lib/python3.4/foo/bar/baz' + # Prefer package over module, i.e. baz/__init__.py* over baz.py*. + for extension in PYTHON_EXTENSIONS: + path = base_path + sepinit + extension + path_stubs = base_path + '-stubs' + sepinit + extension + if is_file(path) and verify_module(id, path): + return path + elif is_file(path_stubs) and verify_module(id, path_stubs): + return path_stubs + # No package, look for module. + for extension in PYTHON_EXTENSIONS: + path = base_path + extension + if is_file(path) and verify_module(id, path): + return path + return None + + +def find_module(id: str, lib_path_arg: Iterable[str], + python_executable: Optional[str]) -> Optional[str]: """Return the path of the module source file, or None if not found.""" lib_path = tuple(lib_path_arg) - - def find() -> Optional[str]: - # If we're looking for a module like 'foo.bar.baz', it's likely that most of the - # many elements of lib_path don't even have a subdirectory 'foo/bar'. Discover - # that only once and cache it for when we look for modules like 'foo.bar.blah' - # that will require the same subdirectory. + if (id, python_executable, lib_path) not in find_module_cache: components = id.split('.') dir_chain = os.sep.join(components[:-1]) # e.g., 'foo/bar' - if (dir_chain, lib_path) not in find_module_dir_cache: - dirs = [] - for pathitem in lib_path: - # e.g., '/usr/lib/python3.4/foo/bar' - isdir = find_module_isdir_cache.get((pathitem, dir_chain)) - if isdir is None: - dir = os.path.normpath(os.path.join(pathitem, dir_chain)) - isdir = os.path.isdir(dir) - find_module_isdir_cache[pathitem, dir_chain] = isdir - if isdir: - dirs.append(dir) - find_module_dir_cache[dir_chain, lib_path] = dirs - candidate_base_dirs = find_module_dir_cache[dir_chain, lib_path] - - # If we're looking for a module like 'foo.bar.baz', then candidate_base_dirs now - # contains just the subdirectories 'foo/bar' that actually exist under the - # elements of lib_path. This is probably much shorter than lib_path itself. - # Now just look for 'baz.pyi', 'baz/__init__.py', etc., inside those directories. - seplast = os.sep + components[-1] # so e.g. '/baz' - sepinit = os.sep + '__init__' - for base_dir in candidate_base_dirs: - base_path = base_dir + seplast # so e.g. '/usr/lib/python3.4/foo/bar/baz' - # Prefer package over module, i.e. baz/__init__.py* over baz.py*. - for extension in PYTHON_EXTENSIONS: - path = base_path + sepinit + extension - if is_file(path) and verify_module(id, path): - return path - # No package, look for module. - for extension in PYTHON_EXTENSIONS: - path = base_path + extension - if is_file(path) and verify_module(id, path): - return path - return None - key = (id, lib_path) - if key not in find_module_cache: - find_module_cache[key] = find() - return find_module_cache[key] + if python_executable is not None: + site_packages_dirs = get_site_packages_dirs(python_executable) + if not site_packages_dirs: + print("Could not find package directories for Python '{}'".format( + python_executable), file=sys.stderr) + sys.exit(2) + else: + site_packages_dirs = [] + base_dirs = find_base_dirs(lib_path, dir_chain, components, site_packages_dirs) + find_module_cache[id, + python_executable, + lib_path] = find_module_in_base_dirs(id, base_dirs, components[-1]) + + return find_module_cache[id, python_executable, lib_path] -def find_modules_recursive(module: str, lib_path: List[str]) -> List[BuildSource]: - module_path = find_module(module, lib_path) +def find_modules_recursive(module: str, lib_path: List[str], + python_executable: Optional[str]) -> List[BuildSource]: + module_path = find_module(module, lib_path, python_executable) if not module_path: return [] result = [BuildSource(module_path, module, None)] @@ -933,14 +1010,14 @@ def find_modules_recursive(module: str, lib_path: List[str]) -> List[BuildSource (os.path.isfile(os.path.join(abs_path, '__init__.py')) or os.path.isfile(os.path.join(abs_path, '__init__.pyi'))): hits.add(item) - result += find_modules_recursive(module + '.' + item, lib_path) + result += find_modules_recursive(module + '.' + item, lib_path, python_executable) elif item != '__init__.py' and item != '__init__.pyi' and \ item.endswith(('.py', '.pyi')): mod = item.split('.')[0] if mod not in hits: hits.add(mod) - result += find_modules_recursive( - module + '.' + mod, lib_path) + result += find_modules_recursive(module + '.' + mod, + lib_path, python_executable) return result @@ -1606,7 +1683,7 @@ def __init__(self, # difference and just assume 'builtins' everywhere, # which simplifies code. file_id = '__builtin__' - path = find_module(file_id, manager.lib_path) + path = find_module(file_id, manager.lib_path, manager.options.python_executable) if path: # For non-stubs, look at options.follow_imports: # - normal (default) -> fully analyze diff --git a/mypy/main.py b/mypy/main.py index b7c1117ea029..8b8bfc16d871 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -1,10 +1,12 @@ """Mypy type checker command line tool.""" import argparse +import ast import configparser import fnmatch import os import re +import subprocess import sys import time @@ -205,6 +207,44 @@ def invert_flag_name(flag: str) -> str: return '--no-{}'.format(flag[2:]) +class PythonExecutableInferenceError(Exception): + """Represents a failure to infer the version or executable while searching.""" + + +if sys.platform == 'win32': + def python_executable_prefix(v: str) -> List[str]: + return ['py', '-{}'.format(v)] +else: + def python_executable_prefix(v: str) -> List[str]: + return ['python{}'.format(v)] + + +def _python_version_from_executable(python_executable: str) -> Tuple[int, int]: + try: + check = subprocess.check_output([python_executable, '-c', + 'import sys; print(repr(sys.version_info[:2]))'], + stderr=subprocess.STDOUT).decode() + return ast.literal_eval(check) + except (subprocess.CalledProcessError, FileNotFoundError): + raise PythonExecutableInferenceError( + 'Error: invalid Python executable {}'.format(python_executable)) + + +def _python_executable_from_version(python_version: Tuple[int, int]) -> str: + if sys.version_info[:2] == python_version: + return sys.executable + str_ver = '.'.join(map(str, python_version)) + try: + sys_exe = subprocess.check_output(python_executable_prefix(str_ver) + + ['-c', 'import sys; print(sys.executable)'], + stderr=subprocess.STDOUT).decode().strip() + return sys_exe + except (subprocess.CalledProcessError, FileNotFoundError): + raise PythonExecutableInferenceError( + 'Error: failed to find a Python executable matching version {},' + ' perhaps try --python-executable, or --no-site-packages?'.format(python_version)) + + def process_options(args: List[str], require_targets: bool = True, server_options: bool = False, @@ -255,7 +295,13 @@ def add_invertible_flag(flag: str, parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('--python-version', type=parse_version, metavar='x.y', - help='use Python x.y') + help='use Python x.y', dest='special-opts:python_version') + parser.add_argument('--python-executable', action='store', + help="Python executable whose installed packages will be" + " used in typechecking.", dest='special-opts:python_executable') + parser.add_argument('--no-site-packages', action='store_true', + dest='special-opts:no_site_packages', + help="Do not search for PEP 561 packages in the package directory.") parser.add_argument('--platform', action='store', metavar='PLATFORM', help="typecheck special-cased code for the given OS platform " "(defaults to sys.platform).") @@ -482,6 +528,33 @@ def add_invertible_flag(flag: str, print("Warning: --no-fast-parser no longer has any effect. The fast parser " "is now mypy's default and only parser.") + try: + # Infer Python version and/or executable if one is not given + if special_opts.python_executable is not None and special_opts.python_version is not None: + py_exe_ver = _python_version_from_executable(special_opts.python_executable) + if py_exe_ver != special_opts.python_version: + parser.error( + 'Python version {} did not match executable {}, got version {}.'.format( + special_opts.python_version, special_opts.python_executable, py_exe_ver + )) + else: + options.python_version = special_opts.python_version + options.python_executable = special_opts.python_executable + elif special_opts.python_executable is None and special_opts.python_version is not None: + options.python_version = special_opts.python_version + if not special_opts.no_site_packages: + py_exe = _python_executable_from_version(special_opts.python_version) + options.python_executable = py_exe + elif special_opts.python_version is None and special_opts.python_executable is not None: + options.python_version = _python_version_from_executable( + special_opts.python_executable) + options.python_executable = special_opts.python_executable + except PythonExecutableInferenceError as e: + parser.error(str(e)) + + if special_opts.no_site_packages: + options.python_executable = None + # Check for invalid argument combinations. if require_targets: code_methods = sum(bool(c) for c in [special_opts.modules, @@ -527,7 +600,8 @@ def add_invertible_flag(flag: str, .format(special_opts.package)) options.build_type = BuildType.MODULE lib_path = [os.getcwd()] + build.mypy_path() - targets = build.find_modules_recursive(special_opts.package, lib_path) + targets = build.find_modules_recursive(special_opts.package, lib_path, + options.python_executable) if not targets: fail("Can't find package '{}'".format(special_opts.package)) return targets, options diff --git a/mypy/options.py b/mypy/options.py index 667d88065648..c3d07df08191 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -52,7 +52,8 @@ def __init__(self) -> None: # -- build options -- self.build_type = BuildType.STANDARD - self.python_version = defaults.PYTHON3_VERSION + self.python_version = sys.version_info[:2] # type: Tuple[int, int] + self.python_executable = sys.executable # type: Optional[str] self.platform = sys.platform self.custom_typing_module = None # type: Optional[str] self.custom_typeshed_dir = None # type: Optional[str] diff --git a/mypy/stubgen.py b/mypy/stubgen.py index 07e85adb34da..8c6c08567bfe 100644 --- a/mypy/stubgen.py +++ b/mypy/stubgen.py @@ -156,7 +156,8 @@ def find_module_path_and_all(module: str, pyversion: Tuple[int, int], module_all = getattr(mod, '__all__', None) else: # Find module by going through search path. - module_path = mypy.build.find_module(module, ['.'] + search_path) + module_path = mypy.build.find_module(module, ['.'] + search_path, + interpreter) if not module_path: raise SystemExit( "Can't find module '{}' (consider using --search-path)".format(module)) diff --git a/mypy/test/config.py b/mypy/test/config.py index 5dbe791e593a..5e6792fb0d57 100644 --- a/mypy/test/config.py +++ b/mypy/test/config.py @@ -5,6 +5,7 @@ # Location of test data files such as test case descriptions. test_data_prefix = os.path.join(PREFIX, 'test-data', 'unit') +package_path = os.path.join(PREFIX, 'test-data', 'packages') assert os.path.isdir(test_data_prefix), \ 'Test data prefix ({}) not set correctly'.format(test_data_prefix) diff --git a/mypy/test/helpers.py b/mypy/test/helpers.py index daffa8344dc0..a26ad27221b5 100644 --- a/mypy/test/helpers.py +++ b/mypy/test/helpers.py @@ -1,9 +1,11 @@ import os import re +import subprocess import sys import time -from typing import List, Dict, Tuple, Callable, Any, Optional + +from typing import Any, Callable, Dict, List, Optional, Tuple from mypy import defaults @@ -16,6 +18,7 @@ from mypy.main import process_options from mypy.options import Options from mypy.test.data import DataDrivenTestCase +from mypy.test.config import test_temp_dir skip = pytest.mark.skip @@ -327,3 +330,30 @@ def parse_options(program_text: str, testcase: DataDrivenTestCase, options.python_version = testcase_pyversion(testcase.file, testcase.name) return options + + +def split_lines(*streams: bytes) -> List[str]: + """Returns a single list of string lines from the byte streams in args.""" + return [ + s + for stream in streams + for s in stream.decode('utf8').splitlines() + ] + + +def run_command(cmdline: List[str], *, env: Optional[Dict[str, str]] = None, + timeout: int = 300, cwd: str = test_temp_dir) -> Tuple[int, List[str]]: + """A poor man's subprocess.run() for 3.4 compatibility.""" + process = subprocess.Popen( + cmdline, + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=cwd, + ) + try: + out, err = process.communicate(timeout=timeout) + except subprocess.TimeoutExpired: + out = err = b'' + process.kill() + return process.returncode, split_lines(out, err) diff --git a/mypy/test/testcheck.py b/mypy/test/testcheck.py index 0b1f1573760e..37be5cd4a8af 100644 --- a/mypy/test/testcheck.py +++ b/mypy/test/testcheck.py @@ -3,6 +3,7 @@ import os import re import shutil +import sys from typing import Dict, List, Optional, Set, Tuple @@ -312,7 +313,7 @@ def parse_module(self, module_names = m.group(1) out = [] for module_name in module_names.split(' '): - path = build.find_module(module_name, [test_temp_dir]) + path = build.find_module(module_name, [test_temp_dir], sys.executable) assert path is not None, "Can't find ad hoc case file" with open(path) as f: program_text = f.read() diff --git a/mypy/test/testcmdline.py b/mypy/test/testcmdline.py index 57910c1a1dc0..88ad272fab0d 100644 --- a/mypy/test/testcmdline.py +++ b/mypy/test/testcmdline.py @@ -47,6 +47,7 @@ def test_python_cmdline(testcase: DataDrivenTestCase) -> None: file.write('{}\n'.format(s)) args = parse_args(testcase.input[0]) args.append('--show-traceback') + args.append('--no-site-packages') # Type check the program. fixed = [python3_path, os.path.join(testcase.old_cwd, 'scripts', 'mypy')] diff --git a/mypy/test/testdiff.py b/mypy/test/testdiff.py index b1cfc65a4a29..552b49be36ec 100644 --- a/mypy/test/testdiff.py +++ b/mypy/test/testdiff.py @@ -53,6 +53,8 @@ def build(self, source: str) -> Tuple[List[str], Optional[Dict[str, MypyFile]]]: options.use_builtins_fixtures = True options.show_traceback = True options.cache_dir = os.devnull + options.python_version = (3, 6) + options.python_executable = None try: result = build.build(sources=[BuildSource('main', None, source)], options=options, diff --git a/mypy/test/testdmypy.py b/mypy/test/testdmypy.py index 5a5cd80ddcc8..5ffd6236f1d8 100644 --- a/mypy/test/testdmypy.py +++ b/mypy/test/testdmypy.py @@ -271,7 +271,7 @@ def parse_module(self, module_names = m.group(1) out = [] # type: List[Tuple[str, str, Optional[str]]] for module_name in module_names.split(' '): - path = build.find_module(module_name, [test_temp_dir]) + path = build.find_module(module_name, [test_temp_dir], sys.executable) if path is None and module_name.startswith(NON_EXISTENT_PREFIX): # This is a special name for a file that we don't want to exist. assert '.' not in module_name # TODO: Packages not supported here diff --git a/mypy/test/testmerge.py b/mypy/test/testmerge.py index cc79958d5c15..283947861791 100644 --- a/mypy/test/testmerge.py +++ b/mypy/test/testmerge.py @@ -102,6 +102,8 @@ def build(self, source: str) -> Tuple[List[str], Optional[BuildManager], Dict[st options.fine_grained_incremental = True options.use_builtins_fixtures = True options.show_traceback = True + options.python_version = (3, 6) + options.python_executable = None main_path = os.path.join(test_temp_dir, 'main') with open(main_path, 'w') as f: f.write(source) diff --git a/mypy/test/testpep561.py b/mypy/test/testpep561.py new file mode 100644 index 000000000000..5ab2bbf3cb3b --- /dev/null +++ b/mypy/test/testpep561.py @@ -0,0 +1,115 @@ +from contextlib import contextmanager +import os +import shutil +import sys +from typing import Generator, List +from unittest import TestCase, main + +import mypy.api +from mypy.build import get_site_packages_dirs +from mypy.test.config import package_path +from mypy.test.helpers import run_command +from mypy.util import try_find_python2_interpreter + +SIMPLE_PROGRAM = """ +from typedpkg.sample import ex +a = ex(['']) +reveal_type(a) +""" + + +class TestPEP561(TestCase): + @contextmanager + def install_package(self, pkg: str, + python_executable: str = sys.executable) -> Generator[None, None, None]: + """Context manager to temporarily install a package from test-data/packages/pkg/""" + working_dir = os.path.join(package_path, pkg) + install_cmd = [python_executable, '-m', 'pip', 'install', '.'] + # if we aren't in a virtualenv, install in the + # user package directory so we don't need sudo + if not hasattr(sys, 'real_prefix') or python_executable != sys.executable: + install_cmd.append('--user') + returncode, lines = run_command(install_cmd, cwd=working_dir) + if returncode != 0: + self.fail('\n'.join(lines)) + try: + yield + finally: + run_command([python_executable, '-m', 'pip', 'uninstall', '-y', pkg], cwd=package_path) + + def test_get_pkg_dirs(self) -> None: + """Check that get_package_dirs works.""" + dirs = get_site_packages_dirs(sys.executable) + assert dirs + + @staticmethod + def check_mypy_run(cmd_line: List[str], + expected_out: str, + expected_err: str = '', + expected_returncode: int = 1) -> None: + """Helper to run mypy and check the output.""" + out, err, returncode = mypy.api.run(cmd_line) + assert out == expected_out, err + assert err == expected_err, out + assert returncode == expected_returncode, returncode + + def test_typed_pkg(self) -> None: + """Tests type checking based on installed packages. + + This test CANNOT be split up, concurrency means that simultaneously + installing/uninstalling will break tests""" + test_file = 'simple.py' + if not os.path.isdir('test-packages-data'): + os.mkdir('test-packages-data') + old_cwd = os.getcwd() + os.chdir('test-packages-data') + with open(test_file, 'w') as f: + f.write(SIMPLE_PROGRAM) + try: + with self.install_package('typedpkg-stubs'): + self.check_mypy_run( + [test_file], + "simple.py:4: error: Revealed type is 'builtins.list[builtins.str]'\n" + ) + + # The Python 2 tests are intentionally placed after a Python 3 test to check + # the package_dir_cache is behaving correctly. + python2 = try_find_python2_interpreter() + if python2: + with self.install_package('typedpkg-stubs', python2): + self.check_mypy_run( + ['--python-executable={}'.format(python2), test_file], + "simple.py:4: error: Revealed type is 'builtins.list[builtins.str]'\n" + ) + with self.install_package('typedpkg', python2): + self.check_mypy_run( + ['--python-executable={}'.format(python2), 'simple.py'], + "simple.py:4: error: Revealed type is 'builtins.tuple[builtins.str]'\n" + ) + + with self.install_package('typedpkg', python2): + with self.install_package('typedpkg-stubs', python2): + self.check_mypy_run( + ['--python-executable={}'.format(python2), test_file], + "simple.py:4: error: Revealed type is 'builtins.list[builtins.str]'\n" + ) + + with self.install_package('typedpkg'): + self.check_mypy_run( + [test_file], + "simple.py:4: error: Revealed type is 'builtins.tuple[builtins.str]'\n" + ) + + with self.install_package('typedpkg'): + with self.install_package('typedpkg-stubs'): + self.check_mypy_run( + [test_file], + "simple.py:4: error: Revealed type is 'builtins.list[builtins.str]'\n" + ) + finally: + os.chdir(old_cwd) + shutil.rmtree('test-packages-data') + + +if __name__ == '__main__': + main() diff --git a/mypy/test/testpythoneval.py b/mypy/test/testpythoneval.py index 222fa6ff32c2..a9d8e35b4396 100644 --- a/mypy/test/testpythoneval.py +++ b/mypy/test/testpythoneval.py @@ -13,15 +13,14 @@ import os import os.path import re -import subprocess import sys import pytest # type: ignore # no pytest in typeshed -from typing import Dict, List, Tuple, Optional +from typing import List from mypy.test.config import test_temp_dir from mypy.test.data import DataDrivenTestCase, DataSuite -from mypy.test.helpers import assert_string_arrays_equal +from mypy.test.helpers import assert_string_arrays_equal, run_command from mypy.util import try_find_python2_interpreter from mypy import api @@ -48,7 +47,7 @@ def test_python_evaluation(testcase: DataDrivenTestCase) -> None: version. """ assert testcase.old_cwd is not None, "test was not properly set up" - mypy_cmdline = ['--show-traceback'] + mypy_cmdline = ['--show-traceback', '--no-site-packages'] py2 = testcase.name.lower().endswith('python2') if py2: mypy_cmdline.append('--py2') @@ -60,6 +59,7 @@ def test_python_evaluation(testcase: DataDrivenTestCase) -> None: return else: interpreter = python3_path + mypy_cmdline.append('--python-version=3.6') # Write the program to a file. program = '_' + testcase.name + '.py' @@ -79,7 +79,7 @@ def test_python_evaluation(testcase: DataDrivenTestCase) -> None: output.append(line.rstrip("\r\n")) if returncode == 0: # Execute the program. - returncode, interp_out = run([interpreter, program]) + returncode, interp_out = run_command([interpreter, program]) output.extend(interp_out) # Remove temp file. os.remove(program_path) @@ -88,35 +88,7 @@ def test_python_evaluation(testcase: DataDrivenTestCase) -> None: testcase.file, testcase.line)) -def split_lines(*streams: bytes) -> List[str]: - """Returns a single list of string lines from the byte streams in args.""" - return [ - s.rstrip('\n\r') - for stream in streams - for s in str(stream, 'utf8').splitlines() - ] - - def adapt_output(testcase: DataDrivenTestCase) -> List[str]: """Translates the generic _program.py into the actual filename.""" program = '_' + testcase.name + '.py' return [program_re.sub(program, line) for line in testcase.output] - - -def run( - cmdline: List[str], *, env: Optional[Dict[str, str]] = None, timeout: int = 300 -) -> Tuple[int, List[str]]: - """A poor man's subprocess.run() for 3.3 and 3.4 compatibility.""" - process = subprocess.Popen( - cmdline, - env=env, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=test_temp_dir, - ) - try: - out, err = process.communicate(timeout=timeout) - except subprocess.TimeoutExpired: - out = err = b'' - process.kill() - return process.returncode, split_lines(out, err) diff --git a/mypy/test/testsemanal.py b/mypy/test/testsemanal.py index 98f3ef64b26c..ef593f19710e 100644 --- a/mypy/test/testsemanal.py +++ b/mypy/test/testsemanal.py @@ -38,6 +38,8 @@ def get_semanal_options() -> Options: options.use_builtins_fixtures = True options.semantic_analysis_only = True options.show_traceback = True + options.python_version = (3, 6) + options.python_executable = None return options diff --git a/mypy/waiter.py b/mypy/waiter.py index 7e475d3e61ae..76d6fd335b0b 100644 --- a/mypy/waiter.py +++ b/mypy/waiter.py @@ -160,7 +160,7 @@ def load_log_file(self) -> Optional[List[Dict[str, Dict[str, Any]]]]: test_log = json.load(fp) except FileNotFoundError: test_log = [] - except json.JSONDecodeError: + except ValueError: print('corrupt test log file {}'.format(self.FULL_LOG_FILENAME), file=sys.stderr) test_log = [] return test_log diff --git a/runtests.py b/runtests.py index c2f3361eadf5..2e64a2b29389 100755 --- a/runtests.py +++ b/runtests.py @@ -9,6 +9,7 @@ import itertools import os from os.path import join, isdir +import re import sys @@ -73,14 +74,16 @@ def add_mypy_cmd(self, name: str, mypy_args: List[str], cwd: Optional[str] = Non return args = [sys.executable, self.mypy] + mypy_args args.append('--show-traceback') + args.append('--no-site-packages') self.waiter.add(LazySubprocess(full_name, args, cwd=cwd, env=self.env)) def add_mypy(self, name: str, *args: str, cwd: Optional[str] = None) -> None: self.add_mypy_cmd(name, list(args), cwd=cwd) def add_mypy_modules(self, name: str, modules: Iterable[str], - cwd: Optional[str] = None) -> None: - args = list(itertools.chain(*(['-m', mod] for mod in modules))) + cwd: Optional[str] = None, extra_args: List[str] = None) -> None: + args = extra_args or [] + args.extend(list(itertools.chain(*(['-m', mod] for mod in modules)))) self.add_mypy_cmd(name, args, cwd=cwd) def add_mypy_package(self, name: str, packagename: str, *flags: str) -> None: @@ -231,6 +234,8 @@ def test_path(*names: str): 'testpythoneval', 'testcmdline', 'teststubgen', + # non-data-driven: + 'testpep561', ) for f in find_files('mypy', prefix='test', suffix='.py'): @@ -256,7 +261,7 @@ def add_stubs(driver: Driver) -> None: module = file_to_module(f[len(stubdir) + 1:]) modules.add(module) - driver.add_mypy_modules('stubs', sorted(modules)) + driver.add_mypy_modules('stubs', sorted(modules), extra_args=['--python-version=3.5']) def add_stdlibsamples(driver: Driver) -> None: @@ -276,7 +281,11 @@ def add_stdlibsamples(driver: Driver) -> None: def add_samples(driver: Driver) -> None: for f in find_files(os.path.join('test-data', 'samples'), suffix='.py'): - driver.add_mypy('file %s' % f, f) + if f == os.path.join('test-data', 'samples', 'crawl2.py'): + # This test requires 3.5 + driver.add_mypy_cmd('file {}'.format(f), ['--python-version=3.5', f]) + else: + driver.add_mypy('file %s' % f, f) def usage(status: int) -> None: diff --git a/test-data/__init__.py b/test-data/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/typedpkg-stubs/setup.py b/test-data/packages/typedpkg-stubs/setup.py new file mode 100644 index 000000000000..b90e3a011f23 --- /dev/null +++ b/test-data/packages/typedpkg-stubs/setup.py @@ -0,0 +1,13 @@ +""" +This setup file installs packages to test mypy's PEP 561 implementation +""" + +from distutils.core import setup + +setup( + name='typedpkg-stubs', + author="The mypy team", + version='0.1', + package_data={'typedpkg-stubs': ['sample.pyi', '__init__.pyi']}, + packages=['typedpkg-stubs'], +) diff --git a/test-data/packages/typedpkg-stubs/typedpkg-stubs/__init__.pyi b/test-data/packages/typedpkg-stubs/typedpkg-stubs/__init__.pyi new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/typedpkg-stubs/typedpkg-stubs/sample.pyi b/test-data/packages/typedpkg-stubs/typedpkg-stubs/sample.pyi new file mode 100644 index 000000000000..355deefd6a2d --- /dev/null +++ b/test-data/packages/typedpkg-stubs/typedpkg-stubs/sample.pyi @@ -0,0 +1,2 @@ +from typing import Iterable, List +def ex(a: Iterable[str]) -> List[str]: ... diff --git a/test-data/packages/typedpkg/setup.py b/test-data/packages/typedpkg/setup.py new file mode 100644 index 000000000000..6da37d2f6629 --- /dev/null +++ b/test-data/packages/typedpkg/setup.py @@ -0,0 +1,14 @@ +""" +This setup file installs packages to test mypy's PEP 561 implementation +""" + +from distutils.core import setup + +setup( + name='typedpkg', + author="The mypy team", + version='0.1', + package_data={'typedpkg': ['py.typed']}, + packages=['typedpkg'], + include_package_data=True, +) diff --git a/test-data/packages/typedpkg/typedpkg/__init__.py b/test-data/packages/typedpkg/typedpkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/typedpkg/typedpkg/py.typed b/test-data/packages/typedpkg/typedpkg/py.typed new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/typedpkg/typedpkg/sample.py b/test-data/packages/typedpkg/typedpkg/sample.py new file mode 100644 index 000000000000..59f6aec1548e --- /dev/null +++ b/test-data/packages/typedpkg/typedpkg/sample.py @@ -0,0 +1,7 @@ +from typing import Iterable, Tuple + + +def ex(a): + # type: (Iterable[str]) -> Tuple[str, ...] + """Example typed package. This intentionally has an error.""" + return tuple(a) diff --git a/test-data/unit/check-async-await.test b/test-data/unit/check-async-await.test index e243bd50f415..227ba6279e23 100644 --- a/test-data/unit/check-async-await.test +++ b/test-data/unit/check-async-await.test @@ -184,7 +184,7 @@ async def f() -> None: [typing fixtures/typing-full.pyi] [case testAsyncForComprehension] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import Generic, Iterable, TypeVar, AsyncIterator, Tuple T = TypeVar('T') @@ -224,7 +224,7 @@ async def generatorexp(obj: Iterable[int]): [typing fixtures/typing-full.pyi] [case testAsyncForComprehensionErrors] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import Generic, Iterable, TypeVar, AsyncIterator, Tuple T = TypeVar('T') @@ -346,7 +346,7 @@ async def f() -> None: [typing fixtures/typing-full.pyi] [case testNoYieldInAsyncDef] -# flags: --python-version 3.5 +# flags: --python-version 3.5 --no-site-packages async def f(): yield None # E: 'yield' in async function @@ -432,7 +432,7 @@ def f() -> Generator[int, str, int]: -- --------------------------------------------------------------------- [case testAsyncGenerator] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import AsyncGenerator, Generator async def f() -> int: @@ -460,7 +460,7 @@ async def wrong_return() -> Generator[int, None, None]: # E: The return type of [typing fixtures/typing-full.pyi] [case testAsyncGeneratorReturnIterator] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import AsyncIterator async def gen() -> AsyncIterator[int]: @@ -476,7 +476,7 @@ async def use_gen() -> None: [typing fixtures/typing-full.pyi] [case testAsyncGeneratorManualIter] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import AsyncGenerator async def genfunc() -> AsyncGenerator[int, None]: @@ -494,7 +494,7 @@ async def user() -> None: [typing fixtures/typing-full.pyi] [case testAsyncGeneratorAsend] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import AsyncGenerator async def f() -> None: @@ -515,7 +515,7 @@ async def h() -> None: [typing fixtures/typing-full.pyi] [case testAsyncGeneratorAthrow] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import AsyncGenerator async def gen() -> AsyncGenerator[str, int]: @@ -534,7 +534,7 @@ async def h() -> None: [typing fixtures/typing-full.pyi] [case testAsyncGeneratorNoSyncIteration] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import AsyncGenerator async def gen() -> AsyncGenerator[int, None]: @@ -553,7 +553,7 @@ main:9: error: Iterable expected main:9: error: "AsyncGenerator[int, None]" has no attribute "__iter__"; maybe "__aiter__"? [case testAsyncGeneratorNoYieldFrom] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import AsyncGenerator async def f() -> AsyncGenerator[int, None]: @@ -566,7 +566,7 @@ async def gen() -> AsyncGenerator[int, None]: [typing fixtures/typing-full.pyi] [case testAsyncGeneratorNoReturnWithValue] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import AsyncGenerator async def return_int() -> AsyncGenerator[int, None]: diff --git a/test-data/unit/check-class-namedtuple.test b/test-data/unit/check-class-namedtuple.test index 2e6d5cff55fa..2f838fb4458b 100644 --- a/test-data/unit/check-class-namedtuple.test +++ b/test-data/unit/check-class-namedtuple.test @@ -1,12 +1,12 @@ [case testNewNamedTupleOldPythonVersion] -# flags: --python-version 3.5 +# flags: --python-version 3.5 --no-site-packages from typing import NamedTuple class E(NamedTuple): # E: NamedTuple class syntax is only supported in Python 3.6 pass [case testNewNamedTupleNoUnderscoreFields] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -15,7 +15,7 @@ class X(NamedTuple): _z: int # E: NamedTuple field name cannot start with an underscore: _z [case testNewNamedTupleAccessingAttributes] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -28,7 +28,7 @@ x.y x.z # E: "X" has no attribute "z" [case testNewNamedTupleAttributesAreReadOnly] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -43,7 +43,7 @@ a: A a.x = 5 # E: Property "x" defined in "A" is read-only [case testNewNamedTupleCreateWithPositionalArguments] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -57,7 +57,7 @@ x = X(1) # E: Too few arguments for "X" x = X(1, '2', 3) # E: Too many arguments for "X" [case testNewNamedTupleShouldBeSingleBase] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class A: ... @@ -65,7 +65,7 @@ class X(NamedTuple, A): # E: NamedTuple should be a single base pass [case testCreateNewNamedTupleWithKeywordArguments] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -78,7 +78,7 @@ x = X(x=1, z=1) # E: Unexpected keyword argument "z" for "X" x = X(y='x') # E: Missing positional argument "x" in call to "X" [case testNewNamedTupleCreateAndUseAsTuple] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -90,7 +90,7 @@ a, b = x a, b, c = x # E: Need more than 2 values to unpack (3 expected) [case testNewNamedTupleWithItemTypes] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class N(NamedTuple): @@ -106,7 +106,7 @@ x, y = n x = y # E: Incompatible types in assignment (expression has type "str", variable has type "int") [case testNewNamedTupleConstructorArgumentTypes] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class N(NamedTuple): @@ -119,7 +119,7 @@ N(1, 'x') N(b='x', a=1) [case testNewNamedTupleAsBaseClass] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class N(NamedTuple): @@ -136,7 +136,7 @@ i, s = x s, s = x # E: Incompatible types in assignment (expression has type "int", variable has type "str") [case testNewNamedTupleSelfTypeWithNamedTupleAsBase] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class A(NamedTuple): @@ -155,7 +155,7 @@ class B(A): [out] [case testNewNamedTupleTypeReferenceToClassDerivedFrom] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class A(NamedTuple): @@ -177,7 +177,7 @@ class B(A): [out] [case testNewNamedTupleSubtyping] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple, Tuple class A(NamedTuple): @@ -197,7 +197,7 @@ t = b a = b [case testNewNamedTupleSimpleTypeInference] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple, Tuple class A(NamedTuple): @@ -214,7 +214,7 @@ a = (1,) # E: Incompatible types in assignment (expression has type "Tuple[int] [builtins fixtures/list.pyi] [case testNewNamedTupleMissingClassAttribute] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class MyNamedTuple(NamedTuple): @@ -224,14 +224,14 @@ class MyNamedTuple(NamedTuple): MyNamedTuple.x # E: "Type[MyNamedTuple]" has no attribute "x" [case testNewNamedTupleEmptyItems] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class A(NamedTuple): ... [case testNewNamedTupleForwardRef] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class A(NamedTuple): @@ -243,7 +243,7 @@ a = A(B()) a = A(1) # E: Argument 1 to "A" has incompatible type "int"; expected "B" [case testNewNamedTupleProperty] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class A(NamedTuple): @@ -260,7 +260,7 @@ C(2).b [builtins fixtures/property.pyi] [case testNewNamedTupleAsDict] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple, Any class X(NamedTuple): @@ -273,7 +273,7 @@ reveal_type(x._asdict()) # E: Revealed type is 'builtins.dict[builtins.str, Any [builtins fixtures/dict.pyi] [case testNewNamedTupleReplaceTyped] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -286,7 +286,7 @@ x._replace(x=5) x._replace(y=5) # E: Argument "y" to "_replace" of "X" has incompatible type "int"; expected "str" [case testNewNamedTupleFields] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -301,7 +301,7 @@ reveal_type(X.__annotations__) # E: Revealed type is 'builtins.dict[builtins.st [builtins fixtures/dict.pyi] [case testNewNamedTupleUnit] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -312,7 +312,7 @@ x._replace() x._fields[0] # E: Tuple index out of range [case testNewNamedTupleJoinNamedTuple] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -327,7 +327,7 @@ reveal_type([X(3, 'b'), Y(1, 'a')]) # E: Revealed type is 'builtins.list[Tuple[ [builtins fixtures/list.pyi] [case testNewNamedTupleJoinTuple] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -340,7 +340,7 @@ reveal_type([X(1, 'a'), (3, 'b')]) # E: Revealed type is 'builtins.list[Tuple[b [builtins fixtures/list.pyi] [case testNewNamedTupleWithTooManyArguments] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -349,7 +349,7 @@ class X(NamedTuple): def f(self): pass [case testNewNamedTupleWithInvalidItems2] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages import typing class X(typing.NamedTuple): @@ -369,7 +369,7 @@ main:9: error: Non-default NamedTuple fields cannot follow default fields [builtins fixtures/list.pyi] [case testNewNamedTupleWithoutTypesSpecified] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -377,7 +377,7 @@ class X(NamedTuple): y = 2 # E: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" [case testTypeUsingTypeCNamedTuple] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import NamedTuple, Type class N(NamedTuple): @@ -391,7 +391,7 @@ def f(a: Type[N]): main:8: error: Unsupported type Type["N"] [case testNewNamedTupleWithDefaults] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import List, NamedTuple, Optional class X(NamedTuple): @@ -431,7 +431,7 @@ UserDefined(1) # E: Argument 1 to "UserDefined" has incompatible type "int"; ex [builtins fixtures/list.pyi] [case testNewNamedTupleWithDefaultsStrictOptional] -# flags: --fast-parser --strict-optional --python-version 3.6 +# flags: --fast-parser --strict-optional --python-version 3.6 --no-site-packages from typing import List, NamedTuple, Optional class HasNone(NamedTuple): @@ -450,7 +450,7 @@ class CannotBeNone(NamedTuple): [builtins fixtures/list.pyi] [case testNewNamedTupleWrongType] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): @@ -458,14 +458,14 @@ class X(NamedTuple): y: int = 'not an int' # E: Incompatible types in assignment (expression has type "str", variable has type "int") [case testNewNamedTupleErrorInDefault] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): x: int = 1 + '1' # E: Unsupported operand types for + ("int" and "str") [case testNewNamedTupleInheritance] -# flags: --fast-parser --python-version 3.6 +# flags: --fast-parser --python-version 3.6 --no-site-packages from typing import NamedTuple class X(NamedTuple): diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 9137345d141e..772b2a76f1ca 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -4135,7 +4135,7 @@ class CQA(Q1): pass class CQW(six.with_metaclass(M, Q1)): pass # E: Inconsistent metaclass structure for 'CQW' [case testSixMetaclassErrors_python2] -# flags: --python-version 2.7 +# flags: --python-version 2.7 --no-site-packages import six class M(type): pass class C4(six.with_metaclass(M)): # E: Multiple metaclass definitions diff --git a/test-data/unit/check-expressions.test b/test-data/unit/check-expressions.test index 0b8607b06254..341bb13ed80e 100644 --- a/test-data/unit/check-expressions.test +++ b/test-data/unit/check-expressions.test @@ -1111,13 +1111,13 @@ a = None # type: Any '%b' % 1 # E: Format character 'b' is only supported on bytes patterns [case testStringInterPolationPython2] -# flags: --python-version 2.7 +# flags: --python-version 2.7 --no-site-packages b'%b' % 1 # E: Format character 'b' is only supported in Python 3.5 and later b'%s' % 1 b'%a' % 1 # E: Format character 'a' is only supported in Python 3 [case testBytesInterpolationBefore35] -# flags: --python-version 3.4 +# flags: --python-version 3.4 --no-site-packages b'%b' % 1 # E: Unsupported left operand type for % ("bytes") [case testBytesInterpolation] diff --git a/test-data/unit/check-fastparse.test b/test-data/unit/check-fastparse.test index e6aaa04f1f35..38f286602cde 100644 --- a/test-data/unit/check-fastparse.test +++ b/test-data/unit/check-fastparse.test @@ -67,7 +67,7 @@ def f7(x): # E: invalid type comment or annotation [case testFastParseInvalidTypes3] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages # All of these should not crash from typing import Callable, Tuple, Iterable diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index 183561ca2836..30c2a5861f28 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -406,7 +406,7 @@ class B: pass class A: pass [case testDefaultArgumentExpressionsPython2] -# flags: --python-version 2.7 +# flags: --python-version 2.7 --no-site-packages from typing import Tuple def f(x = B()): # E: Incompatible default for argument "x" (default has type "B", argument has type "A") # type: (A) -> None @@ -417,7 +417,7 @@ class B: pass class A: pass [case testDefaultTupleArgumentExpressionsPython2] -# flags: --python-version 2.7 +# flags: --python-version 2.7 --no-site-packages from typing import Tuple def f((x, y) = (A(), B())): # E: Incompatible default for tuple argument 1 (default has type "Tuple[A, B]", argument has type "Tuple[B, B]") # type: (Tuple[B, B]) -> None @@ -2116,12 +2116,12 @@ a.__eq__(other=a) # E: Unexpected keyword argument "other" for "__eq__" of "A" [builtins fixtures/bool.pyi] [case testTupleArguments] -# flags: --python-version 2.7 +# flags: --python-version 2.7 --no-site-packages def f(a, (b, c), d): pass [case testTupleArgumentsFastparse] -# flags: --python-version 2.7 +# flags: --python-version 2.7 --no-site-packages def f(a, (b, c), d): pass diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 9c99d7b038e9..ea551efdcf71 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -586,7 +586,7 @@ reveal_type(wrap(z)) # E: Revealed type is '__main__.Node[builtins.int, builtins main:13: error: Argument 2 to "Node" has incompatible type "int"; expected "str" [case testGenericTypeAliasesWrongAliases] -# flags: --show-column-numbers --python-version 3.6 +# flags: --show-column-numbers --python-version 3.6 --no-site-packages from typing import TypeVar, Generic, List, Callable, Tuple, Union T = TypeVar('T') S = TypeVar('S') diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index f89a0e9513a4..5b820ab23345 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -719,7 +719,7 @@ def call(c: Callable[[int], Any], i: int) -> None: [out] [case testCallableMeetAndJoin] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import Callable, Any, TypeVar class A: ... diff --git a/test-data/unit/check-newsyntax.test b/test-data/unit/check-newsyntax.test index 2ed26e4f8a81..25e13c20f9c2 100644 --- a/test-data/unit/check-newsyntax.test +++ b/test-data/unit/check-newsyntax.test @@ -1,15 +1,15 @@ [case testNewSyntaxRequire36] -# flags: --python-version 3.5 +# flags: --python-version 3.5 --no-site-packages x: int = 5 # E: Variable annotation syntax is only supported in Python 3.6 and greater [out] [case testNewSyntaxSyntaxError] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages x: int: int # E: invalid syntax [out] [case testNewSyntaxBasics] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages x: int x = 5 y: int = 5 @@ -23,7 +23,7 @@ zzz: str # E: Name 'zzz' already defined [out] [case testNewSyntaxWithDict] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import Dict, Any d: Dict[int, str] = {} @@ -34,7 +34,7 @@ d['ab'] = 'ab' # E: Invalid index type "str" for "Dict[int, str]"; expected typ [out] [case testNewSyntaxWithRevealType] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from typing import Dict def tst_local(dct: Dict[int, T]) -> Dict[T, int]: @@ -46,7 +46,7 @@ reveal_type(tst_local({1: 'a'})) # E: Revealed type is 'builtins.dict[builtins. [out] [case testNewSyntaxWithInstanceVars] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages class TstInstance: a: str def __init__(self) -> None: @@ -59,27 +59,27 @@ TstInstance().a = 'ab' [out] [case testNewSyntaxWithClassVars] -# flags: --strict-optional --python-version 3.6 +# flags: --strict-optional --python-version 3.6 --no-site-packages class CCC: a: str = None # E: Incompatible types in assignment (expression has type "None", variable has type "str") [out] [case testNewSyntaxWithStrictOptional] -# flags: --strict-optional --python-version 3.6 +# flags: --strict-optional --python-version 3.6 --no-site-packages strict: int strict = None # E: Incompatible types in assignment (expression has type "None", variable has type "int") strict2: int = None # E: Incompatible types in assignment (expression has type "None", variable has type "int") [out] [case testNewSyntaxWithStrictOptionalFunctions] -# flags: --strict-optional --python-version 3.6 +# flags: --strict-optional --python-version 3.6 --no-site-packages def f() -> None: x: int x = None # E: Incompatible types in assignment (expression has type "None", variable has type "int") [out] [case testNewSyntaxWithStrictOptionalClasses] -# flags: --strict-optional --python-version 3.6 +# flags: --strict-optional --python-version 3.6 --no-site-packages class C: def meth(self) -> None: x: int = None # E: Incompatible types in assignment (expression has type "None", variable has type "int") @@ -87,7 +87,7 @@ class C: [out] [case testNewSyntaxSpecialAssign] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages class X: x: str x[0]: int @@ -100,17 +100,17 @@ main:5: error: Type cannot be declared in assignment to non-self attribute main:5: error: "str" has no attribute "x" [case testNewSyntaxAsyncComprehensionError] -# flags: --python-version 3.5 +# flags: --python-version 3.5 --no-site-packages async def f(): results = [i async for i in aiter() if i % 2] # E: Async comprehensions are only supported in Python 3.6 and greater [case testNewSyntaxFstringError] -# flags: --python-version 3.5 +# flags: --python-version 3.5 --no-site-packages f'' # E: Format strings are only supported in Python 3.6 and greater [case testNewSyntaxFStringBasics] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages f'foobar' f'{"foobar"}' f'foo{"bar"}' @@ -122,13 +122,13 @@ a = f'{"foobar"}' [builtins fixtures/f_string.pyi] [case testNewSyntaxFStringExpressionsOk] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages f'.{1 + 1}.' f'.{1 + 1}.{"foo" + "bar"}' [builtins fixtures/f_string.pyi] [case testNewSyntaxFStringExpressionsErrors] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages f'{1 + ""}' f'.{1 + ""}' [builtins fixtures/f_string.pyi] @@ -137,7 +137,7 @@ main:2: error: Unsupported operand types for + ("int" and "str") main:3: error: Unsupported operand types for + ("int" and "str") [case testNewSyntaxFStringParseFormatOptions] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages value = 10.5142 width = 10 precision = 4 @@ -145,7 +145,7 @@ f'result: {value:{width}.{precision}}' [builtins fixtures/f_string.pyi] [case testNewSyntaxFStringSingleField] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages v = 1 reveal_type(f'{v}') # E: Revealed type is 'builtins.str' reveal_type(f'{1}') # E: Revealed type is 'builtins.str' diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test index 3b0abadbf408..614f924580bd 100644 --- a/test-data/unit/check-overloading.test +++ b/test-data/unit/check-overloading.test @@ -153,7 +153,7 @@ class B: pass [builtins fixtures/isinstance.pyi] [case testTypeCheckOverloadWithImplementationPy2] -# flags: --python-version 2.7 +# flags: --python-version 2.7 --no-site-packages from typing import overload @overload diff --git a/test-data/unit/check-python2.test b/test-data/unit/check-python2.test index 4011ef57f4e7..04474dbf6149 100644 --- a/test-data/unit/check-python2.test +++ b/test-data/unit/check-python2.test @@ -246,7 +246,7 @@ class Foo: pass exec('print 1 + 1') [case testUnicodeDocStrings] -# flags: --python-version=2.7 +# flags: --python-version=2.7 --no-site-packages __doc__ = u"unicode" class A: diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 460ff93a5b8c..a7eb0bd3a3e5 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -271,7 +271,7 @@ class B: pass [builtins fixtures/tuple.pyi] [case testMultipleAssignmentWithSquareBracketTuplesPython2] -# flags: --python-version 2.7 +# flags: --python-version 2.7 --no-site-packages from typing import Tuple def avoid_confusing_test_parser(): diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index 757ad6be8c60..e56dd7b3b896 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -78,7 +78,7 @@ p = Point(x='meaning_of_life', y=1337) # E: Incompatible types (expression has -- Define TypedDict (Class syntax) [case testCanCreateTypedDictWithClass] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class Point(TypedDict): @@ -90,7 +90,7 @@ reveal_type(p) # E: Revealed type is 'TypedDict('__main__.Point', {'x': builtin [builtins fixtures/dict.pyi] [case testCanCreateTypedDictWithSubclass] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class Point1D(TypedDict): @@ -104,7 +104,7 @@ reveal_type(p) # E: Revealed type is 'TypedDict('__main__.Point2D', {'x': built [builtins fixtures/dict.pyi] [case testCanCreateTypedDictWithSubclass2] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class Point1D(TypedDict): @@ -117,7 +117,7 @@ reveal_type(p) # E: Revealed type is 'TypedDict('__main__.Point2D', {'x': built [builtins fixtures/dict.pyi] [case testCanCreateTypedDictClassEmpty] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class EmptyDict(TypedDict): @@ -131,7 +131,7 @@ reveal_type(p) # E: Revealed type is 'TypedDict('__main__.EmptyDict', {})' -- Define TypedDict (Class syntax errors) [case testCanCreateTypedDictWithClassOldVersion] -# flags: --python-version 3.5 +# flags: --python-version 3.5 --no-site-packages from mypy_extensions import TypedDict class Point(TypedDict): # E: TypedDict class syntax is only supported in Python 3.6 @@ -139,7 +139,7 @@ class Point(TypedDict): # E: TypedDict class syntax is only supported in Python [builtins fixtures/dict.pyi] [case testCannotCreateTypedDictWithClassOtherBases] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class A: pass @@ -154,7 +154,7 @@ reveal_type(p) # E: Revealed type is 'TypedDict('__main__.Point2D', {'x': built [builtins fixtures/dict.pyi] [case testCannotCreateTypedDictWithClassWithOtherStuff] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class Point(TypedDict): @@ -173,7 +173,7 @@ Point = TypedDict('Point', {'x': int, 'y': int, '_fallback': object}) [builtins fixtures/dict.pyi] [case testCanCreateTypedDictWithClassUnderscores] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class Point(TypedDict): @@ -185,7 +185,7 @@ reveal_type(p) # E: Revealed type is 'TypedDict('__main__.Point', {'x': builtins [builtins fixtures/dict.pyi] [case testCannotCreateTypedDictWithClassOverwriting] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class Bad(TypedDict): @@ -197,7 +197,7 @@ reveal_type(b) # E: Revealed type is 'TypedDict('__main__.Bad', {'x': builtins.i [builtins fixtures/dict.pyi] [case testCannotCreateTypedDictWithClassOverwriting2] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class Point1(TypedDict): @@ -212,7 +212,7 @@ reveal_type(b) # E: Revealed type is 'TypedDict('__main__.Bad', {'x': builtins.i [builtins fixtures/dict.pyi] [case testCannotCreateTypedDictWithClassOverwriting2] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class Point1(TypedDict): @@ -647,7 +647,7 @@ reveal_type(p['y']) # E: Revealed type is 'builtins.int' [builtins fixtures/dict.pyi] [case testCanGetItemOfTypedDictWithValidBytesOrUnicodeLiteralKey] -# flags: --python-version 2.7 +# flags: --python-version 2.7 --no-site-packages from mypy_extensions import TypedDict Cell = TypedDict('Cell', {'value': int}) c = Cell(value=42) diff --git a/test-data/unit/check-underscores.test b/test-data/unit/check-underscores.test index 88f95ef4d2fa..adaaec88336f 100644 --- a/test-data/unit/check-underscores.test +++ b/test-data/unit/check-underscores.test @@ -1,15 +1,15 @@ [case testUnderscoresRequire36] -# flags: --python-version 3.5 +# flags: --python-version 3.5 --no-site-packages x = 1000_000 # E: Underscores in numeric literals are only supported in Python 3.6 and greater [out] [case testUnderscoresSyntaxError] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages x = 1000_000_ # E: invalid token [out] [case testUnderscoresBasics] -# flags: --python-version 3.6 +# flags: --python-version 3.6 --no-site-packages x: int x = 1000_000 x = 0x_FF_FF_FF_FF diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index b86154302f8c..cbfcb3974383 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -434,7 +434,7 @@ x = 1 [out] [case testCustomSysVersionInfo] -# flags: --python-version 3.5 +# flags: --python-version 3.5 --no-site-packages import sys if sys.version_info == (3, 5): x = "foo" @@ -445,7 +445,7 @@ reveal_type(x) # E: Revealed type is 'builtins.str' [out] [case testCustomSysVersionInfo2] -# flags: --python-version 3.5 +# flags: --python-version 3.5 --no-site-packages import sys if sys.version_info == (3, 6): x = "foo" diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test index 86aae2d344f4..4becdb18e23f 100644 --- a/test-data/unit/cmdline.test +++ b/test-data/unit/cmdline.test @@ -581,7 +581,7 @@ m.py:6: error: Explicit "Any" is not allowed m.py:9: error: Explicit "Any" is not allowed [case testDisallowAnyExplicitVarDeclaration] -# cmd: mypy m.py +# cmd: mypy --python-version=3.6 m.py [file mypy.ini] [[mypy] @@ -601,7 +601,7 @@ m.py:3: error: Explicit "Any" is not allowed m.py:5: error: Explicit "Any" is not allowed [case testDisallowAnyExplicitGenericVarDeclaration] -# cmd: mypy m.py +# cmd: mypy --python-version=3.6 m.py [file mypy.ini] [[mypy] @@ -785,7 +785,7 @@ N = TypedDict('N', {'x': str, 'y': List}) # no error m.py:4: error: Explicit "Any" is not allowed [case testDisallowAnyGenericsTupleNoTypeParams] -# cmd: mypy m.py +# cmd: mypy --python-version=3.6 m.py [file mypy.ini] [[mypy] [[mypy-m] @@ -821,7 +821,7 @@ def g(s: List[Tuple[str, str]]) -> None: pass # no error m.py:3: error: Missing type parameters for generic type [case testDisallowAnyGenericsTypeType] -# cmd: mypy m.py +# cmd: mypy --python-version=3.6 m.py [file mypy.ini] [[mypy] [[mypy-m] @@ -858,7 +858,7 @@ def g(l: L[str]) -> None: pass # no error m.py:5: error: Missing type parameters for generic type [case testDisallowAnyGenericsGenericAlias] -# cmd: mypy m.py +# cmd: mypy --python-version=3.6 m.py [file mypy.ini] [[mypy] [[mypy-m] @@ -882,7 +882,7 @@ m.py:7: error: Missing type parameters for generic type m.py:11: error: Missing type parameters for generic type [case testDisallowAnyGenericsPlainList] -# cmd: mypy m.py +# cmd: mypy --python-version=3.6 m.py [file mypy.ini] [[mypy] [[mypy-m] @@ -906,7 +906,7 @@ m.py:8: error: Need type annotation for 'x' m.py:9: error: Missing type parameters for generic type [case testDisallowAnyGenericsCustomGenericClass] -# cmd: mypy m.py +# cmd: mypy --python-version=3.6 m.py [file mypy.ini] [[mypy] [[mypy-m] diff --git a/test-data/unit/diff.test b/test-data/unit/diff.test index 841b5648c077..131dd39fb6fb 100644 --- a/test-data/unit/diff.test +++ b/test-data/unit/diff.test @@ -577,6 +577,7 @@ __main__.Point __main__.p [case testTypedDict2] +# flags: --python-version 3.6 --no-site-packages from mypy_extensions import TypedDict class Point(TypedDict): x: int diff --git a/test-data/unit/reports.test b/test-data/unit/reports.test index 8343212fc8df..850ed128b883 100644 --- a/test-data/unit/reports.test +++ b/test-data/unit/reports.test @@ -281,7 +281,7 @@ Total 0 16 100.00% [case testAnyExpressionsReportTypesOfAny] -# cmd: mypy --any-exprs-report report n.py +# cmd: mypy --no-site-packages --python-version=3.6 --any-exprs-report report n.py [file n.py] from typing import Any, List