| -- 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/a.py] |
| undef |
| [out] |
| dir/a.py:1: error: Name 'undef' is not defined |
| |
| [case testCmdlineNonPackageSlash] |
| # cmd: mypy dir/ |
| [file dir/a.py] |
| undef |
| [file dir/subdir/a.py] |
| undef |
| [out] |
| dir/a.py:1: error: Name 'undef' is not defined |
| |
| [case testCmdlinePackageContainingSubdir] |
| # cmd: mypy pkg |
| [file pkg/__init__.py] |
| [file pkg/a.py] |
| undef |
| [file pkg/subdir/a.py] |
| undef |
| [out] |
| pkg/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') |
| == Return code: 2 |
| |
| [case promptsForgotInit] |
| # cmd: mypy a.py one/mod/a.py |
| [file one/__init__.py] |
| # type: ignore |
| [file a.py] |
| # type: ignore |
| [file one/mod/a.py] |
| #type: ignore |
| [out] |
| one/mod/a.py: error: Duplicate module named 'a' (also at 'a.py') |
| one/mod/a.py: error: Are you missing an __init__.py? |
| == Return code: 2 |
| |
| [case testFlagsFile] |
| # cmd: mypy @flagsfile |
| [file flagsfile] |
| -2 |
| main.py |
| [file main.py] |
| def f(): |
| try: |
| 1/0 |
| except ZeroDivisionError, err: |
| print err |
| |
| [case testConfigFile] |
| # cmd: mypy main.py |
| [file mypy.ini] |
| \[mypy] |
| python_version = 2.7 |
| [file main.py] |
| def f(): |
| try: |
| 1/0 |
| except ZeroDivisionError, err: |
| print err |
| |
| [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] |
| python_version = 2.7 |
| [file main.py] |
| def f(): |
| try: |
| 1/0 |
| except ZeroDivisionError, err: |
| print err |
| |
| [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:bar |
| , baz |
| [file foo/foo.pyi] |
| def foo(x: int) -> str: ... |
| [file bar/bar.pyi] |
| def bar(x: str) -> list: ... |
| [file baz/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/latest/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] |
| "" + 0 |
| [file y.py] |
| "" + 0 |
| [out] |
| y.py:1: error: Unsupported operand types for + ("str" and "int") |
| |
| [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 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' |
| |
| [case testConfigFollowImportsError] |
| # cmd: mypy main.py |
| [file main.py] |
| from a import x |
| reveal_type(x) # Expect Any |
| import a # Error reported here |
| 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 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/latest/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' |
| |
| [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/latest/running_mypy.html#missing-imports |
| main.py:1: error: Cannot find implementation or library stub for module named 'a' |
| |
| [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 2 or 3) |
| == Return code: 0 |
| |
| [case testPythonVersionTooOld26] |
| # cmd: mypy -c pass |
| [file mypy.ini] |
| \[mypy] |
| python_version = 2.6 |
| [out] |
| mypy.ini: [mypy]: python_version: Python 2.6 is not supported (must be 2.7) |
| == 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 testPythonVersionTooNew28] |
| # cmd: mypy -c pass |
| [file mypy.ini] |
| \[mypy] |
| python_version = 2.8 |
| [out] |
| mypy.ini: [mypy]: python_version: Python 2.8 is not supported (must be 2.7) |
| == 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 2 or 3) |
| == Return code: 0 |
| |
| [case testPythonVersionAccepted27] |
| # cmd: mypy -c pass |
| [file mypy.ini] |
| \[mypy] |
| python_version = 2.7 |
| [out] |
| |
| [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) # N: Revealed type is 'builtins.int' |
| reveal_type(a**1) # N: Revealed type is 'builtins.int' |
| reveal_type(a**2) # N: Revealed type is 'builtins.int' |
| reveal_type(a**-0) # N: Revealed type is 'builtins.int' |
| reveal_type(a**-1) # N: Revealed type is 'builtins.float' |
| reveal_type(a**(-2)) # N: Revealed type is 'builtins.float' |
| reveal_type(a**b) # N: Revealed type is 'Any' |
| reveal_type(a.__pow__(2)) # N: Revealed type is 'builtins.int' |
| reveal_type(a.__pow__(a)) # N: Revealed type is 'Any' |
| a.__pow__() # E: Too few arguments for "__pow__" of "int" |
| |
| [case testDisallowAnyUnimported] |
| # cmd: mypy main.py |
| [file mypy.ini] |
| \[mypy] |
| disallow_any_unimported = True |
| ignore_missing_imports = True |
| [file main.py] |
| from unreal import F |
| |
| def f(x: F) -> None: pass |
| [out] |
| main.py:3: error: Argument 1 to "f" becomes "Any" due to an unfollowed import |
| |
| [case testDisallowAnyExplicitDefSignature] |
| # cmd: mypy m.py |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from typing import Any, List |
| |
| def f(x: Any) -> None: |
| pass |
| |
| def g() -> Any: |
| pass |
| |
| def h() -> List[Any]: |
| pass |
| |
| [out] |
| m.py:3: error: Explicit "Any" is not allowed |
| m.py:6: error: Explicit "Any" is not allowed |
| m.py:9: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitVarDeclaration] |
| # cmd: mypy --python-version=3.6 m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from typing import Any, List |
| v: Any = '' |
| w = '' # type: Any |
| class X: |
| y = '' # type: Any |
| |
| [out] |
| m.py:2: error: Explicit "Any" is not allowed |
| m.py:3: error: Explicit "Any" is not allowed |
| m.py:5: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitGenericVarDeclaration] |
| # cmd: mypy --python-version=3.6 m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from typing import Any, List |
| v: List[Any] = [] |
| [out] |
| m.py:2: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitInheritance] |
| # cmd: mypy m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from typing import Any, List |
| |
| class C(Any): |
| pass |
| |
| class D(List[Any]): |
| pass |
| [out] |
| m.py:3: error: Explicit "Any" is not allowed |
| m.py:6: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitAlias] |
| # cmd: mypy m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from typing import Any, List |
| |
| X = Any |
| Y = List[Any] |
| |
| def foo(x: X) -> Y: # no error |
| x.nonexistent() # no error |
| return x |
| |
| [out] |
| m.py:3: error: Explicit "Any" is not allowed |
| m.py:4: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitGenericAlias] |
| # cmd: mypy m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from typing import Any, List, TypeVar, Tuple |
| |
| T = TypeVar('T') |
| |
| TupleAny = Tuple[Any, T] # error |
| |
| def foo(x: TupleAny[str]) -> None: # no error |
| pass |
| |
| def goo(x: TupleAny[Any]) -> None: # error |
| pass |
| |
| [out] |
| m.py:5: error: Explicit "Any" is not allowed |
| m.py:10: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitCast] |
| # cmd: mypy m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from typing import Any, List, cast |
| |
| x = 1 |
| y = cast(Any, x) |
| z = cast(List[Any], x) |
| [out] |
| m.py:4: error: Explicit "Any" is not allowed |
| m.py:5: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitNamedTuple] |
| # cmd: mypy m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from typing import Any, List, NamedTuple |
| |
| Point = NamedTuple('Point', [('x', List[Any]), |
| ('y', Any)]) |
| |
| [out] |
| m.py:3: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitTypeVarConstraint] |
| # cmd: mypy m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from typing import Any, List, TypeVar |
| |
| T = TypeVar('T', Any, List[Any]) |
| [out] |
| m.py:3: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitNewType] |
| # cmd: mypy m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from typing import Any, List, NewType |
| |
| Baz = NewType('Baz', Any) # this error does not come from `--disallow-any-explicit` flag |
| Bar = NewType('Bar', List[Any]) |
| |
| [out] |
| m.py:3: error: Argument 2 to NewType(...) must be subclassable (got "Any") |
| m.py:4: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitTypedDictSimple] |
| # cmd: mypy m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from mypy_extensions import TypedDict |
| from typing import Any |
| |
| M = TypedDict('M', {'x': str, 'y': Any}) # error |
| M(x='x', y=2) # no error |
| def f(m: M) -> None: pass # no error |
| [out] |
| m.py:4: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyExplicitTypedDictGeneric] |
| # cmd: mypy m.py |
| |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_explicit = True |
| |
| [file m.py] |
| from mypy_extensions import TypedDict |
| from typing import Any, List |
| |
| M = TypedDict('M', {'x': str, 'y': List[Any]}) # error |
| N = TypedDict('N', {'x': str, 'y': List}) # no error |
| [out] |
| m.py:4: error: Explicit "Any" is not allowed |
| |
| [case testDisallowAnyGenericsTupleNoTypeParams] |
| # cmd: mypy --python-version=3.6 m.py |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_generics = True |
| |
| [file m.py] |
| from typing import Tuple |
| |
| def f(s: Tuple) -> None: pass # error |
| def g(s) -> Tuple: # error |
| return 'a', 'b' |
| def h(s) -> Tuple[str, str]: # no error |
| return 'a', 'b' |
| x: Tuple = () # error |
| [out] |
| m.py:3: error: Missing type parameters for generic type "Tuple" |
| m.py:4: error: Missing type parameters for generic type "Tuple" |
| m.py:8: error: Missing type parameters for generic type "Tuple" |
| |
| [case testDisallowAnyGenericsTupleWithNoTypeParamsGeneric] |
| # cmd: mypy m.py |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_generics = True |
| |
| [file m.py] |
| from typing import Tuple, List |
| |
| def f(s: List[Tuple]) -> None: pass # error |
| def g(s: List[Tuple[str, str]]) -> None: pass # no error |
| [out] |
| m.py:3: error: Missing type parameters for generic type "Tuple" |
| |
| [case testDisallowAnyGenericsTypeType] |
| # cmd: mypy --python-version=3.6 m.py |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_generics = True |
| |
| [file m.py] |
| from typing import Type, Any |
| |
| def f(s: Type[Any]) -> None: pass # no error |
| def g(s) -> Type: # error |
| return s |
| def h(s) -> Type[str]: # no error |
| return s |
| x: Type = g(0) # error |
| [out] |
| m.py:4: error: Missing type parameters for generic type "Type" |
| m.py:8: error: Missing type parameters for generic type "Type" |
| |
| [case testDisallowAnyGenericsAliasGenericType] |
| # cmd: mypy m.py |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_generics = True |
| |
| [file m.py] |
| from typing import List |
| |
| L = List # no error |
| |
| def f(l: L) -> None: pass # error |
| def g(l: L[str]) -> None: pass # no error |
| [out] |
| m.py:5: error: Missing type parameters for generic type "L" |
| |
| [case testDisallowAnyGenericsGenericAlias] |
| # cmd: mypy --python-version=3.6 m.py |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_generics = True |
| |
| [file m.py] |
| from typing import List, TypeVar, Tuple |
| |
| T = TypeVar('T') |
| A = Tuple[T, str, T] |
| |
| def f(s: A) -> None: pass # error |
| def g(s) -> A: # error |
| return 'a', 'b', 1 |
| def h(s) -> A[str]: # no error |
| return 'a', 'b', 'c' |
| x: A = ('a', 'b', 1) # error |
| [out] |
| m.py:6: error: Missing type parameters for generic type "A" |
| m.py:7: error: Missing type parameters for generic type "A" |
| m.py:11: error: Missing type parameters for generic type "A" |
| |
| [case testDisallowAnyGenericsPlainList] |
| # cmd: mypy --python-version=3.6 m.py |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_generics = True |
| |
| [file m.py] |
| from typing import List |
| |
| def f(l: List) -> None: pass # error |
| def g(l: List[str]) -> None: pass # no error |
| def h(l: List[List]) -> None: pass # error |
| def i(l: List[List[List[List]]]) -> None: pass # error |
| |
| x = [] # error: need type annotation |
| y: List = [] # error |
| [out] |
| m.py:3: error: Missing type parameters for generic type "List" |
| m.py:5: error: Missing type parameters for generic type "List" |
| m.py:6: error: Missing type parameters for generic type "List" |
| m.py:8: error: Need type annotation for 'x' (hint: "x: List[<type>] = ...") |
| m.py:9: error: Missing type parameters for generic type "List" |
| |
| [case testDisallowAnyGenericsCustomGenericClass] |
| # cmd: mypy --python-version=3.6 m.py |
| [file mypy.ini] |
| \[mypy] |
| \[mypy-m] |
| disallow_any_generics = True |
| |
| [file m.py] |
| from typing import Generic, TypeVar, Any |
| |
| T = TypeVar('T') |
| class G(Generic[T]): pass |
| |
| def f() -> G: # error |
| return G() |
| |
| x: G[Any] = G() # no error |
| y: G = x # error |
| |
| [out] |
| m.py:6: error: Missing type parameters for generic type "G" |
| m.py:10: error: Missing type parameters for generic type "G" |
| |
| [case testDisallowAnyGenericsBuiltinCollections] |
| # cmd: mypy m.py |
| [file mypy.ini] |
| \[mypy] |
| \[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 testDisallowSubclassingAny] |
| # cmd: mypy m.py y.py |
| [file mypy.ini] |
| \[mypy] |
| disallow_subclassing_any = True |
| \[mypy-m] |
| disallow_subclassing_any = False |
| |
| [file m.py] |
| from typing import Any |
| |
| x = None # type: Any |
| |
| class ShouldBeFine(x): ... |
| |
| [file y.py] |
| from typing import Any |
| |
| x = None # type: Any |
| |
| class ShouldNotBeFine(x): ... |
| [out] |
| y.py:5: error: Class cannot subclass 'x' (has type 'Any') |
| |
| [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 |
| |
| [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 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 --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 http://mypy.readthedocs.io/en/latest/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 --python-version=3.6 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 testSpecialTypeshedGenericNote] |
| # cmd: mypy --disallow-any-generics --python-version=3.6 test.py |
| [file test.py] |
| from os import PathLike |
| from queue import Queue |
| |
| p: PathLike |
| q: Queue |
| [out] |
| test.py:4: error: Missing type parameters for generic type "_PathLike" |
| test.py:4: note: Subscripting classes that are not generic at runtime may require escaping, see https://mypy.readthedocs.io/en/latest/common_issues.html#not-generic-runtime |
| test.py:5: error: Missing type parameters for generic type "Queue" |
| test.py:5: note: Subscripting classes that are not generic at runtime may require escaping, see https://mypy.readthedocs.io/en/latest/common_issues.html#not-generic-runtime |