| -- 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.11 |
| [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.7 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 testPythonVersionTooOld36] |
| # cmd: mypy -c pass |
| [file mypy.ini] |
| \[mypy] |
| python_version = 3.6 |
| [out] |
| mypy.ini: [mypy]: python_version: Python 3.6 is not supported (must be 3.7 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 testPythonVersionAccepted37] |
| # cmd: mypy -c pass |
| [file mypy.ini] |
| \[mypy] |
| python_version = 3.7 |
| [out] |
| |
| [case testPythonVersionAccepted311] |
| # cmd: mypy -c pass |
| [file mypy.ini] |
| \[mypy] |
| python_version = 3.11 |
| [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 testDisallowAnyGenericsBuiltinCollectionsPre39] |
| # cmd: mypy m.py |
| [file mypy.ini] |
| \[mypy] |
| python_version = 3.8 |
| \[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] |