MYPY(1)
π MYPY(1) β the mypy manual, bestie edition π
okay so. sit down. hydrate. we're talking about mypy(1) and honestly? it's giving main character energy for your whole codebase. π«Ά
β¨ NAME β¨
mypy β optional static typing for Python. yes that's the whole name. iconic. periodt. π
πΈ SYNOPSIS πΈ
mypy [-h] [-v] [-V] [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT]
[OPTIONS...] [FILES ...]
π¦ DESCRIPTION π¦
So basically, mypy is a static type checker for Python 3 and Python 2.7. If you sprinkle type annotations all over your code, mypy can type check it and sniff out those common bugs before they ruin your whole day. no cap.
Mypy is a static analyzer, aka a lint-like tool β which means those type annotations are literally just hints for mypy. They do not get in the way when you actually run your program. You run your program with a standard Python interpreter and the annotations are treated effectively as comments. lowkey magical. β¨
You can annotate using the Python 3 function annotation syntax (the PEP 484 notation), or a comment-based annotation syntax if you're on Python 2 code. Either way, you'll be able to efficiently annotate your code and then let mypy check it for common errors. And the type system?? It's powerful and easy to use, with modern features like:
- type inference
- generics
- callable types
- tuple types
- union types
- structural subtyping
obsessed, honestly. π
You invoke mypy with the paths you need checked:
$ mypy foo.py bar.py some_directory
And the directories get checked recursively to find Python source files. it just keeps going. π
β OPTIONS β
This section documents mypy's command line interface. Want a quick summary of the available flags? Just run mypy --help. easy.
Note: Command line flags are liable to change between releases. π
π Specifying what to type check π
By default, you tell mypy what code to type check by passing in the paths to whatever you want checked:
$ mypy foo.py bar.py some_directory
Note that directories are checked recursively. yes, all the way down. π³οΈ
Mypy also lets you specify what code to type check in several other ways. Here's a short summary of the relevant flags β for full details, see running-mypy.
-m MODULE,--module MODULEβ asks mypy to type check the provided module. This flag may be repeated multiple times. Heads up though: mypy will not recursively type check any submodules of the provided module. it's a one-module kinda deal.-p PACKAGE,--package PACKAGEβ asks mypy to type check the provided package. This flag may be repeated multiple times too. And unlike-m, mypy will recursively type check any submodules of the provided package. This flag is identical to--moduleapart from this behavior. the more you know π«-c PROGRAM_TEXT,--command PROGRAM_TEXTβ asks mypy to type check the provided string as a program. tiny program, big dreams.--excludeβ a regular expression that matches file names, directory names and paths which mypy should ignore while recursively discovering files to check. Use forward slashes on all platforms, bestie, don't be cute about it.
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 discovery of files via import following. You can use a per-module ignore_errors config option to silence errors from a given module, or a per-module follow_imports config option to additionally avoid mypy from following imports and checking code you do not wish to be checked.
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. π«
--exclude-gitignoreβ this flag will add everything that matches.gitignorefile(s) to--exclude. teamwork makes the dream work.
π Optional arguments π
-h,--helpβ show help message and exit.-v,--verboseβ more verbose messages. mypy gets chatty. π¬-V,--versionβ show program's version number and exit.-O FORMAT,--output FORMAT {json}β set a custom output format.
π Config file π
--config-file CONFIG_FILEβ this flag makes mypy read configuration settings from the given file.
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.
--warn-unused-configsβ this flag makes mypy warn about unused[mypy-<pattern>]config file sections. (This requires turning off incremental mode using--no-incremental.) ngl that parenthetical is doing a lot of work.
π§ Import discovery π§
The following flags customize how exactly mypy discovers and follows imports.
--explicit-package-basesβ this flag tells mypy that top-level packages will be based in either the current directory, or a member of theMYPYPATHenvironment variable ormypy_pathconfig option. This option is only useful in the absence of__init__.py. See Mapping file paths to modules for details.--ignore-missing-importsβ this flag makes mypy ignore all missing imports. It is equivalent to adding# type: ignorecomments to all unresolved imports within your codebase.
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.
--follow-untyped-importsβ this flag makes mypy analyze imports from installed packages even if missing apy.typedmarker or stubs.
Warning: Note that analyzing all unannotated modules might result in issues when analyzing code not designed to be type checked and may significantly increase how long mypy takes to run. π so like, be aware.
--follow-imports {normal,silent,skip,error}β this flag adjusts how mypy follows imported modules that were not explicitly passed in via the command line.
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.
--python-executable EXECUTABLEβ this flag will have mypy collect type information from PEP 561 <https://peps.python.org/pep-0561/> compliant packages installed for the Python executableEXECUTABLE. If not provided, mypy will use PEP 561 compliant packages installed for the Python executable running mypy.
See installed-packages for more on making PEP 561 compliant packages.
--no-site-packagesβ this flag will disable searching for PEP 561 <https://peps.python.org/pep-0561/> compliant packages. This will also disable searching for a usable Python executable.
Use this flag if mypy cannot find a Python executable for the version of Python being checked, and you don't need to use PEP 561 typed packages. Otherwise, use --python-executable.
--no-silence-site-packagesβ by default, mypy will suppress any error messages generated within PEP 561 <https://peps.python.org/pep-0561/> compliant packages. Adding this flag will disable this behavior. un-silence it, queen π--fast-module-lookupβ the default logic used to scan through search paths to resolve imports has a quadratic worse-case behavior in some cases, which is for instance triggered by a large number of folders sharing a top-level namespace as in:
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.
--no-namespace-packagesβ this flag disables import discovery of namespace packages (see PEP 420 <https://peps.python.org/pep-0420/>). In particular, this prevents discovery of packages that don't have an__init__.py(or__init__.pyi) file.
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.
π Platform configuration π
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.
--python-version X.Yβ this flag will make mypy type check your code as if it were run under Python versionX.Y. Without this option, mypy will default to using whatever version of Python is running mypy.
This flag will attempt to find a Python executable of the corresponding version to search for PEP 561 <https://peps.python.org/pep-0561/> compliant packages. If you'd like to disable this, use the --no-site-packages flag (see Import discovery <#import-discovery> for more details).
--platform PLATFORMβ makes mypy type check your code as if it were running on that operating system π₯οΈ. Skip this flag and mypy just assumes "whatever OS you're on rn, bestie, that one." The PLATFORM value can be literally any stringsys.platformis down with. no cap.--always-true NAMEβ tells mypy to treat every variable named NAME as a compile-time constant that's always true β . You can repeat this flag as many times as your heart desires π.--always-false NAMEβ the flip side πͺ: every variable named NAME gets treated as a compile-time constant that's always false β. Also repeatable, go off π.
π Disallow dynamic typing π
okay so, the Any type is how we represent a value that's got a dynamic type β aka "idk what this is, don't ask me." The --disallow-any glow-up family says nope to various uses of Any inside a module, which lets you strategically ban dynamic typing in a controlled, measured way π
. it's giving discipline.
The following options are available:
--disallow-any-unimportedβ bans usage of types that come from unfollowed imports (those types just quietly become aliases forAnyπ). Unfollowed imports happen either when the imported module literally doesn't exist, or when--follow-imports=skipis set.--disallow-any-exprβ bans all expressions in the module that have typeAny. If an expression of typeAnyshows up anywhere in your module, mypy will output an error β unless the expression is immediately used as an argument tocast()or assigned to a variable with an explicit type annotation π―.
Also, declaring a variable of type Any or casting to type Any? not allowed, sorry bestie. Note that calling functions that take parameters of type Any is still allowed tho. we're not monsters.
--disallow-any-decoratedβ bans functions that haveAnyin their signature after decorator transformation π.--disallow-any-explicitβ bans explicitAnyin type positions, like type annotations and generic type parameters π«.--disallow-any-genericsβ bans generic types that don't specify explicit type parameters. For example, you can't use a barex: list. Instead you must always write something likex: list[int]. periodt π.--disallow-subclassing-anyβ reports an error whenever a class subclasses a value of typeAny. This can happen when the base class is imported from a module that doesn't exist (when you're using--ignore-missing-imports) or is ignored because of--follow-imports=skipor a# type: ignorecomment on the import statement.
Since the module is silenced, the imported class just gets handed a type of Any π€·. By default mypy assumes the subclass correctly inherited the base class, even though that might genuinely not be the case. This flag makes mypy raise an error instead. lowkey important π₯.
π Untyped definitions and calls π
The following flags configure how mypy handles untyped function definitions or calls.
--disallow-untyped-callsβ reports an error whenever a function that has type annotations calls a function defined without annotations π€.--untyped-calls-excludeβ lets you selectively disable--disallow-untyped-callsfor functions and methods defined in specific packages, modules, or classes π. Note that each exclude entry acts as a prefix. For example (assuming there are no type annotations forthird_party_libavailable):
# mypy --disallow-untyped-calls
# --untyped-calls-exclude=third_party_lib.module_a
# --untyped-calls-exclude=foo.A
from third_party_lib.module_a import some_func
from third_party_lib.module_b import other_func
import foo
some_func() # OK, function comes from module `third_party_lib.module_a`
other_func() # E: Call to untyped function "other_func" in typed context
foo.A().meth() # OK, method was defined in class `foo.A`
foo.B().meth() # E: Call to untyped function "meth" in typed context
# file foo.py
class A:
def meth(self): pass
class B:
def meth(self): pass
--disallow-untyped-defsβ reports an error whenever it hits a function definition with no type annotations, or with incomplete type annotations (so it's a superset of--disallow-incomplete-defs, bestie π). For example, it would report an error fordef f(a, b)anddef f(a: int, b).--disallow-incomplete-defsβ reports an error whenever it hits a partly annotated function definition, while still letting fully unannotated definitions slide π. For example, it would report an error fordef f(a: int, b)but notdef f(a, b).--check-untyped-defsβ this one's less severe than the previous two, it's giving gentle π₯Ί. It type checks the body of every function, regardless of whether it has type annotations (by default, the bodies of functions without annotations don't get type checked at all). It will assume all arguments have typeAnyand always inferAnyas the return type.--disallow-untyped-decoratorsβ reports an error whenever a function with type annotations gets decorated by a decorator without annotations ππ«.
π«₯ None and Optional handling π«₯
The following flags adjust how mypy handles values of type None.
--implicit-optionalβ makes mypy treat parameters with aNonedefault value as having an implicit optional type (T | None) π».
For example, if this flag is set, mypy would assume the x parameter is actually of type int | None 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. π
--no-strict-optionalβ effectively disables checking of optional types andNonevalues. With this option, mypy doesn't generally check the use ofNonevalues βNonegets treated as compatible with every type π΅βπ«.
Warning: --no-strict-optional is evil π. Avoid using it, and definitely do not use it without understanding what it does. fr fr.
β οΈ Configuring warnings β οΈ
The following flags enable warnings for code that is technically sound but is potentially problematic or redundant in some way. it's giving "not wrong, but why tho."
--warn-redundant-castsβ makes mypy report an error whenever your code uses an unnecessarycastthat can safely be removed ποΈ.--warn-unused-ignoresβ makes mypy report an error whenever your code uses a# type: ignorecomment on a line that isn't actually generating an error message π³.
This flag, along with the --warn-redundant-casts flag, is especially useful when you're upgrading mypy π. Back in the day 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 the cases where those workarounds are no longer necessary. so satisfying β¨.
--no-warn-no-returnβ by default, mypy generates errors when a function is missing return statements in some execution paths π§. The only exceptions are when:- The function has a
NoneorAnyreturn type - The function has an empty body and is marked as an abstract method, is in a protocol class, or is in a stub file
- The execution path can never return; for example, if an exception is always raised
- The function has a
Passing in --no-warn-no-return will disable these error messages in all cases. gone, reduced to atoms π.
--warn-return-anyβ causes mypy to generate a warning when returning a value with typeAnyfrom a function declared with a non-Anyreturn type π.--warn-unreachableβ makes mypy report an error whenever it encounters code that's determined to be unreachable or redundant after it does its type analysis π. This can be a genuinely helpful way of detecting certain kinds of bugs in your code. ate.
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 gets silenced in exactly three cases ποΈ:
- When the unreachable statement is a
raisestatement, is anassert Falsestatement, or calls a function that has theNoReturnreturn type hint. In other words, when the unreachable statement throws an error or terminates the program in some way. - When the unreachable statement is
return NotImplemented. This is allowed by mypy because of its use in operator overloading. - When the unreachable statement was intentionally marked as unreachable using
version_and_platform_checks.
Note: Mypy currently cannot detect and report unreachable or redundant code inside any functions using value-constrained type variables. This limitation will be removed in future releases of mypy. π
--report-deprecated-as-noteβ if error codedeprecatedis enabled, mypy emits errors when your code imports or uses deprecated features π« . This flag converts those errors into notes, which means mypy eventually finishes with a zero exit code π. Features are considered deprecated when decorated withwarnings.deprecated.--deprecated-calls-excludeβ lets you selectively disable deprecated warnings for functions and methods defined in specific packages, modules, or classes π. Note that each exclude entry acts as a prefix. For example (assumingfoo.A.funcis deprecated):
# mypy --enable-error-code deprecated
# --deprecated-calls-exclude=foo.A
import foo
foo.A().func() # OK, the deprecated warning is ignored
# file foo.py
from typing_extensions import deprecated
class A:
@deprecated("Use A.func2 instead")
def func(self): pass
β¨ Miscellaneous strictness flags β¨
bestie this is the β¨ catch-all β¨ corner of the manpage β literally every flag that doesn't fit neatly under any of the sections above lives down here. π«Ά
--allow-untyped-globalsβ makes mypy suppress the errors it would otherwise throw when it can't fully infer the types of global and class variables. like, it just can't figure it out, so it stops yelling. π--allow-redefinitionβ okay so by default mypy will not let you redefine a variable with an unrelated type. this flag enables the redefinition of unannotated variables with an arbitrary type. it also requires--local-partial-types, which is enabled by default starting from mypy 2.0. here's the vibe:
def maybe_convert(n: int, b: bool) -> int | str:
if b:
x = str(n) # Assign "str"
else:
x = n # Assign "int"
# Type of "x" is "int | str" here.
return x
without this flag, mypy only supports inferring optional types (X | None) from multiple assignments. with this option on, mypy can infer arbitrary union types. π
it also lets an unannotated variable have different types in different code locations:
if check():
for x in range(n):
# Type of "x" is "int" here.
...
else:
for x in ['a', 'b']:
# Type of "x" is "str" here.
...
function arguments are special, bestie β changing their type within the function body is allowed even if they're annotated, but that annotation is used to infer types of the r.h.s. of all subsequent assignments. this middle-ground semantics gives a good balance for the majority of common use cases. for example:
def process(values: list[float]) -> None:
if not values:
values = [0, 0, 0]
reveal_type(values) # Revealed type is list[float]
π’ note: we are planning to turn this flag on by default in a future mypy release. so likeβ¦ get used to it ig. π
--allow-redefinition-newβ deprecated alias for--allow-redefinition. it's giving legacy, it's giving "we renamed this". π--allow-redefinition-oldβ this is an older, more limited variant of--allow-redefinition. it enables redefinition of a variable with an arbitrary type in some contexts: only redefinitions within the same block and nesting depth as the original definition are allowed. so it's the same energy but on a leash. π
we have no plans to remove this flag, but --allow-redefinition is recommended for new use cases.
here's an example where this can be useful:
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, okay?? crucially:
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
--no-local-partial-typesβ disables local partial types to enable the legacy type inference mode for containers. local partial types prevent inferring a container type for a variable when the initial assignment happens at module top level or in a class body, and the container item type is only set in a function. like this:
a = [] # Need type annotation unless using --no-local-partial-types
def func() -> None:
a.append(1)
reveal_type(a) # "list[int]" if using --no-local-partial-types
local partial types are enabled by default starting from mypy 2.0. and bestie, the mypy daemon requires local partial types. π
--no-implicit-reexportβ by default, values imported into a module are treated as exported and mypy lets other modules import them. this flag flips that: no re-exporting unless the item is imported using from-as or is included in__all__. ngl this is always treated as enabled for stub files. example time:
# 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']
see how as bar re-exports but as bang doesn't? yeah. sneaky. β¨
--strict-equalityβ by default mypy allows always-false comparisons like42 == 'no'. use this flag to prohibit such comparisons of non-overlapping types, plus similar identity and container checks:
items: list[int]
if 'some string' in items: # Error: non-overlapping container check!
...
text: str
if text != b'other bytes': # Error: non-overlapping equality check!
...
assert text is not None # OK, check against None is allowed
--strict-equality-for-noneβ extends--strict-equalityto checks againstNone:
text: str
assert text is not None # Error: non-overlapping identity check!
β οΈ note that--strict-equality-for-noneonly works in combination with--strict-equality. it does not solo. it needs its bestie. π«Ά
--no-strict-bytesβ treatsbytearrayandmemoryviewas subtypes ofbytes. this is not true at runtime and can lead to unexpected behavior π β it was the default behavior prior to mypy 2.0 though, so if you're time-traveling from old mypy, hii.
def f(buf: bytes) -> None:
assert isinstance(buf, bytes) # Raises runtime AssertionError with bytearray/memoryview
with open("binary_file", "wb") as fp:
fp.write(buf)
# Using --no-strict-bytes disables the following errors
f(bytearray(b"")) # Argument 1 to "f" has incompatible type "bytearray"; expected "bytes"
f(memoryview(b"")) # Argument 1 to "f" has incompatible type "memoryview"; expected "bytes"
# If `f` accepts any object that implements the buffer protocol,
# consider using Buffer instead:
from collections.abc import Buffer # "from typing_extensions" in Python 3.11 and earlier
def f(buf: Buffer) -> None:
with open("binary_file", "wb") as fp:
fp.write(buf)
f(b"") # Ok
f(bytearray(b"")) # Ok
f(memoryview(b"")) # Ok
the Buffer glow-up is iconic, honestly. π¦
--extra-checksβ enables additional checks that are technically correct but may be impractical. specifically: it prohibits partial overlap inTypedDictupdates, and makes arguments prepended viaConcatenatepositional-only. like:
from typing import TypedDict
class Foo(TypedDict):
a: int
class Bar(TypedDict):
a: int
b: int
def test(foo: Foo, bar: Bar) -> None:
# This is technically unsafe since foo can have a subtype of Foo at
# runtime, where type of key "b" is incompatible with int, see below
bar.update(foo)
class Bad(Foo):
b: str
bad: Bad = {"a": 0, "b": "no"}
test(bad, bar)
in future, more checks may be added to this flag if:
- The corresponding use cases are rare, thus not justifying a dedicated strictness flag.
- The new check cannot be supported as an opt-in error code.
--strictβ this flag mode enables a defined subset of optional error-checking flags. this subset primarily includes checks for inadvertent type unsoundness (i.e strict will catch type errors as long as intentional methods like type ignore or casting were not used.)
π’ note: the --warn-unreachable flag is not automatically enabled by the strict flag. don't @ me, that's just how it is.
the strict flag does not take precedence over other strict-related flags. directly specifying a flag of alternate behavior will override the behavior of strict, regardless of the order in which they are passed. you can see the list of flags enabled by strict mode in the full mypy --help output. β¨
π note: the exact list of flags enabled by running --strict may change over time.
--disable-error-codeβ lets you disable one or multiple error codes globally. seeerror-codesfor more info. watch:
# 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()
poof. error gone. π
--enable-error-codeβ lets you enable one or multiple error codes globally. seeerror-codesfor more info.
π note: this flag will override disabled error codes from the --disable-error-code flag. it's giving main character energy over the other 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]
πΈ Configuring error messages πΈ
the following flags let you adjust how much detail mypy displays in error messages. basically: how much yapping does mypy do when something's wrong. π
--show-error-contextβ this flag will precede all errors withnotemessages explaining the context of the error. so instead of just the roast, you get the roast and the explanation of why you're being roasted. consider this program:
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")
obsessed. so much more context. π«Ά
--show-column-numbersβ this flag will add column offsets to error messages. for example, the following indicates an error in line 12, column 9. and bestie, note that column offsets are 0-based π:
main.py:12:9: error: Unsupported operand types for / ("int" and "str")
--show-error-code-linksβ okay so this one ALSO drops a link to the docs for whatever error code mypy just yelled about, and it anchors straight to that code so the code gets highlighted all pretty on the docs page. Turn it on and your messages start looking like:
main.py:3: error: Unsupported operand types for - ("int" and "str") [operator]
main.py:3: note: See 'https://mypy.rtfd.io/en/stable/_refs.html#code-operator' for more info
--show-error-endβ bestie, this gives you the whole span, not just where the error starts. You get the end position of the relevant expression too, so your editor/tooling can highlight the entire thing instead of one lonely character. Format isfile:line:column:end_line:end_column. Heads up: this one implies--show-column-numbers. π--hide-error-codesβ hides the[<code>]bit from error messages. By default that code is sitting right there after every message:
prog.py:1: error: "str" has no attribute "trim" [attr-defined]
See error-codes if you wanna know more.
--prettyβ makes the output actually cute: soft word wrap, source code snippets, and little markers showing you where the error is. Visually nicer. We love that.--no-color-outputβ kills the color in error messages. (Color is on by default, jsyk. π¨)--no-error-summaryβ nope, no summary line for you. By default mypy gives you a lil wrap-up with the total number of errors, how many files had errors, and how many files got checked. This flag says "don't."--show-absolute-pathβ shows you absolute paths to your files, no relative-path games.--soft-error-limit Nβ this tweaks the limit where mypy (sometimes!) stops reporting most of the extra errors. And it only kicks in if it seems like the rest of those errors probably won't be useful, or they're gonna be way too noisy. IfNis negative, there's no limit at all. Default limit is-1.
π Incremental mode π
So by default, mypy stores your type info in a cache. Next time it type checks your code it peeks at that info so it doesn't redo work it already did, which speeds things up β especially when most of your program hasn't changed since the last run. Huge. π«Ά
And if incremental mode isn't fast enough for you, try running mypy in daemon mode. That's the next level up.
--no-incrementalβ incremental mode? Off. mypy stops referencing the cache when you re-run it.
Ngl though, mypy will still write out to the cache even when incremental mode is off β peep the --cache-dir flag below for the details. π
--cache-dir DIRβ by default all the cache data lives in a folder called.mypy_cachein the current directory. This flag lets you change that folder. It's also handy for controlling cache use when you're doing remote caching.
This setting overrides the MYPY_CACHE_DIR environment variable if that's set.
Also bestie, mypy always writes to the cache even with incremental mode disabled, so it can "warm up" the cache. Wanna stop the writing entirely? Use --cache-dir=/dev/null (UNIX) or --cache-dir=nul (Windows).
--no-sqlite-cacheβ avoids using an SQLite <https://www.sqlite.org/> database to store the cache, and writes the cache data out to individual files instead.--cache-fine-grainedβ includes fine-grained dependency information in the cache, for the mypy daemon.--skip-version-checkβ by default mypy ignores cache data that came from a different version of mypy. This flag disables that behavior.--skip-cache-mtime-checksβ skips the cache's internal consistency checks based on mtime.
π₯ Parallel type-checking π₯
By default, mypy checks all your modules in the same Python process. For a big codebase that can be slow, so mypy offers an experimental parallel type-checking mode that uses multiple worker processes. In parallel mode, modules that don't depend on each other get type-checked in parallel. Incremental cache <#incremental> manages most of the shared state. Parallel type-checking also requires --local-partial-types, which is enabled by default starting from mypy 2.0.
-n NUMBER,--num-workers NUMBERβ usesNUMBERparallel worker processes (on top of the coordinator process) to do the type-checking. Passing--num-workers 0(the default) disables parallel checking. And no, automatic detection of the optimal number of workers isn't supported yet. π
This setting overrides the MYPY_NUM_WORKERS environment variable if it's set.
Notes:
- An import cycle is always processed as a whole by a worker process. So avoiding large import cycles in your code will significantly improve type-checking speed. β¨
- Specifying more workers than you have physical CPU cores isn't beneficial, since mypy is usually CPU bound. Best way to tune the number of workers on a given machine: start from 3-4 workers and increase the number while you keep seeing a performance improvement.
- Parallel mode requires and automatically enables
--native-parser.
π§ Advanced options π§
These flags are mostly for the people who are out here developing or debugging mypy internals. Respect. π
--pdbβ invokes the Python debugger when mypy hits a fatal error.--show-traceback,--tbβ if set, shows a full traceback when mypy hits a fatal error.--raise-exceptionsβ raises the exception on a fatal error.--custom-typing-module MODULEβ lets you use a custom module as a substitute for thetypingmodule.--custom-typeshed-dir DIRβ tells mypy where to look for the standard library typeshed stubs, instead of the typeshed that ships with mypy. Mainly this makes it easier to test typeshed changes before sending them upstream, but it also lets you use a forked version of typeshed.
Important: this doesn't affect third-party library stubs. Wanna test third-party stubs? For example, try MYPYPATH=stubs/six mypy ....
--warn-incomplete-stubβ this one modifies both--disallow-untyped-defsand--disallow-incomplete-defsso they also report errors if stubs in typeshed are missing type annotations or have incomplete annotations. If both of those flags are missing,--warn-incomplete-stubdoes nothing.
It's mainly for people who wanna contribute to typeshed and want 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 <#untyped-definitions-and-calls> for more details.
--shadow-file SOURCE_FILE SHADOW_FILEβ when mypy is asked to type checkSOURCE_FILE, this flag makes it read from and type check the contents ofSHADOW_FILEinstead. But the diagnostics still refer toSOURCE_FILE. Iconic behavior honestly.
You can pass this multiple times (--shadow-file X1 Y1 --shadow-file X2 Y2) and mypy will do multiple substitutions.
It lets tooling create temporary files with helpful modifications without changing the source file in place. Example: say you have a pipeline that adds reveal_type for certain variables. You run that pipeline on original.py to produce temp.py. Then running mypy --shadow-file original.py temp.py original.py makes mypy type check the contents of temp.py instead of original.py, but the error messages still reference original.py. Slay.
--native-parserβ enables the fast Rust-based parser that parses directly to mypy AST. It'll become the default parser in one of the next mypy releases. π
π Report generation π
If these flags are set, mypy will generate a report in the specified format, into the specified directory.
--any-exprs-report DIRβ generates a text file report documenting how many expressions of typeAnyare present in your codebase.--cobertura-xml-report DIRβ generates a Cobertura XML type checking coverage report.
To generate this report you gotta either install the lxml <https://pypi.org/project/lxml/> library manually, or specify your mypy installation with the setuptools extra mypy[reports].
--html-report/--xslt-html-report DIRβ generates an HTML type checking coverage report.
To generate this report you gotta either install the lxml <https://pypi.org/project/lxml/> library manually, or specify your mypy installation with the setuptools extra mypy[reports].
--linecount-report DIRβ generates a text file report documenting the functions and lines that are typed and untyped within your codebase.--linecoverage-report DIRβ generates a JSON file that maps each source file's absolute filename to a list of line numbers belonging to typed functions in that file.--lineprecision-report DIRβ generates a flat text file report with per-module statistics of how many lines are typechecked etc.--txt-report/--xslt-txt-report DIRβ generates a text file type checking coverage report.
To generate this report you gotta either install the lxml <https://pypi.org/project/lxml/> library manually, or specify your mypy installation with the setuptools extra mypy[reports].
--xml-report DIRβ generates an XML type checking coverage report.
To generate this report you gotta either install the lxml <https://pypi.org/project/lxml/> library manually, or specify your mypy installation with the setuptools extra mypy[reports].
β¨ Enabling incomplete/experimental features β¨
--enable-incomplete-feature {PreciseTupleTypes,InlineTypedDict}β okay so some features just take several releases to land properly, bestie. Maybe they're super complex, maybe they'd break backwards compat, maybe the semantics are still ambiguous and the team wants the community's feedback first. Whatever the reason, this flag lets you preview them early. But heads up: it is not guaranteed that all of these will eventually be enabled by default. In rare cases they might decide to just not go ahead with a feature at all. π
List of currently incomplete/experimental features:
- PreciseTupleTypes: this one infers more precise tuple types in all sorts of scenarios. Back before variadic types got added to the Python type system by PEP 646 (
https://peps.python.org/pep-0646/), there was literally no way to express a type like "a tuple with at least two integers". The best you could do wastuple[int, ...], so mypy was super lenient with variable-length tuples. Now you can write it astuple[int, int, *tuple[int, ...]]. For these more precise types β when the user explicitly defines them β mypy will, for example, warn you about unsafe index access, and generally handle them in a type-safe way. But to avoid breaking existing code, mypy does not infer these precise types even when it technically could. Here are the notable examples wherePreciseTupleTypesinfers more precise types:
numbers: tuple[int, ...]
more_numbers = (1, *numbers, 1)
reveal_type(more_numbers)
# Without PreciseTupleTypes: tuple[int, ...]
# With PreciseTupleTypes: tuple[int, *tuple[int, ...], int]
other_numbers = (1, 1) + numbers
reveal_type(other_numbers)
# Without PreciseTupleTypes: tuple[int, ...]
# With PreciseTupleTypes: tuple[int, int, *tuple[int, ...]]
if len(numbers) > 2:
reveal_type(numbers)
# Without PreciseTupleTypes: tuple[int, ...]
# With PreciseTupleTypes: tuple[int, int, int, *tuple[int, ...]]
else:
reveal_type(numbers)
# Without PreciseTupleTypes: tuple[int, ...]
# With PreciseTupleTypes: tuple[()] | tuple[int] | tuple[int, int]
- InlineTypedDict: this one unlocks the non-standard syntax for inline TypedDicts, like literally this:
def test_values() -> {"width": int, "description": str}:
return {"width": 42, "description": "test"}
π Miscellaneous π
--install-typesβ this flag makes mypy install known missing stub packages for third-party libraries usingpip. It'll show you the exactpipcommand it's about to run, and it expects a confirmation before it installs anything. For security reasons these stubs are limited to only a tiny curated subset of manually selected packages that the typeshed team has verified. And slay, these packages contain only stub files and no executable code. π
If you run this option without giving mypy any files or modules to type check, it'll install the stub packages that were suggested during your previous mypy run. But if there are files or modules to type check, mypy type checks those first, and only proposes installing the missing stubs at the end of the run β and only if any missing modules were actually detected.
Note: this is new in mypy 0.900. Previous mypy versions just included a selection of third-party package stubs instead of installing them separately. Not me being nostalgic or anything. π
--non-interactiveβ when you use this together with--install-types, mypy installs all the suggested stub packages usingpipwith no confirmation prompt, and then keeps on type checking using the installed stubs, if some files or modules were provided to type check. No questions asked, we just go. π
This is implemented as up to two mypy runs internally. The first run is used to find missing stub packages, and its output is shown only if no missing stub packages were found. If missing stub packages were found, they get installed and then another run is performed.
--junit-xml JUNIT_XML_OUTPUT_FILEβ makes mypy generate a JUnit XML test result document with your type checking results. Lowkey makes it way easier to plug mypy into continuous integration (CI) tools. π₯--junit-format {global,per_file}β if--junit-xmlis set, this specifies the format.global(the default): a single test with all the errors.per_file: one test entry per file with failures.--find-occurrences CLASS.MEMBERβ this flag makes mypy print out all usages of a class member based on static type information. Fair warning bestie: this feature is experimental. π§--scripts-are-modulesβ this flag gives command line arguments that look like scripts (i.e. files whose name does not end in.py) a module name derived from the script name, rather than the fixed name__main__.
This lets you check more than one script in a single mypy invocation. (The default __main__ is technically more correct, but if you've got a bunch of scripts importing a large package, the behavior this flag enables is often way more convenient.)
πΈ ENVIRONMENT πΈ
MYPYPATHβ additional module search path entries. The format is the same as the shell's$PATH: one or more directory pathnames separated by colons. Classic. π«Ά
π SEE ALSO π
Full documentation is available online at http://mypy.readthedocs.io/en/latest/getting_started.html, or locally at /usr/share/doc/mypy/html (requires the mypy-doc package). π
π Author π
Jukka Lehtosalo and contributors. Iconic behavior honestly, thank you for your service. π«‘
And that's a wrap on the whole page, bestie β this is MYPY(1), dated Aug 16, 2026, and it ate. Go forth and type check everything. β¨ππ¦
π¦ where this page comes from
- ubuntu stonking: mypy 2.2.0-2 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms