MYPY(1) | Mypy | MYPY(1) |
mypy - Optional static typing for Python
mypy [-h] [-v] [-V] [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [OPTIONS...] [FILES ...]
Mypy is a static type checker for Python 3 and Python 2.7. If you sprinkle your code with type annotations, mypy can type check your code and find common bugs. As mypy is a static analyzer, or a lint-like tool, the type annotations are just hints for mypy and don’t interfere when running your program. You run your program with a standard Python interpreter, and the annotations are treated effectively as comments.
Using the Python 3 function annotation syntax (using the PEP 484 notation) or a comment-based annotation syntax for Python 2 code, you will be able to efficiently annotate your code and use mypy to check the code for common errors. Mypy has a powerful and easy-to-use type system with modern features such as type inference, generics, callable types, tuple types, union types, and structural subtyping.
Mypy is invoked with the paths the user needs to check:
$ mypy foo.py bar.py some_directory
The directories are checked recursively to find Python source files.
This section documents mypy's command line interface. You can view a quick summary of the available flags by running mypy --help.
NOTE:
By default, you can specify what code you want mypy to type check by passing in the paths to what you want to have type checked:
$ mypy foo.py bar.py some_directory
Note that directories are checked recursively.
Mypy also lets you specify what code to type check in several other ways. A short summary of the relevant flags is included below: for full details, see running-mypy.
Mypy will not recursively type check any submodules of the provided module.
Mypy will recursively type check any submodules of the provided package. This flag is identical to --module apart from this behavior.
For instance, to avoid discovering any files named setup.py you could pass --exclude '/setup\.py$'. Similarly, you can ignore discovering directories with a given name by e.g. --exclude /build/ or those matching a subpath with --exclude /project/vendor/. To ignore multiple files / directories / paths, you can provide the --exclude flag more than once, e.g --exclude '/setup\.py$' --exclude '/build/'.
Note that this flag only affects recursive directory tree discovery, that is, when mypy is discovering files within a directory tree or submodules of a package to check. If you pass a file or module explicitly it will still be checked. For instance, mypy --exclude '/setup.py$' but_still_check/setup.py.
In particular, --exclude does not affect mypy's import following. You can use a per-module
:confval:`follow_imports`
Note that mypy will never recursively discover files and directories named "site-packages", "node_modules" or "__pycache__", or those whose name starts with a period, exactly as --exclude '/(site-packages|node_modules|__pycache__|\..*)/$' would. Mypy will also never recursively discover files with extensions other than .py or .pyi.
By default settings are read from mypy.ini, .mypy.ini, pyproject.toml, or setup.cfg in the current directory. Settings override mypy's built-in defaults and command line flags can override settings.
Specifying --config-file= (with no filename) will ignore all config files.
See config-file for the syntax of configuration files.
The following flags customize how exactly mypy discovers and follows imports.
:confval:`mypy_path`
Note that this flag does not suppress errors about missing names in successfully resolved modules. For example, if one has the following files:
package/__init__.py package/mod.py
Then mypy will generate the following errors with --ignore-missing-imports:
import package.unknown # No error, ignored x = package.unknown.func() # OK. 'func' is assumed to be of type 'Any' from package import unknown # No error, ignored from package.mod import NonExisting # Error: Module has no attribute 'NonExisting'
For more details, see ignore-missing-imports.
The default option is normal: mypy will follow and type check all modules. For more information on what the other options do, see Following imports.
See installed-packages for more on making PEP 561 compliant packages.
Use this flag if mypy cannot find a Python executable for the version of Python being checked, and you don't need to use PEP 561 typed packages. Otherwise, use --python-executable.
foo/
company/
foo/
a.py bar/
company/
bar/
b.py baz/
company/
baz/
c.py ...
If you are in this situation, you can enable an experimental fast path by setting the --fast-module-lookup option.
This flag affects how mypy finds modules and packages explicitly passed on the command line. It also affects how mypy determines fully qualified module names for files passed on the command line. See Mapping file paths to modules for details.
By default, mypy will assume that you intend to run your code using the same operating system and Python version you are using to run mypy itself. The following flags let you modify this behavior.
For more information on how to use these flags, see version_and_platform_checks.
This flag will attempt to find a Python executable of the corresponding version to search for PEP 561 compliant packages. If you'd like to disable this, use the --no-site-packages flag (see Import discovery for more details).
The PLATFORM parameter may be any string supported by sys.platform.
The Any type is used to represent a value that has a dynamic type. The --disallow-any family of flags will disallow various uses of the Any type in a module -- this lets us strategically disallow the use of dynamic typing in a controlled way.
The following options are available:
In addition, declaring a variable of type Any or casting to type Any is not allowed. Note that calling functions that take parameters of type Any is still allowed.
Since the module is silenced, the imported class is given a type of Any. By default mypy will assume that the subclass correctly inherited the base class even though that may not actually be the case. This flag makes mypy raise an error instead.
The following flags configure how mypy handles untyped function definitions or calls.
It will assume all arguments have type Any and always infer Any as the return type.
The following flags adjust how mypy handles values of type None. For more details, see no_strict_optional.
For example, if this flag is set, mypy would assume that the x parameter is actually of type Optional[int] in the code snippet below since the default parameter is None:
def foo(x: int = None) -> None:
print(x)
Note: This was disabled by default starting in mypy 0.980.
Note: Strict optional checking was enabled by default starting in mypy 0.600, and in previous versions it had to be explicitly enabled using --strict-optional (which is still accepted).
The following flags enable warnings for code that is sound but is potentially problematic or redundant in some way.
This flag, along with the --warn-redundant-casts flag, are both particularly useful when you are upgrading mypy. Previously, you may have needed to add casts or # type: ignore annotations to work around bugs in mypy or missing stubs for 3rd party libraries.
These two flags let you discover cases where either workarounds are no longer necessary.
Passing in --no-warn-no-return will disable these error messages in all cases.
For example, enabling this flag will make mypy report that the x > 7 check is redundant and that the else block below is unreachable.
def process(x: int) -> None:
# Error: Right operand of "or" is never evaluated
if isinstance(x, int) or x > 7:
# Error: Unsupported operand types for + ("int" and "str")
print(x + "bad")
else:
# Error: 'Statement is unreachable' error
print(x + "bad")
To help prevent mypy from generating spurious warnings, the "Statement is unreachable" warning will be silenced in exactly two cases:
NOTE:
This limitation will be removed in future releases of mypy.
This section documents any other flags that do not neatly fall under any of the above sections.
def process(items: list[str]) -> None:
# 'items' has type list[str]
items = [item.split() for item in items]
# 'items' now has type list[list[str]]
The variable must be used before it can be redefined:
def process(items: list[str]) -> None:
items = "mypy" # invalid redefinition to str because the variable hasn't been used yet
print(items)
items = "100" # valid, items now has type str
items = int(items) # valid, items now has type int
from typing import Optional a = None # Need type annotation here if using --local-partial-types b: Optional[int] = None class Foo:
bar = None # Need type annotation here if using --local-partial-types
baz: Optional[int] = None
def __init__(self) -> None:
self.bar = 1 reveal_type(Foo().bar) # Union[int, None] without --local-partial-types
Note: this option is always implicitly enabled in mypy daemon and will become enabled by default for mypy in a future release.
# This won't re-export the value from foo import bar # Neither will this from foo import bar as bang # This will re-export it as bar and allow other modules to import it from foo import bar as bar # This will also re-export bar from foo import bar __all__ = ['bar']
from typing import Text items: list[int] if 'some string' in items: # Error: non-overlapping container check!
... text: Text if text != b'other bytes': # Error: non-overlapping equality check!
... assert text is not None # OK, check against None is allowed as a special case.
Note: the exact list of flags enabled by running --strict may change over time.
# no flag x = 'a string' x.trim() # error: "str" has no attribute "trim" [attr-defined] # When using --disable-error-code attr-defined x = 'a string' x.trim()
Note: This flag will override disabled error codes from the --disable-error-code flag.
# When using --disable-error-code attr-defined x = 'a string' x.trim() # --disable-error-code attr-defined --enable-error-code attr-defined x = 'a string' x.trim() # error: "str" has no attribute "trim" [attr-defined]
The following flags let you adjust how much detail mypy displays in error messages.
class Test:
def foo(self, x: int) -> int:
return x + "bar"
Mypy normally displays an error message that looks like this:
main.py:3: error: Unsupported operand types for + ("int" and "str")
If we enable this flag, the error message now looks like this:
main.py: note: In member "foo" of class "Test": main.py:3: error: Unsupported operand types for + ("int" and "str")
main.py:12:9: error: Unsupported operand types for / ("int" and "str")
prog.py:1: error: "str" has no attribute "trim" [attr-defined]
See error-codes for more information.
By default, mypy will store type information into a cache. Mypy will use this information to avoid unnecessary recomputation when it type checks your code again. This can help speed up the type checking process, especially when most parts of your program have not changed since the previous mypy run.
If you want to speed up how long it takes to recheck your code beyond what incremental mode can offer, try running mypy in daemon mode.
Note that mypy will still write out to the cache even when incremental mode is disabled: see the --cache-dir flag below for more details.
This setting will override the MYPY_CACHE_DIR environment variable if it is set.
Mypy will also always write to the cache even when incremental mode is disabled so it can "warm up" the cache. To disable writing to the cache, use --cache-dir=/dev/null (UNIX) or --cache-dir=nul (Windows).
The following flags are useful mostly for people who are interested in developing or debugging mypy internals.
Note that this doesn't affect third-party library stubs. To test third-party stubs, for example try MYPYPATH=stubs/six mypy ....
This flag is mainly intended to be used by people who want contribute to typeshed and would like a convenient way to find gaps and omissions.
If you want mypy to report an error when your codebase uses an untyped function, whether that function is defined in typeshed or not, use the --disallow-untyped-calls flag. See Untyped definitions and calls for more details.
Specifying this argument multiple times (--shadow-file X1 Y1 --shadow-file X2 Y2) will allow mypy to perform multiple substitutions.
This allows tooling to create temporary files with helpful modifications without having to change the source file in place. For example, suppose we have a pipeline that adds reveal_type for certain variables. This pipeline is run on original.py to produce temp.py. Running mypy --shadow-file original.py temp.py original.py will then cause mypy to type check the contents of temp.py instead of original.py, but error messages will still reference original.py.
If these flags are set, mypy will generate a report in the specified format into the specified directory.
To generate this report, you must either manually install the lxml library or specify mypy installation with the setuptools extra mypy[reports].
To generate this report, you must either manually install the lxml library or specify mypy installation with the setuptools extra mypy[reports].
To generate this report, you must either manually install the lxml library or specify mypy installation with the setuptools extra mypy[reports].
To generate this report, you must either manually install the lxml library or specify mypy installation with the setuptools extra mypy[reports].
If you use this option without providing any files or modules to type check, mypy will install stub packages suggested during the previous mypy run. If there are files or modules to type check, mypy first type checks those, and proposes to install missing stubs at the end of the run, but only if any missing modules were detected.
NOTE:
This is implemented as up to two mypy runs internally. The first run is used to find missing stub packages, and output is shown from this run only if no missing stub packages were found. If missing stub packages were found, they are installed and then another run is performed.
This lets you check more than one script in a single mypy invocation. (The default __main__ is technically more correct, but if you have many scripts that import a large package, the behavior enabled by this flag is often more convenient.)
Full documentation is available online at: http://mypy.readthedocs.io/en/latest/getting_started.html or locally at: /usr/share/doc/mypy/html (requires mypy-doc package).
Jukka Lehtosalo and contributors
February 24, 2023 |