| -- Tests for command line parsing | |
| -- ------------------------------ | |
| -- | |
| -- The initial line specifies the command line, in the format | |
| -- | |
| -- # cmd: mypy <options> | |
| -- | |
| -- Note that # flags: --some-flag IS NOT SUPPORTED. | |
| -- Use # cmd: mypy --some-flag ... | |
| -- | |
| -- '== Return code: <value>' is added to the output when the process return code | |
| -- is "nonobvious" -- that is, when it is something other than 0 if there are no | |
| -- messages and 1 if there are. | |
| -- Directories/packages on the command line | |
| -- ---------------------------------------- | |
| [case testCmdlinePackage] | |
| # cmd: mypy pkg | |
| [file pkg/__init__.py] | |
| [file pkg/a.py] | |
| undef | |
| [file pkg/subpkg/__init__.py] | |
| [file pkg/subpkg/a.py] | |
| undef | |
| import pkg.subpkg.a | |
| [out] | |
| pkg/a.py:1: error: Name "undef" is not defined | |
| pkg/subpkg/a.py:1: error: Name "undef" is not defined | |
| [case testCmdlinePackageSlash] | |
| # cmd: mypy pkg/ | |
| [file pkg/__init__.py] | |
| [file pkg/a.py] | |
| undef | |
| [file pkg/subpkg/__init__.py] | |
| [file pkg/subpkg/a.py] | |
| undef | |
| import pkg.subpkg.a | |
| [out] | |
| pkg/a.py:1: error: Name "undef" is not defined | |
| pkg/subpkg/a.py:1: error: Name "undef" is not defined | |
| [case testCmdlineNonPackage] | |
| # cmd: mypy dir | |
| [file dir/a.py] | |
| undef | |
| [file dir/subdir/b.py] | |
| undef | |
| [out] | |
| dir/a.py:1: error: Name "undef" is not defined | |
| dir/subdir/b.py:1: error: Name "undef" is not defined | |
| [case testCmdlineNonPackageDuplicate] | |
| # cmd: mypy dir | |
| [file dir/a.py] | |
| undef | |
| [file dir/subdir/a.py] | |
| undef | |
| [out] | |
| dir/a.py: error: Duplicate module named "a" (also at "dir/subdir/a.py") | |
| dir/a.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info | |
| dir/a.py: note: Common resolutions include: a) using `--exclude` to avoid checking one of them, b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or adjusting MYPYPATH | |
| == Return code: 2 | |
| [case testCmdlineNonPackageSlash] | |
| # cmd: mypy dir/ | |
| [file dir/a.py] | |
| undef | |
| import b | |
| [file dir/subdir/b.py] | |
| undef | |
| import a | |
| [out] | |
| dir/a.py:1: error: Name "undef" is not defined | |
| dir/subdir/b.py:1: error: Name "undef" is not defined | |
| [case testCmdlinePackageContainingSubdir] | |
| # cmd: mypy pkg | |
| [file pkg/__init__.py] | |
| [file pkg/a.py] | |
| undef | |
| import pkg.a | |
| [file pkg/subdir/a.py] | |
| undef | |
| import pkg.a | |
| [out] | |
| pkg/a.py:1: error: Name "undef" is not defined | |
| pkg/subdir/a.py:1: error: Name "undef" is not defined | |
| [case testCmdlineNonPackageContainingPackage] | |
| # cmd: mypy dir | |
| [file dir/a.py] | |
| undef | |
| import subpkg.a | |
| [file dir/subpkg/__init__.py] | |
| [file dir/subpkg/a.py] | |
| undef | |
| [out] | |
| dir/subpkg/a.py:1: error: Name "undef" is not defined | |
| dir/a.py:1: error: Name "undef" is not defined | |
| [case testCmdlineInvalidPackageName] | |
| # cmd: mypy dir/sub.pkg/a.py | |
| [file dir/sub.pkg/__init__.py] | |
| [file dir/sub.pkg/a.py] | |
| undef | |
| [out] | |
| sub.pkg is not a valid Python package name | |
| == Return code: 2 | |
| [case testBadFileEncoding] | |
| # cmd: mypy a.py | |
| [file a.py] | |
| # coding: uft-8 | |
| [out] | |
| mypy: can't decode file 'a.py': unknown encoding: uft-8 | |
| == Return code: 2 | |
| -- ' | |
| [case testCannotIgnoreDuplicateModule] | |
| # cmd: mypy one/mod/__init__.py two/mod/__init__.py | |
| [file one/mod/__init__.py] | |
| # type: ignore | |
| [file two/mod/__init__.py] | |
| # type: ignore | |
| [out] | |
| two/mod/__init__.py: error: Duplicate module named "mod" (also at "one/mod/__init__.py") | |
| two/mod/__init__.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info | |
| two/mod/__init__.py: note: Common resolutions include: a) using `--exclude` to avoid checking one of them, b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or adjusting MYPYPATH | |
| == Return code: 2 | |
| -- Note that we use `----`, because this is how `--` is escaped while `--` is a comment starter. | |
| [case testFlagsFile] | |
| # cmd: mypy @flagsfile | |
| [file flagsfile] | |
| ----always-true=FLAG | |
| main.py | |
| [file main.py] | |
| x: int | |
| FLAG = False | |
| if not FLAG: | |
| x = "unreachable" | |
| [case testConfigFile] | |
| # cmd: mypy main.py | |
| [file mypy.ini] | |
| \[mypy] | |
| always_true = FLAG | |
| [file main.py] | |
| x: int | |
| FLAG = False | |
| if not FLAG: | |
| x = "unreachable" | |
| [case testErrorContextConfig] | |
| # cmd: mypy main.py | |
| [file mypy.ini] | |
| \[mypy] | |
| show_error_context=True | |
| [file main.py] | |
| def f() -> None: | |
| 0 + "" | |
| [out] | |
| main.py: note: In function "f": | |
| main.py:2: error: Unsupported operand types for + ("int" and "str") | |
| [case testAltConfigFile] | |
| # cmd: mypy --config-file config.ini main.py | |
| [file config.ini] | |
| \[mypy] | |
| always_true = FLAG | |
| [file main.py] | |
| x: int | |
| FLAG = False | |
| if not FLAG: | |
| x = "unreachable" | |
| [case testNoConfigFile] | |
| # cmd: mypy main.py --config-file= | |
| [file mypy.ini] | |
| \[mypy] | |
| warn_unused_ignores = True | |
| [file main.py] | |
| # type: ignore | |
| [case testPerFileConfigSection] | |
| # cmd: mypy x.py y.py z.py | |
| [file mypy.ini] | |
| \[mypy] | |
| disallow_untyped_defs = True | |
| \[mypy-y] | |
| disallow_untyped_defs = False | |
| \[mypy-z] | |
| disallow_untyped_calls = True | |
| [file x.py] | |
| def f(a): | |
| pass | |
| def g(a: int) -> int: | |
| return f(a) | |
| [file y.py] | |
| def f(a): | |
| pass | |
| def g(a: int) -> int: | |
| return f(a) | |
| [file z.py] | |
| def f(a): | |
| pass | |
| def g(a: int) -> int: | |
| return f(a) | |
| [out] | |
| z.py:1: error: Function is missing a type annotation | |
| z.py:4: error: Call to untyped function "f" in typed context | |
| x.py:1: error: Function is missing a type annotation | |
| [case testPerFileConfigSectionMultipleMatchesDisallowed] | |
| # cmd: mypy xx.py xy.py yx.py yy.py | |
| [file mypy.ini] | |
| \[mypy] | |
| \[mypy-*x*] | |
| disallow_untyped_defs = True | |
| \[mypy-*y*] | |
| disallow_untyped_calls = True | |
| [file xx.py] | |
| def f(a): pass | |
| def g(a: int) -> int: return f(a) | |
| [file xy.py] | |
| def f(a): pass | |
| def g(a: int) -> int: return f(a) | |
| [file yx.py] | |
| def f(a): pass | |
| def g(a: int) -> int: return f(a) | |
| [file yy.py] | |
| def f(a): pass | |
| def g(a: int) -> int: return f(a) | |
| [out] | |
| mypy.ini: [mypy-*x*]: Patterns must be fully-qualified module names, optionally with '*' in some components (e.g spam.*.eggs.*) | |
| mypy.ini: [mypy-*y*]: Patterns must be fully-qualified module names, optionally with '*' in some components (e.g spam.*.eggs.*) | |
| == Return code: 0 | |
| [case testMultipleGlobConfigSection] | |
| # cmd: mypy x.py y.py z.py | |
| [file mypy.ini] | |
| \[mypy] | |
| \[mypy-x.*,z.*] | |
| disallow_untyped_defs = True | |
| [file x.py] | |
| def f(a): pass | |
| [file y.py] | |
| def f(a): pass | |
| [file z.py] | |
| def f(a): pass | |
| [out] | |
| z.py:1: error: Function is missing a type annotation | |
| x.py:1: error: Function is missing a type annotation | |
| [case testConfigErrorNoSection] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| [out] | |
| mypy.ini: No [mypy] section in config file | |
| == Return code: 0 | |
| [case testConfigErrorUnknownFlag] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| \[mypy] | |
| bad = 0 | |
| [out] | |
| mypy.ini: [mypy]: Unrecognized option: bad = 0 | |
| == Return code: 0 | |
| [case testConfigErrorBadFlag] | |
| # cmd: mypy a.py | |
| [file mypy.ini] | |
| \[mypy] | |
| disallow-untyped-defs = True | |
| [file a.py] | |
| def f(): | |
| pass | |
| [out] | |
| mypy.ini: [mypy]: Unrecognized option: disallow-untyped-defs = True | |
| == Return code: 0 | |
| [case testConfigErrorBadBoolean] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| \[mypy] | |
| ignore_missing_imports = nah | |
| [out] | |
| mypy.ini: [mypy]: ignore_missing_imports: Not a boolean: nah | |
| == Return code: 0 | |
| [case testConfigErrorNotPerFile] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| \[mypy] | |
| \[mypy-*] | |
| python_version = 3.4 | |
| [out] | |
| mypy.ini: [mypy-*]: Per-module sections should only specify per-module flags (python_version) | |
| == Return code: 0 | |
| [case testConfigMypyPath] | |
| # cmd: mypy file.py | |
| [file mypy.ini] | |
| \[mypy] | |
| mypy_path = | |
| foo_dir:bar_dir | |
| , baz_dir | |
| [file foo_dir/foo.pyi] | |
| def foo(x: int) -> str: ... | |
| [file bar_dir/bar.pyi] | |
| def bar(x: str) -> list: ... | |
| [file baz_dir/baz.pyi] | |
| def baz(x: list) -> dict: ... | |
| [file file.py] | |
| import no_stubs | |
| from foo import foo | |
| from bar import bar | |
| from baz import baz | |
| baz(bar(foo(42))) | |
| baz(bar(foo('oof'))) | |
| [out] | |
| file.py:1: error: Cannot find implementation or library stub for module named "no_stubs" | |
| file.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports | |
| file.py:6: error: Argument 1 to "foo" has incompatible type "str"; expected "int" | |
| [case testIgnoreErrorsConfig] | |
| # cmd: mypy x.py y.py | |
| [file mypy.ini] | |
| \[mypy] | |
| \[mypy-x] | |
| ignore_errors = True | |
| [file x.py] | |
| x: str = 5 | |
| [file y.py] | |
| x: str = 5 | |
| [out] | |
| y.py:1: error: Incompatible types in assignment (expression has type "int", variable has type "str") | |
| [case testConfigFollowImportsNormal] | |
| # cmd: mypy main.py | |
| [file main.py] | |
| from a import x | |
| x + 0 | |
| x + '' # E | |
| import a | |
| a.x + 0 | |
| a.x + '' # E | |
| a.y # E | |
| a + 0 # E | |
| [file mypy.ini] | |
| \[mypy] | |
| follow_imports = normal | |
| [file a.py] | |
| x = 0 | |
| x += '' # Error reported here | |
| [out] | |
| a.py:2: error: Unsupported operand types for + ("int" and "str") | |
| main.py:3: error: Unsupported operand types for + ("int" and "str") | |
| main.py:6: error: Unsupported operand types for + ("int" and "str") | |
| main.py:7: error: Module has no attribute "y" | |
| main.py:8: error: Unsupported operand types for + (Module and "int") | |
| [case testConfigFollowImportsSysPath] | |
| # cmd: mypy main.py | |
| [file main.py] | |
| from a import x | |
| x + 0 | |
| x + '' # E | |
| import a | |
| a.x + 0 | |
| a.x + '' # E | |
| a.y # E | |
| a + 0 # E | |
| [file mypy.ini] | |
| \[mypy] | |
| follow_imports = normal | |
| no_silence_site_packages = True | |
| [file pypath/a/__init__.py] | |
| x = 0 | |
| x += '' # Error reported here | |
| [file pypath/a/py.typed] | |
| [out] | |
| pypath/a/__init__.py:2: error: Unsupported operand types for + ("int" and "str") | |
| main.py:3: error: Unsupported operand types for + ("int" and "str") | |
| main.py:6: error: Unsupported operand types for + ("int" and "str") | |
| main.py:7: error: Module has no attribute "y" | |
| main.py:8: error: Unsupported operand types for + (Module and "int") | |
| [case testConfigFollowImportsSilent] | |
| # cmd: mypy main.py | |
| [file main.py] | |
| from a import x | |
| x + '' | |
| import a | |
| a.x + '' | |
| a.y | |
| a + 0 | |
| [file mypy.ini] | |
| \[mypy] | |
| follow_imports = silent | |
| [file a.py] | |
| x = 0 | |
| x += '' # No error reported | |
| [out] | |
| main.py:2: error: Unsupported operand types for + ("int" and "str") | |
| main.py:4: error: Unsupported operand types for + ("int" and "str") | |
| main.py:5: error: Module has no attribute "y" | |
| main.py:6: error: Unsupported operand types for + (Module and "int") | |
| [case testConfigFollowImportsSkip] | |
| # cmd: mypy main.py | |
| [file main.py] | |
| from a import x | |
| reveal_type(x) # Expect Any | |
| import a | |
| reveal_type(a.x) # Expect Any | |
| [file mypy.ini] | |
| \[mypy] | |
| follow_imports = skip | |
| [file a.py] | |
| / # No error reported | |
| [out] | |
| main.py:2: note: Revealed type is "Any" | |
| main.py:4: note: Revealed type is "Any" | |
| == Return code: 0 | |
| [case testConfigFollowImportsError] | |
| # cmd: mypy main.py | |
| [file main.py] | |
| from a import x # Error reported here | |
| reveal_type(x) # Expect Any | |
| import a | |
| reveal_type(a.x) # Expect Any | |
| [file mypy.ini] | |
| \[mypy] | |
| follow_imports = error | |
| [file a.py] | |
| / # No error reported | |
| [out] | |
| main.py:1: error: Import of "a" ignored | |
| main.py:1: note: (Using --follow-imports=error, module not passed on command line) | |
| main.py:2: note: Revealed type is "Any" | |
| main.py:4: note: Revealed type is "Any" | |
| [case testConfigFollowImportsSelective] | |
| # cmd: mypy main.py | |
| [file mypy.ini] | |
| \[mypy] | |
| \[mypy-normal] | |
| follow_imports = normal | |
| \[mypy-silent] | |
| follow_imports = silent | |
| \[mypy-skip] | |
| follow_imports = skip | |
| \[mypy-error] | |
| follow_imports = error | |
| [file main.py] | |
| import normal | |
| import silent | |
| import skip | |
| import error | |
| reveal_type(normal.x) | |
| reveal_type(silent.x) | |
| reveal_type(skip) | |
| reveal_type(error) | |
| [file normal.py] | |
| x = 0 | |
| x += '' | |
| [file silent.py] | |
| x = 0 | |
| x += '' | |
| [file skip.py] | |
| bla bla | |
| [file error.py] | |
| bla bla | |
| [out] | |
| normal.py:2: error: Unsupported operand types for + ("int" and "str") | |
| main.py:4: error: Import of "error" ignored | |
| main.py:4: note: (Using --follow-imports=error, module not passed on command line) | |
| main.py:5: note: Revealed type is "builtins.int" | |
| main.py:6: note: Revealed type is "builtins.int" | |
| main.py:7: note: Revealed type is "Any" | |
| main.py:8: note: Revealed type is "Any" | |
| [case testConfigFollowImportsInvalid] | |
| # cmd: mypy main.py | |
| [file mypy.ini] | |
| \[mypy] | |
| follow_imports =True | |
| [file main.py] | |
| [out] | |
| mypy.ini: [mypy]: follow_imports: invalid choice 'True' (choose from 'normal', 'silent', 'skip', 'error') | |
| == Return code: 0 | |
| [case testConfigSilentMissingImportsOff] | |
| # cmd: mypy main.py | |
| [file main.py] | |
| import missing # Expect error here | |
| reveal_type(missing.x) # Expect Any | |
| [file mypy.ini] | |
| \[mypy] | |
| ignore_missing_imports = False | |
| [out] | |
| main.py:1: error: Cannot find implementation or library stub for module named "missing" | |
| main.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports | |
| main.py:2: note: Revealed type is "Any" | |
| [case testConfigSilentMissingImportsOn] | |
| # cmd: mypy main.py | |
| [file main.py] | |
| import missing # No error here | |
| reveal_type(missing.x) # Expect Any | |
| [file mypy.ini] | |
| \[mypy] | |
| ignore_missing_imports = True | |
| [out] | |
| main.py:2: note: Revealed type is "Any" | |
| == Return code: 0 | |
| [case testFailedImportOnWrongCWD] | |
| # cmd: mypy main.py | |
| # cwd: main/subdir1/subdir2 | |
| [file main/subdir1/subdir2/main.py] | |
| import parent | |
| import grandparent | |
| import missing | |
| [file main/subdir1/subdir2/__init__.py] | |
| [file main/subdir1/parent.py] | |
| [file main/subdir1/__init__.py] | |
| [file main/grandparent.py] | |
| [file main/__init__.py] | |
| [out] | |
| main.py:1: error: Cannot find implementation or library stub for module named "parent" | |
| main.py:1: note: You may be running mypy in a subpackage, mypy should be run on the package root | |
| main.py:2: error: Cannot find implementation or library stub for module named "grandparent" | |
| main.py:3: error: Cannot find implementation or library stub for module named "missing" | |
| main.py:3: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports | |
| [case testImportInParentButNoInit] | |
| # cmd: mypy main.py | |
| # cwd: main/not_a_package | |
| [file main/not_a_package/main.py] | |
| import needs_init | |
| [file main/needs_init.py] | |
| [file main/__init__.py] | |
| [out] | |
| main.py:1: error: Cannot find implementation or library stub for module named "needs_init" | |
| main.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports | |
| [case testConfigNoErrorForUnknownXFlagInSubsection] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| \[mypy] | |
| \[mypy-foo] | |
| x_bad = 0 | |
| [out] | |
| [case testDotInFilenameOKScript] | |
| # cmd: mypy a.b.py c.d.pyi | |
| [file a.b.py] | |
| undef | |
| [file c.d.pyi] | |
| whatever | |
| [out] | |
| c.d.pyi:1: error: Name "whatever" is not defined | |
| a.b.py:1: error: Name "undef" is not defined | |
| [case testDotInFilenameOKFolder] | |
| # cmd: mypy my.folder | |
| [file my.folder/tst.py] | |
| undef | |
| [out] | |
| my.folder/tst.py:1: error: Name "undef" is not defined | |
| [case testDotInFilenameNoImport] | |
| # cmd: mypy main.py | |
| [file main.py] | |
| import a.b | |
| [file a.b.py] | |
| whatever | |
| [out] | |
| main.py:1: error: Cannot find implementation or library stub for module named "a.b" | |
| main.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports | |
| main.py:1: error: Cannot find implementation or library stub for module named "a" | |
| [case testPythonVersionWrongFormatPyProjectTOML] | |
| # cmd: mypy -c pass | |
| [file pyproject.toml] | |
| \[tool.mypy] | |
| python_version = 3.10 | |
| [out] | |
| pyproject.toml: [mypy]: python_version: Python 3.1 is not supported (must be 3.4 or higher). You may need to put quotes around your Python version | |
| == Return code: 0 | |
| [case testPythonVersionTooOld10] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| \[mypy] | |
| python_version = 1.0 | |
| [out] | |
| mypy.ini: [mypy]: python_version: Python major version '1' out of range (must be 3) | |
| == Return code: 0 | |
| [case testPythonVersionTooOld33] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| \[mypy] | |
| python_version = 3.3 | |
| [out] | |
| mypy.ini: [mypy]: python_version: Python 3.3 is not supported (must be 3.4 or higher) | |
| == Return code: 0 | |
| [case testPythonVersionTooNew40] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| \[mypy] | |
| python_version = 4.0 | |
| [out] | |
| mypy.ini: [mypy]: python_version: Python major version '4' out of range (must be 3) | |
| == Return code: 0 | |
| [case testPythonVersionTooDead27] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| \[mypy] | |
| python_version = 2.7 | |
| [out] | |
| usage: mypy [-h] [-v] [-V] [more options; see below] | |
| [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [files ...] | |
| mypy: error: Mypy no longer supports checking Python 2 code. Consider pinning to mypy<0.980 if you need to check Python 2 code. | |
| == Return code: 2 | |
| [case testPythonVersionAccepted34] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| \[mypy] | |
| python_version = 3.4 | |
| [out] | |
| [case testPythonVersionAccepted36] | |
| # cmd: mypy -c pass | |
| [file mypy.ini] | |
| \[mypy] | |
| python_version = 3.6 | |
| [out] | |
| -- This should be a dumping ground for tests of plugins that are sensitive to | |
| -- typeshed changes. | |
| [case testTypeshedSensitivePlugins] | |
| # cmd: mypy int_pow.py | |
| [file int_pow.py] | |
| a = 1 | |
| b = a + 2 | |
| reveal_type(a**0) | |
| reveal_type(a**1) | |
| reveal_type(a**2) | |
| reveal_type(a**-0) | |
| reveal_type(a**-1) | |
| reveal_type(a**(-2)) | |
| reveal_type(a**b) | |
| reveal_type(a.__pow__(2)) | |
| reveal_type(a.__pow__(a)) | |
| [out] | |
| int_pow.py:3: note: Revealed type is "Literal[1]" | |
| int_pow.py:4: note: Revealed type is "builtins.int" | |
| int_pow.py:5: note: Revealed type is "builtins.int" | |
| int_pow.py:6: note: Revealed type is "Literal[1]" | |
| int_pow.py:7: note: Revealed type is "builtins.float" | |
| int_pow.py:8: note: Revealed type is "builtins.float" | |
| int_pow.py:9: note: Revealed type is "Any" | |
| int_pow.py:10: note: Revealed type is "builtins.int" | |
| int_pow.py:11: note: Revealed type is "Any" | |
| == Return code: 0 | |
| [case testDisallowAnyGenericsBuiltinCollections] | |
| # cmd: mypy m.py | |
| [file mypy.ini] | |
| \[mypy] | |
| python_version=3.6 | |
| \[mypy-m] | |
| disallow_any_generics = True | |
| [file m.py] | |
| s = tuple([1, 2, 3]) # no error | |
| def f(t: tuple) -> None: pass | |
| def g() -> list: pass | |
| def h(s: dict) -> None: pass | |
| def i(s: set) -> None: pass | |
| def j(s: frozenset) -> None: pass | |
| [out] | |
| m.py:3: error: Implicit generic "Any". Use "typing.Tuple" and specify generic parameters | |
| m.py:4: error: Implicit generic "Any". Use "typing.List" and specify generic parameters | |
| m.py:5: error: Implicit generic "Any". Use "typing.Dict" and specify generic parameters | |
| m.py:6: error: Implicit generic "Any". Use "typing.Set" and specify generic parameters | |
| m.py:7: error: Implicit generic "Any". Use "typing.FrozenSet" and specify generic parameters | |
| [case testDisallowAnyGenericsTypingCollections] | |
| # cmd: mypy m.py | |
| [file mypy.ini] | |
| \[mypy] | |
| \[mypy-m] | |
| disallow_any_generics = True | |
| [file m.py] | |
| from typing import Tuple, List, Dict, Set, FrozenSet | |
| def f(t: Tuple) -> None: pass | |
| def g() -> List: pass | |
| def h(s: Dict) -> None: pass | |
| def i(s: Set) -> None: pass | |
| def j(s: FrozenSet) -> None: pass | |
| [out] | |
| m.py:3: error: Missing type parameters for generic type "Tuple" | |
| m.py:4: error: Missing type parameters for generic type "List" | |
| m.py:5: error: Missing type parameters for generic type "Dict" | |
| m.py:6: error: Missing type parameters for generic type "Set" | |
| m.py:7: error: Missing type parameters for generic type "FrozenSet" | |
| [case testSectionInheritance] | |
| # cmd: mypy a | |
| [file a/__init__.py] | |
| 0() | |
| [file a/foo.py] | |
| 0() | |
| [file a/b/__init__.py] | |
| [file a/b/c/__init__.py] | |
| 0() | |
| [file a/b/c/d/__init__.py] | |
| [file a/b/c/d/e/__init__.py] | |
| from typing import List | |
| def g(x: List) -> None: pass | |
| g(None) | |
| [file mypy.ini] | |
| \[mypy] | |
| allow_any_generics = True | |
| \[mypy-a.*] | |
| ignore_errors = True | |
| \[mypy-a.b.*] | |
| disallow_any_generics = True | |
| ignore_errors = True | |
| \[mypy-a.b.c.*] | |
| ignore_errors = True | |
| \[mypy-a.b.c.d.*] | |
| ignore_errors = True | |
| \[mypy-a.b.c.d.e.*] | |
| ignore_errors = True | |
| strict_optional = True | |
| \[mypy-a.b.c.d.e] | |
| ignore_errors = False | |
| [out] | |
| a/b/c/d/e/__init__.py:2: error: Missing type parameters for generic type "List" | |
| a/b/c/d/e/__init__.py:3: error: Argument 1 to "g" has incompatible type "None"; expected "List[Any]" | |
| [case testDisallowUntypedDefsAndGenerics] | |
| # cmd: mypy a.py | |
| [file mypy.ini] | |
| \[mypy] | |
| disallow_untyped_defs = True | |
| disallow_any_generics = True | |
| [file a.py] | |
| def get_tasks(self): | |
| return 'whatever' | |
| [out] | |
| a.py:1: error: Function is missing a return type annotation | |
| [case testMissingFile] | |
| # cmd: mypy nope.py | |
| [out] | |
| mypy: can't read file 'nope.py': No such file or directory | |
| == Return code: 2 | |
| --' | |
| [case testParseError] | |
| # cmd: mypy a.py | |
| [file a.py] | |
| def foo( | |
| [out] | |
| a.py:1: error: unexpected EOF while parsing | |
| == Return code: 2 | |
| [out version>=3.10] | |
| a.py:1: error: '(' was never closed | |
| == Return code: 2 | |
| [case testParseErrorAnnots] | |
| # cmd: mypy a.py | |
| [file a.py] | |
| def foo(x): | |
| # type: (str, int) -> None | |
| return | |
| [out] | |
| a.py:1: error: Type signature has too many arguments | |
| [case testModulesAndPackages] | |
| # cmd: mypy --package p.a --package p.b --module c | |
| [file p/__init__.py] | |
| [file p/a.py] | |
| def foo(x): | |
| # type: (int) -> str | |
| return "x" | |
| foo("wrong") | |
| [file p/b/__init__.py] | |
| from ..a import foo | |
| def bar(a): | |
| # type: (int) -> str | |
| return foo(a) | |
| bar("wrong") | |
| [file c.py] | |
| import p.b | |
| p.b.bar("wrong") | |
| [out] | |
| p/a.py:4: error: Argument 1 to "foo" has incompatible type "str"; expected "int" | |
| p/b/__init__.py:5: error: Argument 1 to "bar" has incompatible type "str"; expected "int" | |
| c.py:2: error: Argument 1 to "bar" has incompatible type "str"; expected "int" | |
| [case testSrcPEP420Packages] | |
| # cmd: mypy -p anamespace --namespace-packages | |
| [file mypy.ini] | |
| \[mypy] | |
| mypy_path = src | |
| [file src/setup.cfg] | |
| [file src/anamespace/foo/__init__.py] | |
| [file src/anamespace/foo/bar.py] | |
| def bar(a: int, b: int) -> str: | |
| return a + b | |
| [out] | |
| src/anamespace/foo/bar.py:2: error: Incompatible return value type (got "int", expected "str") | |
| [case testNestedPEP420Packages] | |
| # cmd: mypy -p pkg --namespace-packages | |
| [file pkg/a1/b/c/d/e.py] | |
| x = 0 # type: str | |
| [file pkg/a1/b/f.py] | |
| from pkg.a1.b.c.d.e import x | |
| x() | |
| [file pkg/a2/__init__.py] | |
| [file pkg/a2/b/c/d/e.py] | |
| x = 0 # type: str | |
| [file pkg/a2/b/f.py] | |
| from pkg.a2.b.c.d.e import x | |
| x() | |
| [out] | |
| pkg/a2/b/c/d/e.py:1: error: Incompatible types in assignment (expression has type "int", variable has type "str") | |
| pkg/a1/b/c/d/e.py:1: error: Incompatible types in assignment (expression has type "int", variable has type "str") | |
| pkg/a2/b/f.py:2: error: "str" not callable | |
| pkg/a1/b/f.py:2: error: "str" not callable | |
| [case testFollowImportStubs1] | |
| # cmd: mypy main.py | |
| [file mypy.ini] | |
| \[mypy] | |
| \[mypy-math.*] | |
| follow_imports = error | |
| follow_imports_for_stubs = True | |
| [file main.py] | |
| import math | |
| math.frobnicate() | |
| [out] | |
| main.py:1: error: Import of "math" ignored | |
| main.py:1: note: (Using --follow-imports=error, module not passed on command line) | |
| [case testFollowImportStubs2] | |
| # cmd: mypy main.py | |
| [file mypy.ini] | |
| \[mypy] | |
| \[mypy-math.*] | |
| follow_imports = skip | |
| follow_imports_for_stubs = True | |
| [file main.py] | |
| import math | |
| math.frobnicate() | |
| [case testShadowFile1] | |
| # cmd: mypy --shadow-file source.py shadow.py source.py | |
| [file source.py] | |
| def foo() -> str: | |
| return "bar" | |
| [file shadow.py] | |
| def bar() -> str: | |
| return 14 | |
| [out] | |
| source.py:2: error: Incompatible return value type (got "int", expected "str") | |
| [case testShadowFile2] | |
| # cmd: mypy --shadow-file s1.py shad1.py --shadow-file s2.py shad2.py --shadow-file s3.py shad3.py s1.py s2.py s3.py s4.py | |
| [file s1.py] | |
| def foo() -> str: | |
| return "bar" | |
| [file shad1.py] | |
| def bar() -> str: | |
| return 14 | |
| [file s2.py] | |
| def baz() -> str: | |
| return 14 | |
| [file shad2.py] | |
| def baz() -> int: | |
| return 14 | |
| [file s3.py] | |
| def qux() -> str: | |
| return "bar" | |
| [file shad3.py] | |
| def foo() -> int: | |
| return [42] | |
| [file s4.py] | |
| def foo() -> str: | |
| return 9 | |
| [out] | |
| s4.py:2: error: Incompatible return value type (got "int", expected "str") | |
| s3.py:2: error: Incompatible return value type (got "List[int]", expected "int") | |
| s1.py:2: error: Incompatible return value type (got "int", expected "str") | |
| [case testConfigWarnUnusedSection1] | |
| # cmd: mypy foo.py quux.py spam/eggs.py | |
| [file mypy.ini] | |
| \[mypy] | |
| warn_unused_configs = True | |
| incremental = False | |
| \[mypy-bar] | |
| \[mypy-foo] | |
| \[mypy-baz.*] | |
| \[mypy-quux.*] | |
| \[mypy-spam.*] | |
| \[mypy-spam.eggs] | |
| \[mypy-emarg.*] | |
| \[mypy-emarg.hatch] | |
| -- Currently we don't treat an unstructured pattern like a.*.b as unused | |
| -- if it matches another section (like a.x.b). This would be reasonable | |
| -- to change. ' | |
| \[mypy-a.*.b] | |
| \[mypy-a.*.c] | |
| \[mypy-a.x.b] | |
| [file foo.py] | |
| [file quux.py] | |
| [file spam/__init__.py] | |
| [file spam/eggs.py] | |
| [out] | |
| Warning: unused section(s) in mypy.ini: [mypy-bar], [mypy-baz.*], [mypy-emarg.*], [mypy-emarg.hatch], [mypy-a.*.c], [mypy-a.x.b] | |
| == Return code: 0 | |
| [case testConfigUnstructuredGlob] | |
| # cmd: mypy emarg foo | |
| [file mypy.ini] | |
| \[mypy] | |
| ignore_errors = true | |
| \[mypy-*.lol] | |
| ignore_errors = false | |
| \[mypy-emarg.*] | |
| ignore_errors = false | |
| \[mypy-emarg.*.villip.*] | |
| ignore_errors = true | |
| \[mypy-emarg.hatch.villip.mankangulisk] | |
| ignore_errors = false | |
| [file emarg/__init__.py] | |
| [file emarg/foo.py] | |
| fail | |
| [file emarg/villip.py] | |
| fail | |
| [file emarg/hatch/__init__.py] | |
| [file emarg/hatch/villip/__init__.py] | |
| [file emarg/hatch/villip/nus.py] | |
| fail | |
| [file emarg/hatch/villip/mankangulisk.py] | |
| fail | |
| [file foo/__init__.py] | |
| [file foo/lol.py] | |
| fail | |
| [out] | |
| foo/lol.py:1: error: Name "fail" is not defined | |
| emarg/foo.py:1: error: Name "fail" is not defined | |
| emarg/hatch/villip/mankangulisk.py:1: error: Name "fail" is not defined | |
| [case testPackageRootEmpty] | |
| # cmd: mypy --no-namespace-packages --package-root= a/b/c.py main.py | |
| [file a/b/c.py] | |
| [file main.py] | |
| import a.b.c | |
| [case testPackageRootEmptyNamespacePackage] | |
| # cmd: mypy --namespace-packages --package-root= a/b/c.py main.py | |
| [file a/b/c.py] | |
| [file main.py] | |
| import a.b.c | |
| [case testPackageRootNonEmpty] | |
| # cmd: mypy --package-root=a/ a/b/c.py main.py | |
| [file a/b/c.py] | |
| [file main.py] | |
| import b.c | |
| [case testPackageRootMultiple1] | |
| # cmd: mypy --package-root=. --package-root=a a/b/c.py d.py main.py | |
| [file a/b/c.py] | |
| [file d.py] | |
| [file main.py] | |
| import b.c | |
| import d | |
| [case testPackageRootMultiple2] | |
| # cmd: mypy --package-root=a/ --package-root=./ a/b/c.py d.py main.py | |
| [file a/b/c.py] | |
| [file d.py] | |
| [file main.py] | |
| import b.c | |
| import d | |
| [case testCacheMap] | |
| -- This just checks that a valid --cache-map triple is accepted. | |
| -- (Errors are too verbose to check.) | |
| # cmd: mypy a.py --no-sqlite-cache --cache-map a.py a.meta.json a.data.json | |
| [file a.py] | |
| [out] | |
| [case testIniFiles] | |
| # cmd: mypy | |
| [file mypy.ini] | |
| \[mypy] | |
| files = a.py, b.py | |
| [file a.py] | |
| fail | |
| [file b.py] | |
| fail | |
| [out] | |
| b.py:1: error: Name "fail" is not defined | |
| a.py:1: error: Name "fail" is not defined | |
| [case testIniFilesGlobbing] | |
| # cmd: mypy | |
| [file mypy.ini] | |
| \[mypy] | |
| files = **/*.py | |
| [file a/b.py] | |
| fail | |
| [file c.py] | |
| fail | |
| [out] | |
| a/b.py:1: error: Name "fail" is not defined | |
| c.py:1: error: Name "fail" is not defined | |
| [case testIniFilesCmdlineOverridesConfig] | |
| # cmd: mypy override.py | |
| [file mypy.ini] | |
| \[mypy] | |
| files = config.py | |
| [out] | |
| mypy: can't read file 'override.py': No such file or directory | |
| == Return code: 2 | |
| [case testErrorSummaryOnSuccess] | |
| # cmd: mypy --error-summary good.py | |
| [file good.py] | |
| x = 2 + 2 | |
| [out] | |
| Success: no issues found in 1 source file | |
| == Return code: 0 | |
| [case testErrorSummaryOnFail] | |
| # cmd: mypy --error-summary bad.py | |
| [file bad.py] | |
| 42 + 'no' | |
| [out] | |
| bad.py:1: error: Unsupported operand types for + ("int" and "str") | |
| Found 1 error in 1 file (checked 1 source file) | |
| [case testErrorSummaryOnFailNotes] | |
| # cmd: mypy --error-summary bad.py | |
| [file bad.py] | |
| from typing import List | |
| x = [] # type: List[float] | |
| y = [] # type: List[int] | |
| x = y | |
| [out] | |
| bad.py:4: error: Incompatible types in assignment (expression has type "List[int]", variable has type "List[float]") | |
| bad.py:4: note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance | |
| bad.py:4: note: Consider using "Sequence" instead, which is covariant | |
| Found 1 error in 1 file (checked 1 source file) | |
| [case testErrorSummaryOnFailTwoErrors] | |
| # cmd: mypy --error-summary bad.py foo.py | |
| [file bad.py] | |
| 42 + 'no' | |
| 42 + 'no' | |
| [file foo.py] | |
| [out] | |
| bad.py:1: error: Unsupported operand types for + ("int" and "str") | |
| bad.py:2: error: Unsupported operand types for + ("int" and "str") | |
| Found 2 errors in 1 file (checked 2 source files) | |
| [case testErrorSummaryOnFailTwoFiles] | |
| # cmd: mypy --error-summary bad.py bad2.py | |
| [file bad.py] | |
| 42 + 'no' | |
| [file bad2.py] | |
| 42 + 'no' | |
| [out] | |
| bad2.py:1: error: Unsupported operand types for + ("int" and "str") | |
| bad.py:1: error: Unsupported operand types for + ("int" and "str") | |
| Found 2 errors in 2 files (checked 2 source files) | |
| [case testErrorSummaryOnBadUsage] | |
| # cmd: mypy --error-summary missing.py | |
| [out] | |
| mypy: can't read file 'missing.py': No such file or directory | |
| == Return code: 2 | |
| [case testShowSourceCodeSnippetsWrappedFormatting] | |
| # cmd: mypy --pretty some_file.py | |
| [file some_file.py] | |
| from typing import Union | |
| 42 + 'no way' | |
| class OneCustomClassName: | |
| def some_interesting_method(self, arg: AnotherCustomClassDefinedBelow) -> AnotherCustomClassDefinedBelow: | |
| ... | |
| class AnotherCustomClassDefinedBelow: | |
| def another_even_more_interesting_method(self, arg: Union[int, str, float]) -> None: | |
| self.very_important_attribute_with_long_name: OneCustomClassName = OneCustomClassName().some_interesting_method(arg) | |
| [out] | |
| some_file.py:3: error: Unsupported operand types for + ("int" and "str") | |
| 42 + 'no way' | |
| ^~~~~~~~ | |
| some_file.py:11: error: Incompatible types in assignment (expression has type | |
| "AnotherCustomClassDefinedBelow", variable has type "OneCustomClassName") | |
| ...t_attribute_with_long_name: OneCustomClassName = OneCustomClassName().... | |
| ^~~~~~~~~~~~~~~~~~~~~... | |
| some_file.py:11: error: Argument 1 to "some_interesting_method" of | |
| "OneCustomClassName" has incompatible type "Union[int, str, float]"; expected | |
| "AnotherCustomClassDefinedBelow" | |
| ...OneCustomClassName = OneCustomClassName().some_interesting_method(arg) | |
| ^~~ | |
| [case testShowSourceCodeSnippetsBlockingError] | |
| # cmd: mypy --pretty --show-error-codes some_file.py | |
| [file some_file.py] | |
| it_looks_like_we_started_typing_something_but_then. = did_not_notice(an_extra_dot) | |
| [out] | |
| some_file.py:1: error: invalid syntax [syntax] | |
| ...ooks_like_we_started_typing_something_but_then. = did_not_notice(an_ex... | |
| ^ | |
| == Return code: 2 | |
| [case testTabRenderingUponError] | |
| # cmd: mypy --pretty tabs.py | |
| [file tabs.py] | |
| def test_tabs() -> str: | |
| return None | |
| def test_between(x: str) -> None: ... | |
| test_between(1 + 1) | |
| [out] | |
| tabs.py:2: error: Incompatible return value type (got "None", expected "str") | |
| return None | |
| ^~~~ | |
| tabs.py:4: error: Argument 1 to "test_between" has incompatible type "int"; | |
| expected "str" | |
| test_between(1 + 1) | |
| ^~~~~~~~~~~~ | |
| [case testErrorMessageWhenOpenPydFile] | |
| # cmd: mypy a.pyd | |
| [file a.pyd] | |
| # coding: uft-8 | |
| [out] | |
| mypy: stubgen does not support .pyd files: 'a.pyd' | |
| == Return code: 2 | |
| [case testDuplicateModules] | |
| # cmd: mypy src | |
| [file mypy.ini] | |
| \[mypy] | |
| mypy_path = src | |
| [file src/__init__.py] | |
| [file src/a.py] | |
| import foo.bar | |
| [file src/foo/__init__.py] | |
| [file src/foo/bar.py] | |
| 1+'x' | |
| [out] | |
| src/foo/bar.py: error: Source file found twice under different module names: "src.foo.bar" and "foo.bar" | |
| src/foo/bar.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info | |
| src/foo/bar.py: note: Common resolutions include: a) adding `__init__.py` somewhere, b) using `--explicit-package-bases` or adjusting MYPYPATH | |
| == Return code: 2 | |
| [case testEnableInvalidErrorCode] | |
| # cmd: mypy --enable-error-code YOLO test.py | |
| [file test.py] | |
| x = 1 | |
| [out] | |
| usage: mypy [-h] [-v] [-V] [more options; see below] | |
| [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [files ...] | |
| mypy: error: Invalid error code(s): YOLO | |
| == Return code: 2 | |
| [case testDisableInvalidErrorCode] | |
| # cmd: mypy --disable-error-code YOLO test.py | |
| [file test.py] | |
| x = 1 | |
| [out] | |
| usage: mypy [-h] [-v] [-V] [more options; see below] | |
| [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [files ...] | |
| mypy: error: Invalid error code(s): YOLO | |
| == Return code: 2 | |
| [case testEnableAndDisableInvalidErrorCode] | |
| # cmd: mypy --disable-error-code YOLO --enable-error-code YOLO2 test.py | |
| [file test.py] | |
| x = 1 | |
| [out] | |
| usage: mypy [-h] [-v] [-V] [more options; see below] | |
| [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [files ...] | |
| mypy: error: Invalid error code(s): YOLO, YOLO2 | |
| == Return code: 2 | |
| [case testEnableValidAndInvalidErrorCode] | |
| # cmd: mypy --enable-error-code attr-defined --enable-error-code YOLO test.py | |
| [file test.py] | |
| x = 1 | |
| [out] | |
| usage: mypy [-h] [-v] [-V] [more options; see below] | |
| [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [files ...] | |
| mypy: error: Invalid error code(s): YOLO | |
| == Return code: 2 | |
| [case testDisableValidAndInvalidErrorCode] | |
| # cmd: mypy --disable-error-code attr-defined --disable-error-code YOLO test.py | |
| [file test.py] | |
| x = 1 | |
| [out] | |
| usage: mypy [-h] [-v] [-V] [more options; see below] | |
| [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [files ...] | |
| mypy: error: Invalid error code(s): YOLO | |
| == Return code: 2 | |
| [case testStubsDirectory] | |
| # cmd: mypy --error-summary pkg-stubs | |
| [file pkg-stubs/__init__.pyi] | |
| [file pkg-stubs/thing.pyi] | |
| class Thing: ... | |
| [out] | |
| Success: no issues found in 2 source files | |
| == Return code: 0 | |
| [case testStubsDirectoryFile] | |
| # cmd: mypy --error-summary pkg-stubs/thing.pyi | |
| [file pkg-stubs/__init__.pyi] | |
| [file pkg-stubs/thing.pyi] | |
| class Thing: ... | |
| [out] | |
| Success: no issues found in 1 source file | |
| == Return code: 0 | |
| [case testStubsSubDirectory] | |
| # cmd: mypy --error-summary src/pkg-stubs | |
| [file src/pkg-stubs/__init__.pyi] | |
| [file src/pkg-stubs/thing.pyi] | |
| class Thing: ... | |
| [out] | |
| Success: no issues found in 2 source files | |
| == Return code: 0 | |
| [case testStubsSubDirectoryFile] | |
| # cmd: mypy --error-summary src/pkg-stubs/thing.pyi | |
| [file src/pkg-stubs/__init__.pyi] | |
| [file src/pkg-stubs/thing.pyi] | |
| class Thing: ... | |
| [out] | |
| Success: no issues found in 1 source file | |
| == Return code: 0 | |
| [case testBlocker] | |
| # cmd: mypy pkg --error-summary --disable-error-code syntax | |
| [file pkg/x.py] | |
| public static void main(String[] args) | |
| [file pkg/y.py] | |
| x: str = 0 | |
| [out] | |
| pkg/x.py:1: error: invalid syntax | |
| Found 1 error in 1 file (errors prevented further checking) | |
| == Return code: 2 | |
| [out version>=3.10] | |
| pkg/x.py:1: error: invalid syntax. Perhaps you forgot a comma? | |
| Found 1 error in 1 file (errors prevented further checking) | |
| == Return code: 2 | |
| [out version>=3.10.3] | |
| pkg/x.py:1: error: invalid syntax | |
| Found 1 error in 1 file (errors prevented further checking) | |
| == Return code: 2 | |
| [case testCmdlinePackageAndFile] | |
| # cmd: mypy -p pkg file | |
| [out] | |
| usage: mypy [-h] [-v] [-V] [more options; see below] | |
| [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [files ...] | |
| mypy: error: May only specify one of: module/package, files, or command. | |
| == Return code: 2 | |
| [case testCmdlinePackageAndIniFiles] | |
| # cmd: mypy -p pkg | |
| [file mypy.ini] | |
| \[mypy] | |
| files=file | |
| [file pkg.py] | |
| x = 0 # type: str | |
| [file file.py] | |
| y = 0 # type: str | |
| [out] | |
| pkg.py:1: error: Incompatible types in assignment (expression has type "int", variable has type "str") | |
| [case testCmdlineModuleAndIniFiles] | |
| # cmd: mypy -m pkg | |
| [file mypy.ini] | |
| \[mypy] | |
| files=file | |
| [file pkg.py] | |
| x = 0 # type: str | |
| [file file.py] | |
| y = 0 # type: str | |
| [out] | |
| pkg.py:1: error: Incompatible types in assignment (expression has type "int", variable has type "str") | |
| [case testCmdlineNonInteractiveWithoutInstallTypes] | |
| # cmd: mypy --non-interactive -m pkg | |
| [out] | |
| error: --non-interactive is only supported with --install-types | |
| == Return code: 2 | |
| [case testCmdlineNonInteractiveInstallTypesNothingToDo] | |
| # cmd: mypy --install-types --non-interactive -m pkg | |
| [file pkg.py] | |
| 1() | |
| [out] | |
| pkg.py:1: error: "int" not callable | |
| [case testCmdlineNonInteractiveInstallTypesNothingToDoNoError] | |
| # cmd: mypy --install-types --non-interactive -m pkg | |
| [file pkg.py] | |
| 1 + 2 | |
| [out] | |
| [case testCmdlineNonInteractiveInstallTypesNoSitePackages] | |
| # cmd: mypy --install-types --non-interactive --no-site-packages -m pkg | |
| [out] | |
| error: --install-types not supported without python executable or site packages | |
| == Return code: 2 | |
| [case testCmdlineInteractiveInstallTypesNothingToDo] | |
| # cmd: mypy --install-types -m pkg | |
| [file pkg.py] | |
| 1() | |
| [out] | |
| pkg.py:1: error: "int" not callable | |
| [case testCmdlineExclude] | |
| # cmd: mypy --exclude abc . | |
| [file abc/apkg.py] | |
| 1() | |
| [file b/bpkg.py] | |
| 1() | |
| [file c/cpkg.py] | |
| 1() | |
| [out] | |
| c/cpkg.py:1: error: "int" not callable | |
| b/bpkg.py:1: error: "int" not callable | |
| [case testCmdlineMultipleExclude] | |
| # cmd: mypy --exclude abc --exclude b/ . | |
| [file abc/apkg.py] | |
| 1() | |
| [file b/bpkg.py] | |
| 1() | |
| [file c/cpkg.py] | |
| 1() | |
| [out] | |
| c/cpkg.py:1: error: "int" not callable | |
| [case testCmdlineCfgExclude] | |
| # cmd: mypy . | |
| [file mypy.ini] | |
| \[mypy] | |
| exclude = abc | |
| [file abc/apkg.py] | |
| 1() | |
| [file b/bpkg.py] | |
| 1() | |
| [file c/cpkg.py] | |
| 1() | |
| [out] | |
| c/cpkg.py:1: error: "int" not callable | |
| b/bpkg.py:1: error: "int" not callable | |
| [case testCmdlineCfgMultipleExclude] | |
| # cmd: mypy . | |
| [file mypy.ini] | |
| \[mypy] | |
| exclude = (?x)( | |
| ^abc/ | |
| |^b/ | |
| ) | |
| [file abc/apkg.py] | |
| 1() | |
| [file b/bpkg.py] | |
| 1() | |
| [file c/cpkg.py] | |
| 1() | |
| [out] | |
| c/cpkg.py:1: error: "int" not callable | |
| [case testCmdlineTimingStats] | |
| # cmd: mypy --timing-stats timing.txt . | |
| [file b/__init__.py] | |
| [file b/c.py] | |
| class C: pass | |
| [outfile-re timing.txt] | |
| .* | |
| b \d+ | |
| b\.c \d+ | |
| .* | |
| [case testCmdlineEnableIncompleteFeatures] | |
| # cmd: mypy --enable-incomplete-features a.py | |
| [file a.py] | |
| pass | |
| [out] | |
| Warning: --enable-incomplete-features is deprecated, use --enable-incomplete-feature=FEATURE instead | |
| == Return code: 0 | |
| [case testShadowTypingModuleEarlyLoad] | |
| # cmd: mypy dir | |
| [file dir/__init__.py] | |
| from typing import Union | |
| def foo(a: Union[int, str]) -> str: | |
| return str | |
| [file typing.py] | |
| # Since this file will be picked by mypy itself, we need it to be a fully-working typing | |
| # A bare minimum would be NamedTuple and TypedDict, which are used in runtime, | |
| # everything else technically can be just mocked. | |
| import sys | |
| import os | |
| del sys.modules["typing"] | |
| path = sys.path | |
| try: | |
| sys.path.remove(os.getcwd()) | |
| except ValueError: | |
| sys.path.remove("") # python 3.6 | |
| from typing import * | |
| sys.path = path | |
| [out] | |
| mypy: "typing.py" shadows library module "typing" | |
| note: A user-defined top-level module with name "typing" is not supported | |
| == Return code: 2 | |
| [case testCustomTypeshedDirWithRelativePathDoesNotCrash] | |
| # cmd: mypy --custom-typeshed-dir dir dir/typing.pyi | |
| [file dir/stdlib/abc.pyi] | |
| [file dir/stdlib/builtins.pyi] | |
| [file dir/stdlib/sys.pyi] | |
| [file dir/stdlib/types.pyi] | |
| [file dir/stdlib/typing.pyi] | |
| [file dir/stdlib/typing_extensions.pyi] | |
| [file dir/stdlib/_typeshed.pyi] | |
| [file dir/stdlib/_collections_abc.pyi] | |
| [file dir/stdlib/collections/abc.pyi] | |
| [file dir/stdlib/collections/__init__.pyi] | |
| [file dir/stdlib/VERSIONS] | |
| [out] | |
| Failed to find builtin module mypy_extensions, perhaps typeshed is broken? | |
| == Return code: 2 | |
| [case testRecursiveAliasesFlagDeprecated] | |
| # cmd: mypy --enable-recursive-aliases a.py | |
| [file a.py] | |
| pass | |
| [out] | |
| Warning: --enable-recursive-aliases is deprecated; recursive types are enabled by default | |
| == Return code: 0 | |
| [case testNotesOnlyResultInExitSuccess] | |
| # cmd: mypy a.py | |
| [file a.py] | |
| def f(): | |
| x: int = "no" | |
| [out] | |
| a.py:2: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs | |
| == Return code: 0 | |
| [case testCustomTypeshedDirFilePassedExplicitly] | |
| # cmd: mypy --custom-typeshed-dir dir m.py dir/stdlib/foo.pyi | |
| [file m.py] | |
| 1() | |
| [file dir/stdlib/abc.pyi] | |
| 1() # Errors are not reported from typeshed by default | |
| [file dir/stdlib/builtins.pyi] | |
| class object: pass | |
| class str(object): pass | |
| class int(object): pass | |
| class list: pass | |
| class dict: pass | |
| [file dir/stdlib/sys.pyi] | |
| [file dir/stdlib/types.pyi] | |
| [file dir/stdlib/typing.pyi] | |
| [file dir/stdlib/mypy_extensions.pyi] | |
| [file dir/stdlib/typing_extensions.pyi] | |
| [file dir/stdlib/_typeshed.pyi] | |
| [file dir/stdlib/_collections_abc.pyi] | |
| [file dir/stdlib/collections/abc.pyi] | |
| [file dir/stdlib/collections/__init__.pyi] | |
| [file dir/stdlib/foo.pyi] | |
| 1() # Errors are reported if the file was explicitly passed on the command line | |
| [file dir/stdlib/VERSIONS] | |
| [out] | |
| dir/stdlib/foo.pyi:1: error: "int" not callable | |
| m.py:1: error: "int" not callable | |
| [case testFileInPythonPathPassedExplicitly1] | |
| # cmd: mypy $CWD/pypath/foo.py | |
| [file pypath/foo.py] | |
| 1() | |
| [out] | |
| pypath/foo.py:1: error: "int" not callable | |
| [case testFileInPythonPathPassedExplicitly2] | |
| # cmd: mypy pypath/foo.py | |
| [file pypath/foo.py] | |
| 1() | |
| [out] | |
| pypath/foo.py:1: error: "int" not callable | |
| [case testFileInPythonPathPassedExplicitly3] | |
| # cmd: mypy -p foo | |
| # cwd: pypath | |
| [file pypath/foo/__init__.py] | |
| 1() | |
| [file pypath/foo/m.py] | |
| 1() | |
| [out] | |
| foo/m.py:1: error: "int" not callable | |
| foo/__init__.py:1: error: "int" not callable | |
| [case testFileInPythonPathPassedExplicitly4] | |
| # cmd: mypy -m foo | |
| # cwd: pypath | |
| [file pypath/foo.py] | |
| 1() | |
| [out] | |
| foo.py:1: error: "int" not callable | |
| [case testFileInPythonPathPassedExplicitly5] | |
| # cmd: mypy -m foo.m | |
| # cwd: pypath | |
| [file pypath/foo/__init__.py] | |
| 1() # TODO: Maybe this should generate errors as well? But how would we decide? | |
| [file pypath/foo/m.py] | |
| 1() | |
| [out] | |
| foo/m.py:1: error: "int" not callable | |
| [case testCmdlineCfgEnableErrorCodeTrailingComma] | |
| # cmd: mypy . | |
| [file mypy.ini] | |
| \[mypy] | |
| enable_error_code = | |
| truthy-bool, | |
| redundant-expr, | |
| [out] | |
| [case testCmdlineCfgDisableErrorCodeTrailingComma] | |
| # cmd: mypy . | |
| [file mypy.ini] | |
| \[mypy] | |
| disable_error_code = | |
| misc, | |
| override, | |
| [out] | |
| [case testCmdlineCfgAlwaysTrueTrailingComma] | |
| # cmd: mypy . | |
| [file mypy.ini] | |
| \[mypy] | |
| always_true = | |
| MY_VAR, | |
| [out] |