mypy Documentation

Optional static typing for Python

20,591 stars Python Python 1 file ยท ~43,681 tokens #linter#python#typechecker#types#typing
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy mypy on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name mypy --restart always python/mypy:latest

File: README.md

Mypy: Static Typing for Python








Got a question?

We are always happy to answer questions! Here are some good places to ask them:

If you're just getting started,
the documentation
and type hints cheat sheet
can also help answer questions.

If you think you've found a bug:

To report a bug or request an enhancement:

To discuss a new type system feature:

What is mypy?

Mypy is a static type checker for Python.

Type checkers help ensure that you're using variables and functions in your code
correctly. With mypy, add type hints (PEP 484)
to your Python programs, and mypy will warn you when you use those types
incorrectly.

Python is a dynamic language, so usually you'll only see errors in your code
when you attempt to run it. Mypy is a static checker, so it finds bugs
in your programs without even running them!

Here is a small example to whet your appetite:

python
number = input("What is your favourite number?")
print("It is", number + 1)  # error: Unsupported operand types for + ("str" and "int")

Adding type hints for mypy does not interfere with the way your program would
otherwise run. Think of type hints as similar to comments! You can always use
the Python interpreter to run your code, even if mypy reports errors.

Mypy is designed with gradual typing in mind. This means you can add type
hints to your code base slowly and that you can always fall back to dynamic
typing when static typing is not convenient.

Mypy has a powerful and easy-to-use type system, supporting features such as
type inference, generics, callable types, tuple types, union types,
structural subtyping and more. Using mypy will make your programs easier to
understand, debug, and maintain.

See the documentation for
more examples and information.

In particular, see:

Quick start

Mypy can be installed using pip:

bash
python3 -m pip install -U mypy

If you want to run the latest version of the code, you can install from the
repo directly:

bash
python3 -m pip install -U git+https://github.com/python/mypy.git

Now you can type-check the statically typed parts of a program like this:

bash
mypy PROGRAM

You can always use the Python interpreter to run your statically typed
programs, even if mypy reports type errors:

bash
python3 PROGRAM

If you are working with large code bases, you can run mypy in
daemon mode, that will give much faster (often sub-second) incremental updates:

bash
dmypy run -- PROGRAM

You can also try mypy in an online playground (developed by
Yusuke Miyazaki).

Integrations

Mypy can be integrated into popular IDEs:

Web site and documentation

Additional information is available at the web site:

https://www.mypy-lang.org/

Jump straight to the documentation:

https://mypy.readthedocs.io/

Follow along our changelog at:

https://mypy-lang.blogspot.com/

Contributing

Help in testing, development, documentation and other tasks is
highly appreciated and useful to the project. There are tasks for
contributors of all experience levels.

To get started with developing mypy, see CONTRIBUTING.md.

Mypyc and compiled version of mypy

Mypyc uses Python type hints to compile Python
modules to faster C extensions. Mypy is itself compiled using mypyc: this makes
mypy approximately 4 times faster than if interpreted!

To install an interpreted mypy instead, use:

bash
python3 -m pip install --no-binary mypy -U mypy

To use a compiled version of a development
version of mypy, directly install a binary from
https://github.com/mypyc/mypy_mypyc-wheels/releases/latest.

To contribute to the mypyc project, check out the issue tracker at https://github.com/mypyc/mypyc


File: docs/source/additional_features.rst

Additional features

This section discusses various features that did not fit in naturally in one
of the previous sections.

.. _dataclasses_support:

Dataclasses


The :py:mod:dataclasses module allows defining and customizing simple
boilerplate-free classes. They can be defined using the
:py:func:@dataclasses.dataclass decorator:

.. code-block:: python

text
from dataclasses import dataclass, field

@dataclass
class Application:
    name: str
    plugins: list[str] = field(default_factory=list)

test = Application("Testing...")  # OK
bad = Application("Testing...", "with plugin")  # Error: list[str] expected

Mypy will detect special methods (such as :py:meth:__lt__ <object.__lt__>) depending on the flags used to
define dataclasses. For example:

.. code-block:: python

text
from dataclasses import dataclass

@dataclass(order=True)
class OrderedPoint:
    x: int
    y: int

@dataclass(order=False)
class UnorderedPoint:
    x: int
    y: int

OrderedPoint(1, 2) < OrderedPoint(3, 4)  # OK
UnorderedPoint(1, 2) < UnorderedPoint(3, 4)  # Error: Unsupported operand types

Dataclasses can be generic and can be used in any other way a normal
class can be used (Python 3.12 syntax):

.. code-block:: python

text
from dataclasses import dataclass

@dataclass
class BoxedData[T]:
    data: T
    label: str

def unbox[T](bd: BoxedData[T]) -> T:
    ...

val = unbox(BoxedData(42, ""))  # OK, inferred type is int

For more information see :doc:official docs
and :pep:557.

Caveats/Known Issues

Some functions in the :py:mod:dataclasses module, such as :py:func:~dataclasses.asdict,
have imprecise (too permissive) types. This will be fixed in future releases.

Mypy does not yet recognize aliases of :py:func:dataclasses.dataclass <dataclasses.dataclass>, and will
probably never recognize dynamically computed decorators. The following example
does not work:

.. code-block:: python

text
from dataclasses import dataclass

dataclass_alias = dataclass
def dataclass_wrapper(cls):
  return dataclass(cls)

@dataclass_alias
class AliasDecorated:
  """
  Mypy doesn't recognize this as a dataclass because it is decorated by an
  alias of `dataclass` rather than by `dataclass` itself.
  """
  attribute: int

AliasDecorated(attribute=1) # error: Unexpected keyword argument

To have Mypy recognize a wrapper of :py:func:dataclasses.dataclass <dataclasses.dataclass>
as a dataclass decorator, consider using the :py:func:~typing.dataclass_transform
decorator (example uses Python 3.12 syntax):

.. code-block:: python

text
from dataclasses import dataclass, Field
from typing import dataclass_transform

@dataclass_transform(field_specifiers=(Field,))
def my_dataclass[T](cls: type[T]) -> type[T]:
    ...
    return dataclass(cls)

Data Class Transforms


Mypy supports the :py:func:~typing.dataclass_transform decorator as described in
PEP 681 <https://www.python.org/dev/peps/pep-0681/#the-dataclass-transform-decorator>_.

.. note::

text
Pragmatically, mypy will assume such classes have the internal attribute :code:`__dataclass_fields__`
(even though they might lack it in runtime) and will assume functions such as :py:func:`dataclasses.is_dataclass`
and :py:func:`dataclasses.fields` treat them as if they were dataclasses
(even though they may fail at runtime).

.. _attrs_package:

The attrs package


:doc:attrs <attrs:index> is a package that lets you define
classes without writing boilerplate code. Mypy can detect uses of the
package and will generate the necessary method definitions for decorated
classes using the type annotations it finds.
Type annotations can be added as follows:

.. code-block:: python

text
import attrs

@attrs.define
class A:
    one: int
    two: int = 7
    three: int = attrs.field(8)

If you're using auto_attribs=False you must use attrs.field:

.. code-block:: python

text
import attrs

@attrs.define
class A:
    one: int = attrs.field()          # Variable annotation (Python 3.6+)
    two = attrs.field()  # type: int  # Type comment
    three = attrs.field(type=int)     # type= argument

Typeshed has a couple of "white lie" annotations to make type checking
easier. :py:func:attrs.field and :py:class:attrs.Factory actually return objects, but the
annotation says these return the types that they expect to be assigned to.
That enables this to work:

.. code-block:: python

text
import attrs

@attrs.define
class A:
    one: int = attrs.field(8)
    two: dict[str, str] = attrs.Factory(dict)
    bad: str = attrs.field(16)   # Error: can't assign int to str

Caveats/Known Issues

  • The detection of attr classes and attributes works by function name only.
    This means that if you have your own helper functions that, for example,
    return attrs.field() mypy will not see them.

  • All boolean arguments that mypy cares about must be literal True or False.
    e.g the following will not work:

    .. code-block:: python

    text
    import attrs
    YES = True
    @attrs.define(init=YES)
    class A:
        ...
  • Currently, converter only supports named functions. If mypy finds something else it
    will complain about not understanding the argument and the type annotation in
    :py:meth:__init__ <object.__init__> will be replaced by Any.

  • :ref:Validator decorators <attrs:examples-validators>
    and default decorators <https://www.attrs.org/en/stable/examples.html#defaults>_
    are not type-checked against the attribute they are setting/validating.

  • Method definitions added by mypy currently overwrite any existing method
    definitions.

.. _remote-cache:

Using a remote cache to speed up mypy runs


Mypy performs type checking incrementally, reusing results from
previous runs to speed up successive runs. If you are type checking a
large codebase, mypy can still be sometimes slower than desirable. For
example, if you create a new branch based on a much more recent commit
than the target of the previous mypy run, mypy may have to
process almost every file, as a large fraction of source files may
have changed. This can also happen after you've rebased a local
branch.

Mypy supports using a remote cache to improve performance in cases
such as the above. In a large codebase, remote caching can sometimes
speed up mypy runs by a factor of 10, or more.

Mypy doesn't include all components needed to set
this up -- generally you will have to perform some simple integration
with your Continuous Integration (CI) or build system to configure
mypy to use a remote cache. This discussion assumes you have a CI
system set up for the mypy build you want to speed up, and that you
are using a central git repository. Generalizing to different
environments should not be difficult.

Here are the main components needed:

  • A shared repository for storing mypy cache files for all landed commits.

  • CI build that uploads mypy incremental cache files to the shared repository for
    each commit for which the CI build runs.

  • A wrapper script around mypy that developers use to run mypy with remote
    caching enabled.

Below we discuss each of these components in some detail.

Shared repository for cache files

You need a repository that allows you to upload mypy cache files from
your CI build and make the cache files available for download based on
a commit id. A simple approach would be to produce an archive of the
.mypy_cache directory (which contains the mypy cache data) as a
downloadable build artifact from your CI build (depending on the
capabilities of your CI system). Alternatively, you could upload the
data to a web server or to S3, for example.

Continuous Integration build

The CI build would run a regular mypy build and create an archive containing
the .mypy_cache directory produced by the build. Finally, it will produce
the cache as a build artifact or upload it to a repository where it is
accessible by the mypy wrapper script.

Your CI script might work like this:

  • Run mypy normally. This will generate cache data under the
    .mypy_cache directory.

  • Create a tarball from the .mypy_cache directory.

  • Determine the current git master branch commit id (say, using
    git rev-parse HEAD).

  • Upload the tarball to the shared repository with a name derived from the
    commit id.

Mypy wrapper script

The wrapper script is used by developers to run mypy locally during
development instead of invoking mypy directly. The wrapper first
populates the local .mypy_cache directory from the shared
repository and then runs a normal incremental build.

The wrapper script needs some logic to determine the most recent
central repository commit (by convention, the origin/master branch
for git) the local development branch is based on. In a typical git
setup you can do it like this:

.. code::

text
git merge-base HEAD origin/master

The next step is to download the cache data (contents of the
.mypy_cache directory) from the shared repository based on the
commit id of the merge base produced by the git command above. The
script will decompress the data so that mypy will start with a fresh
.mypy_cache. Finally, the script runs mypy normally. And that's all!

Caching with mypy daemon

You can also use remote caching with the :ref:mypy daemon <mypy_daemon>.
The remote cache will significantly speed up the first dmypy check
run after starting or restarting the daemon.

The mypy daemon requires extra fine-grained dependency data in
the cache files which aren't included by default. To use caching with
the mypy daemon, use the :option:--cache-fine-grained <mypy --cache-fine-grained> option in your CI
build::

text
$ mypy --cache-fine-grained <args...>

This flag adds extra information for the daemon to the cache. In
order to use this extra information, you will also need to use the
--use-fine-grained-cache option with dmypy start or
dmypy restart. Example::

text
$ dmypy start -- --use-fine-grained-cache <options...>

Now your first dmypy check run should be much faster, as it can use
cache information to avoid processing the whole program.

Refinements

There are several optional refinements that may improve things further,
at least if your codebase is hundreds of thousands of lines or more:

  • If the wrapper script determines that the merge base hasn't changed
    from a previous run, there's no need to download the cache data and
    it's better to instead reuse the existing local cache data.

  • If you use the mypy daemon, you may want to restart the daemon each time
    after the merge base or local branch has changed to avoid processing a
    potentially large number of changes in an incremental build, as this can
    be much slower than downloading cache data and restarting the daemon.

  • If the current local branch is based on a very recent master commit,
    the remote cache data may not yet be available for that commit, as
    there will necessarily be some latency to build the cache files. It
    may be a good idea to look for cache data for, say, the 5 latest
    master commits and use the most recent data that is available.

  • If the remote cache is not accessible for some reason (say, from a public
    network), the script can still fall back to a normal incremental build.

  • You can have multiple local cache directories for different local branches
    using the :option:--cache-dir <mypy --cache-dir> option. If the user switches to an existing
    branch where downloaded cache data is already available, you can continue
    to use the existing cache data instead of redownloading the data.

  • You can set up your CI build to use a remote cache to speed up the
    CI build. This would be particularly useful if each CI build starts
    from a fresh state without access to cache files from previous
    builds. It's still recommended to run a full, non-incremental
    mypy build to create the cache data, as repeatedly updating cache
    data incrementally could result in drift over a long time period (due
    to a mypy caching issue, perhaps).

.. _extended_callable:

Extended Callable types


.. note::

This feature is deprecated. You can use
:ref:callback protocols <callback_protocols> as a replacement.

As an experimental mypy extension, you can specify :py:class:~collections.abc.Callable types
that support keyword arguments, optional arguments, and more. When
you specify the arguments of a :py:class:~collections.abc.Callable, you can choose to supply just
the type of a nameless positional argument, or an "argument specifier"
representing a more complicated form of argument. This allows one to
more closely emulate the full range of possibilities given by the
def statement in Python.

As an example, here's a complicated function definition and the
corresponding :py:class:~collections.abc.Callable:

.. code-block:: python

from collections.abc import Callable
from mypy_extensions import (Arg, DefaultArg, NamedArg,
DefaultNamedArg, VarArg, KwArg)

def func(__a: int, # This convention is for nameless arguments
b: int,
c: int = 0,
*args: int,
d: int,
e: int = 0,
**kwargs: int) -> int:
...

F = Callable[[int, # Or Arg(int)
Arg(int, 'b'),
DefaultArg(int, 'c'),
VarArg(int),
NamedArg(int, 'd'),
DefaultNamedArg(int, 'e'),
KwArg(int)],
int]

f: F = func

Argument specifiers are special function calls that can specify the
following aspects of an argument:

  • its type (the only thing that the basic format supports)

  • its name (if it has one)

  • whether it may be omitted

  • whether it may or must be passed using a keyword

  • whether it is a *args argument (representing the remaining
    positional arguments)

  • whether it is a **kwargs argument (representing the remaining
    keyword arguments)

The following functions are available in mypy_extensions for this
purpose:

.. code-block:: python

def Arg(type=Any, name=None):
# A normal, mandatory, positional argument.
# If the name is specified it may be passed as a keyword.

def DefaultArg(type=Any, name=None):
# An optional positional argument (i.e. with a default value).
# If the name is specified it may be passed as a keyword.

def NamedArg(type=Any, name=None):
# A mandatory keyword-only argument.

def DefaultNamedArg(type=Any, name=None):
# An optional keyword-only argument (i.e. with a default value).

def VarArg(type=Any):
# A *args-style variadic positional argument.
# A single VarArg() specifier represents all remaining
# positional arguments.

def KwArg(type=Any):
# A **kwargs-style variadic keyword argument.
# A single KwArg() specifier represents all remaining
# keyword arguments.

In all cases, the type argument defaults to Any, and if the
name argument is omitted the argument has no name (the name is
required for NamedArg and DefaultNamedArg). A basic
:py:class:~collections.abc.Callable such as

.. code-block:: python

MyFunc = Callable[[int, str, int], float]

is equivalent to the following:

.. code-block:: python

MyFunc = Callable[[Arg(int), Arg(str), Arg(int)], float]

A :py:class:~collections.abc.Callable with unspecified argument types, such as

.. code-block:: python

MyOtherFunc = Callable[..., int]

is (roughly) equivalent to

.. code-block:: python

MyOtherFunc = Callable[[VarArg(), KwArg()], int]

.. note::

Each of the functions above currently just returns its type
argument at runtime, so the information contained in the argument
specifiers is not available at runtime. This limitation is
necessary for backwards compatibility with the existing
typing.py module as present in the Python 3.5+ standard library
and distributed via PyPI.


File: docs/source/builtin_types.rst

Built-in types

This chapter introduces some commonly used built-in types. We will
cover many other kinds of types later.

Simple types
............

Here are examples of some common built-in types:

====================== ===============================
Type Description
====================== ===============================
int integer
float floating point number
bool boolean value (subclass of int)
str text, sequence of unicode codepoints
bytes 8-bit string, sequence of byte values
object an arbitrary object (object is the common base class)
====================== ===============================

All built-in classes can be used as types.

Any type
........

If you can't find a good type for some value, you can always fall back
to Any:

====================== ===============================
Type Description
====================== ===============================
Any dynamically typed value with an arbitrary type
====================== ===============================

The type Any is defined in the :py:mod:typing module.
See :ref:dynamic-typing for more details.

Generic types
.............

Built-in collection type objects support indexing:

====================== ===============================
Type Description
====================== ===============================
list[str] list of str objects
tuple[int, int] tuple of two int objects (tuple[()] is the empty tuple)
tuple[int, ...] tuple of an arbitrary number of int objects
dict[str, int] dictionary from str keys to int values
Iterable[int] iterable object containing ints
Sequence[bool] sequence of booleans (read-only)
Mapping[str, int] mapping from str keys to int values (read-only)
type[C] type object of C (C is a class/type variable/union of types)
====================== ===============================

The type dict is a generic class, signified by type arguments within
[...]. For example, dict[int, str] is a dictionary from integers to
strings and dict[Any, Any] is a dictionary of dynamically typed
(arbitrary) values and keys. list is another generic class.

Iterable, Sequence, and Mapping are generic types that correspond to
Python protocols. For example, a str object or a list[str] object is
valid when Iterable[str] or Sequence[str] is expected.
You can import them from :py:mod:collections.abc instead of importing from
:py:mod:typing.

See :ref:generic-builtins for more details.

These legacy types defined in :py:mod:typing are also supported:

====================== ===============================
Type Description
====================== ===============================
List[str] list of str objects
Tuple[int, int] tuple of two int objects (Tuple[()] is the empty tuple)
Tuple[int, ...] tuple of an arbitrary number of int objects
Dict[str, int] dictionary from str keys to int values
Type[C] type object of C (C is a class/type variable/union of types)
====================== ===============================


File: docs/source/cheat_sheet_py3.rst

.. _cheat-sheet-py3:

Type hints cheat sheet

This document is a quick cheat sheet showing how to use type
annotations for various common types in Python.

Variables


Technically many of the type annotations shown below are redundant,
since mypy can usually infer the type of a variable from its value.
See :ref:type-inference-and-annotations for more details.

.. code-block:: python

This is how you declare the type of a variable

age: int = 1

You don't need to initialize a variable to annotate it

a: int # Ok (no value at runtime until assigned)

Doing so can be useful in conditional branches

child: bool
if age < 18:
child = True
else:
child = False

Useful built-in types


.. code-block:: python

For most types, just use the name of the type in the annotation

Note that mypy can usually infer the type of a variable from its value,

so technically these annotations are redundant

x: int = 1
x: float = 1.0
x: bool = True
x: str = "test"
x: bytes = b"test"

For collections, the type of the collection item is in brackets

x: list[int] = [1]
x: set[int] = {6, 7}

For mappings, we need the types of both keys and values

x: dict[str, float] = {"field": 2.0}

For tuples of fixed size, we specify the types of all the elements

x: tuple[int, str, float] = (3, "yes", 7.5)

For tuples of variable size, we use one type and ellipsis

x: tuple[int, ...] = (1, 2, 3)

On Python 3.8 and earlier, the name of the collection type is

capitalized, and the type is imported from the 'typing' module

from typing import List, Set, Dict, Tuple
x: List[int] = [1]
x: Set[int] = {6, 7}
x: Dict[str, float] = {"field": 2.0}
x: Tuple[int, str, float] = (3, "yes", 7.5)
x: Tuple[int, ...] = (1, 2, 3)

from typing import Union, Optional

Use the | operator when something could be one of a few types

x: list[int | str] = [3, 5, "test", "fun"]

Union is equivalent

x: list[Union[int, str]] = [3, 5, "test", "fun"]

Use X | None for a value that could be None; Optional[X] is the same as X | None

x: str | None = "something" if some_condition() else None
if x is not None:
# Mypy understands x won't be None here because of the if-statement
print(x.upper())

If you know a value can never be None due to some logic that mypy doesn't

understand, use an assert

assert x is not None
print(x.upper())

Functions


.. code-block:: python

from collections.abc import Iterator, Callable
from typing import Union, Optional

This is how you annotate a function definition

def stringify(num: int) -> str:
return str(num)

And here's how you specify multiple arguments

def plus(num1: int, num2: int) -> int:
return num1 + num2

If a function does not return a value, use None as the return type

Default value for an argument goes after the type annotation

def show(value: str, excitement: int = 10) -> None:
print(value + "!" * excitement)

Note that arguments without a type are dynamically typed (treated as Any)

and that functions without any annotations are not checked

def untyped(x):
x.anything() + 1 + "string" # no errors

This is how you annotate a callable (function) value

x: Callable[[int, float], float] = f
def register(callback: Callable[[str], int]) -> None: ...

A generator function that yields ints is secretly just a function that

returns an iterator of ints, so that's how we annotate it

def gen(n: int) -> Iterator[int]:
i = 0
while i < n:
yield i
i += 1

You can of course split a function annotation over multiple lines

def send_email(
address: str | list[str],
sender: str,
cc: list[str] | None,
bcc: list[str] | None,
subject: str = '',
body: list[str] | None = None,
) -> bool:
...

Mypy understands positional-only and keyword-only arguments

Positional-only arguments can also be marked by using a name starting with

two underscores

def quux(x: int, /, *, y: int) -> None:
pass

quux(3, y=5) # Ok
quux(3, 5) # error: Too many positional arguments for "quux"
quux(x=3, y=5) # error: Unexpected keyword argument "x" for "quux"

This says each positional arg and each keyword arg is a "str"

def call(self, *args: str, **kwargs: str) -> str:
reveal_type(args) # Revealed type is "tuple[str, ...]"
reveal_type(kwargs) # Revealed type is "dict[str, str]"
request = make_request(*args, **kwargs)
return self.do_api_query(request)

Classes


.. code-block:: python

from typing import ClassVar

class BankAccount:
# The "init" method doesn't return anything, so it gets return
# type "None" just like any other method that doesn't return anything
def init(self, account_name: str, initial_balance: int = 0) -> None:
# mypy will infer the correct types for these instance variables
# based on the types of the parameters.
self.account_name = account_name
self.balance = initial_balance

text
# For instance methods, omit type for "self"
   def deposit(self, amount: int) -> None:
       self.balance += amount

   def withdraw(self, amount: int) -> None:
       self.balance -= amount

User-defined classes are valid as types in annotations

account: BankAccount = BankAccount("Alice", 400)
def transfer(src: BankAccount, dst: BankAccount, amount: int) -> None:
src.withdraw(amount)
dst.deposit(amount)

Functions that accept BankAccount also accept any subclass of BankAccount!

class AuditedBankAccount(BankAccount):
# You can optionally declare instance variables in the class body
audit_log: list[str]

text
def __init__(self, account_name: str, initial_balance: int = 0) -> None:
       super().__init__(account_name, initial_balance)
       self.audit_log: list[str] = []

   def deposit(self, amount: int) -> None:
       self.audit_log.append(f"Deposited {amount}")
       self.balance += amount

   def withdraw(self, amount: int) -> None:
       self.audit_log.append(f"Withdrew {amount}")
       self.balance -= amount

audited = AuditedBankAccount("Bob", 300)
transfer(audited, account, 100) # type checks!

You can use the ClassVar annotation to declare a class variable

class Car:
seats: ClassVar[int] = 4
passengers: ClassVar[list[str]]

If you want dynamic attributes on your class, have it

override "__setattr__" or "__getattr__"

class A:
# This will allow assignment to any A.x, if x is the same type as "value"
# (use "value: Any" to allow arbitrary types)
def setattr(self, name: str, value: int) -> None: ...

text
# This will allow access to any A.x, if x is compatible with the return type
   def __getattr__(self, name: str) -> int: ...

a = A()
a.foo = 42 # Works
a.bar = 'Ex-parrot' # Fails type checking

When you're puzzled or when things are complicated


.. code-block:: python

from typing import Union, Any, Optional, TYPE_CHECKING, cast

To find out what type mypy infers for an expression anywhere in

your program, wrap it in reveal_type(). Mypy will print an error

message with the type; remove it again before running the code.

reveal_type(1) # Revealed type is "builtins.int"

If you initialize a variable with an empty container or "None"

you may have to help mypy a bit by providing an explicit type annotation

x: list[str] = []
x: str | None = None

Use Any if you don't know the type of something or it's too

dynamic to write a type for

x: Any = mystery_function()

Mypy will let you do anything with x!

x.whatever() * x["you"] + x("want") - any(x) and all(x) is super # no errors

Use a "type: ignore" comment to suppress errors on a given line,

when your code confuses mypy or runs into an outright bug in mypy.

Good practice is to add a comment explaining the issue.

x = confusing_function() # type: ignore # confusing_function won't return None here because ...

"cast" is a helper function that lets you override the inferred

type of an expression. It's only for mypy -- there's no runtime check.

a = [4]
b = cast(list[int], a) # Passes fine
c = cast(list[str], a) # Passes fine despite being a lie (no runtime check)
reveal_type(c) # Revealed type is "builtins.list[builtins.str]"
print(c) # Still prints [4] ... the object is not changed or casted at runtime

Use "TYPE_CHECKING" if you want to have code that mypy can see but will not

be executed at runtime (or to have code that mypy can't see)

if TYPE_CHECKING:
import json
else:
import orjson as json # mypy is unaware of this

In some cases type annotations can cause issues at runtime, see
:ref:runtime_troubles for dealing with this.

See :ref:silencing-type-errors for details on how to silence errors.

Standard "duck types"


In typical Python code, many functions that can take a list or a dict
as an argument only need their argument to be somehow "list-like" or
"dict-like". A specific meaning of "list-like" or "dict-like" (or
something-else-like) is called a "duck type", and several duck types
that are common in idiomatic Python are standardized.

.. code-block:: python

from collections.abc import Mapping, MutableMapping, Sequence, Iterable

or 'from typing import ...' (required in Python 3.8)

Use Iterable for generic iterables (anything usable in "for"),

and Sequence where a sequence (supporting "len" and "__getitem__") is

required

def f(ints: Iterable[int]) -> list[str]:
return [str(x) for x in ints]

f(range(1, 3))

Mapping describes a dict-like object (with "__getitem__") that we won't

mutate, and MutableMapping one (with "__setitem__") that we might

def f(my_mapping: Mapping[int, str]) -> list[int]:
my_mapping[5] = 'maybe' # mypy will complain about this line...
return list(my_mapping.keys())

f({3: 'yes', 4: 'no'})

def f(my_mapping: MutableMapping[int, str]) -> set[str]:
my_mapping[5] = 'maybe' # ...but mypy is OK with this.
return set(my_mapping.values())

f({3: 'yes', 4: 'no'})

import sys
from typing import IO

Use IO[str] or IO[bytes] for functions that should accept or return

objects that come from an open() call (note that IO does not

distinguish between reading, writing or other modes)

def get_sys_IO(mode: str = 'w') -> IO[str]:
if mode == 'w':
return sys.stdout
elif mode == 'r':
return sys.stdin
else:
return sys.stdout

You can even make your own duck types using :ref:protocol-types.

Forward references


.. code-block:: python

You may want to reference a class before it is defined.

This is known as a "forward reference".

def f(foo: A) -> int: # This will fail at runtime with 'A' is not defined
...

However, if you add the following special import:

from future import annotations

It will work at runtime and type checking will succeed as long as there

is a class of that name later on in the file

def f(foo: A) -> int: # Ok
...

Another option is to just put the type in quotes

def f(foo: 'A') -> int: # Also ok
...

class A:
# This can also come up if you need to reference a class in a type
# annotation inside the definition of that class
@classmethod
def create(cls) -> A:
...

See :ref:forward-references for more details.

Decorators


Decorator functions can be expressed via generics. See
:ref:declaring-decorators for more details. Example using Python 3.12
syntax:

.. code-block:: python

text
from collections.abc import Callable
from typing import Any

def bare_decorator[F: Callable[..., Any]](func: F) -> F:
    ...

def decorator_args[F: Callable[..., Any]](url: str) -> Callable[[F], F]:
    ...

The same example using pre-3.12 syntax:

.. code-block:: python

text
from collections.abc import Callable
from typing import Any, TypeVar

F = TypeVar('F', bound=Callable[..., Any])

def bare_decorator(func: F) -> F:
    ...

def decorator_args(url: str) -> Callable[[F], F]:
    ...

Coroutines and asyncio


See :ref:async-and-await for the full detail on typing coroutines and asynchronous code.

.. code-block:: python

import asyncio

A coroutine is typed like a normal function

async def countdown(tag: str, count: int) -> str:
while count > 0:
print(f'T-minus {count} ({tag})')
await asyncio.sleep(0.1)
count -= 1
return "Blastoff!"


File: docs/source/class_basics.rst

.. _class-basics:

Class basics

This section will help get you started annotating your
classes. Built-in classes such as int also follow these same
rules.

Instance and class attributes


The mypy type checker detects if you are trying to access a missing
attribute, which is a very common programming error. For this to work
correctly, instance and class attributes must be defined or
initialized within the class. Mypy infers the types of attributes:

.. code-block:: python

class A:
def init(self, x: int) -> None:
self.x = x # Aha, attribute 'x' of type 'int'

a = A(1)
a.x = 2 # OK!
a.y = 3 # Error: "A" has no attribute "y"

This is a bit like each class having an implicitly defined
:py:data:__slots__ <object.__slots__> attribute. This is only enforced during type
checking and not when your program is running.

You can declare types of variables in the class body explicitly using
a type annotation:

.. code-block:: python

class A:
x: list[int] # Declare attribute 'x' of type list[int]

a = A()
a.x = [1] # OK

As in Python generally, a variable defined in the class body can be used
as a class or an instance variable. (As discussed in the next section, you
can override this with a :py:data:~typing.ClassVar annotation.)

Similarly, you can give explicit types to instance variables defined
in a method:

.. code-block:: python

class A:
def init(self) -> None:
self.x: list[int] = []

text
def f(self) -> None:
       self.y: Any = 0

You can only define an instance variable within a method if you assign
to it explicitly using self:

.. code-block:: python

class A:
def init(self) -> None:
self.y = 1 # Define 'y'
a = self
a.x = 1 # Error: 'x' not defined

Annotating init methods


The :py:meth:__init__ <object.__init__> method is somewhat special -- it doesn't return a
value. This is best expressed as -> None. However, since many feel
this is redundant, it is allowed to omit the return type declaration
on :py:meth:__init__ <object.__init__> methods if at least one argument is annotated. For
example, in the following classes :py:meth:__init__ <object.__init__> is considered fully
annotated:

.. code-block:: python

class C1:
def init(self) -> None:
self.var = 42

class C2:
def init(self, arg: int):
self.var = arg

However, if :py:meth:__init__ <object.__init__> has no annotated arguments and no return type
annotation, it is considered an untyped method:

.. code-block:: python

class C3:
def init(self):
# This body is not type checked
self.var = 42 + 'abc'

Class attribute annotations


You can use a :py:data:ClassVar[t] <typing.ClassVar> annotation to explicitly declare that a
particular attribute should not be set on instances:

.. code-block:: python

from typing import ClassVar

class A:
x: ClassVar[int] = 0 # Class variable only

A.x += 1 # OK

a = A()
a.x = 1 # Error: Cannot assign to class variable "x" via instance
print(a.x) # OK -- can be read through an instance

It's not necessary to annotate all class variables using
:py:data:~typing.ClassVar. An attribute without the :py:data:~typing.ClassVar annotation can
still be used as a class variable. However, mypy won't prevent it from
being used as an instance variable, as discussed previously:

.. code-block:: python

class A:
x = 0 # Can be used as a class or instance variable

A.x += 1 # OK

a = A()
a.x = 1 # Also OK

Note that :py:data:~typing.ClassVar is not a class, and you can't use it with
:py:func:isinstance or :py:func:issubclass. It does not change Python
runtime behavior -- it's only for type checkers such as mypy (and
also helpful for human readers).

You can also omit the square brackets and the variable type in
a :py:data:~typing.ClassVar annotation, but this might not do what you'd expect:

.. code-block:: python

class A:
y: ClassVar = 0 # Type implicitly Any!

In this case the type of the attribute will be implicitly Any.
This behavior will change in the future, since it's surprising.

An explicit :py:data:~typing.ClassVar may be particularly handy to distinguish
between class and instance variables with callable types. For example:

.. code-block:: python

from collections.abc import Callable
from typing import ClassVar

class A:
foo: Callable[[int], None]
bar: ClassVar[Callable[[A, int], None]]
bad: Callable[[A], None]

A().foo(42) # OK
A().bar(42) # OK
A().bad() # Error: Too few arguments

.. note::
A :py:data:~typing.ClassVar type parameter cannot include type variables:
ClassVar[T] and ClassVar[list[T]]
are both invalid if T is a type variable (see :ref:generic-classes
for more about type variables).

Overriding statically typed methods


When overriding a statically typed method, mypy checks that the
override has a compatible signature:

.. code-block:: python

class Base:
def f(self, x: int) -> None:
...

class Derived1(Base):
def f(self, x: str) -> None: # Error: type of 'x' incompatible
...

class Derived2(Base):
def f(self, x: int, y: int) -> None: # Error: too many arguments
...

class Derived3(Base):
def f(self, x: int) -> None: # OK
...

class Derived4(Base):
def f(self, x: float) -> None: # OK: mypy treats int as a subtype of float
...

class Derived5(Base):
def f(self, x: int, y: int = 0) -> None: # OK: accepts more than the base
... # class method

.. note::

You can also vary return types covariantly in overriding. For
example, you could override the return type Iterable[int] with a
subtype such as list[int]. Similarly, you can vary argument types
contravariantly -- subclasses can have more general argument types.

In order to ensure that your code remains correct when renaming methods,
it can be helpful to explicitly mark a method as overriding a base
method. This can be done with the @override decorator. @override
can be imported from typing starting with Python 3.12 or from
typing_extensions for use with older Python versions. If the base
method is then renamed while the overriding method is not, mypy will
show an error:

.. code-block:: python

from typing import override

class Base:
def f(self, x: int) -> None:
...
def g_renamed(self, y: str) -> None:
...

class Derived1(Base):
@override
def f(self, x: int) -> None: # OK
...

text
@override
   def g(self, y: str) -> None:   # Error: no corresponding base method found
       ...

.. note::

Use :ref:--enable-error-code explicit-override <code-explicit-override> to require
that method overrides use the @override decorator. Emit an error if it is missing.

You can also override a statically typed method with a dynamically
typed one. This allows dynamically typed code to override methods
defined in library classes without worrying about their type
signatures.

As always, relying on dynamically typed code can be unsafe. There is no
runtime enforcement that the method override returns a value that is
compatible with the original return type, since annotations have no
effect at runtime:

.. code-block:: python

class Base:
def inc(self, x: int) -> int:
return x + 1

class Derived(Base):
def inc(self, x): # Override, dynamically typed
return 'hello' # Incompatible with 'Base', but no mypy error

Abstract base classes and multiple inheritance


Mypy supports Python :doc:abstract base classes (ABCs). Abstract classes
have at least one abstract method or property that must be implemented
by any concrete (non-abstract) subclass. You can define abstract base
classes using the :py:class:abc.ABCMeta metaclass and the :py:func:@abc.abstractmethod <abc.abstractmethod>
function decorator. Example:

.. code-block:: python

from abc import ABCMeta, abstractmethod

class Animal(metaclass=ABCMeta):
@abstractmethod
def eat(self, food: str) -> None: pass

text
@property
   @abstractmethod
   def can_walk(self) -> bool: pass

class Cat(Animal):
def eat(self, food: str) -> None:
... # Body omitted

text
@property
   def can_walk(self) -> bool:
       return True

x = Animal() # Error: 'Animal' is abstract due to 'eat' and 'can_walk'
y = Cat() # OK

Note that mypy performs checking for unimplemented abstract methods
even if you omit the :py:class:~abc.ABCMeta metaclass. This can be useful if the
metaclass would cause runtime metaclass conflicts.

Since you can't create instances of ABCs, they are most commonly used in
type annotations. For example, this method accepts arbitrary iterables
containing arbitrary animals (instances of concrete Animal
subclasses):

.. code-block:: python

def feed_all(animals: Iterable[Animal], food: str) -> None:
for animal in animals:
animal.eat(food)

There is one important peculiarity about how ABCs work in Python --
whether a particular class is abstract or not is somewhat implicit.
In the example below, Derived is treated as an abstract base class
since Derived inherits an abstract f method from Base and
doesn't explicitly implement it. The definition of Derived
generates no errors from mypy, since it's a valid ABC:

.. code-block:: python

from abc import ABCMeta, abstractmethod

class Base(metaclass=ABCMeta):
@abstractmethod
def f(self, x: int) -> None: pass

class Derived(Base): # No error -- Derived is implicitly abstract
def g(self) -> None:
...

Attempting to create an instance of Derived will be rejected,
however:

.. code-block:: python

d = Derived() # Error: 'Derived' is abstract

.. note::

It's a common error to forget to implement an abstract method.
As shown above, the class definition will not generate an error
in this case, but any attempt to construct an instance will be
flagged as an error.

Mypy allows you to omit the body for an abstract method, but if you do so,
it is unsafe to call such method via super(). For example:

.. code-block:: python

from abc import abstractmethod
class Base:
@abstractmethod
def foo(self) -> int: pass
@abstractmethod
def bar(self) -> int:
return 0
class Sub(Base):
def foo(self) -> int:
return super().foo() + 1 # error: Call to abstract method "foo" of "Base"
# with trivial body via super() is unsafe
@abstractmethod
def bar(self) -> int:
return super().bar() + 1 # This is OK however.

A class can inherit any number of classes, both abstract and
concrete. As with normal overrides, a dynamically typed method can
override or implement a statically typed method defined in any base
class, including an abstract method defined in an abstract base class.

You can implement an abstract property using either a normal
property or an instance variable.

Slots


When a class has explicitly defined :std:term:__slots__,
mypy will check that all attributes assigned to are members of __slots__:

.. code-block:: python

class Album:
slots = ('name', 'year')

text
def __init__(self, name: str, year: int) -> None:
     self.name = name
     self.year = year
     # Error: Trying to assign name "released" that is not in "__slots__" of type "Album"
     self.released = True

my_album = Album('Songs about Python', 2021)

Mypy will only check attribute assignments against __slots__ when
the following conditions hold:

  1. All base classes (except builtin ones) must have explicit
    __slots__ defined (this mirrors Python semantics).

  2. __slots__ does not include __dict__. If __slots__
    includes __dict__, arbitrary attributes can be set, similar to
    when __slots__ is not defined (this mirrors Python semantics).

  3. All values in __slots__ must be string literals.


File: docs/source/command_line.rst

.. _command-line:

.. program:: mypy

The mypy command line

This section documents mypy's command line interface. You can view
a quick summary of the available flags by running :option:mypy --help.

.. note::

Command line flags are liable to change between releases.

Specifying what to type check


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::

text
$ 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 :ref:running-mypy.

.. option:: -m MODULE, --module MODULE

text
Asks mypy to type check the provided module. This flag may be
repeated multiple times.

Mypy *will not* recursively type check any submodules of the provided
module.

.. option:: -p PACKAGE, --package PACKAGE

text
Asks mypy to type check the provided package. This flag may be
repeated multiple times.

Mypy *will* recursively type check any submodules of the provided
package. This flag is identical to :option:`--module` apart from this
behavior.

.. option:: -c PROGRAM_TEXT, --command PROGRAM_TEXT

text
Asks mypy to type check the provided string as a program.

.. option:: --exclude

text
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.

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 :ref:`import following <follow-imports>`. You can use a per-module
:confval:`ignore_errors` config option to silence errors from a given module,
or a per-module :confval:`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``.

.. option:: --exclude-gitignore

text
This flag will add everything that matches ``.gitignore`` file(s) to :option:`--exclude`.

Optional arguments


.. option:: -h, --help

text
Show help message and exit.

.. option:: -v, --verbose

text
More verbose messages.

.. option:: -V, --version

text
Show program's version number and exit.

.. option:: -O FORMAT, --output FORMAT {json}

text
Set a custom output format.

.. _config-file-flag:

Config file


.. option:: --config-file CONFIG_FILE

text
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 :option:`--config-file= <--config-file>` (with no filename) will ignore *all*
config files.

See :ref:`config-file` for the syntax of configuration files.

.. option:: --warn-unused-configs

text
This flag makes mypy warn about unused ``[mypy-]`` config
file sections.
(This requires turning off incremental mode using :option:`--no-incremental`.)

.. _import-discovery:

Import discovery


The following flags customize how exactly mypy discovers and follows
imports.

.. option:: --explicit-package-bases

text
This flag tells mypy that top-level packages will be based in either the
current directory, or a member of the ``MYPYPATH`` environment variable or
:confval:`mypy_path` config option. This option is only useful
in the absence of `__init__.py`. See :ref:`Mapping file
paths to modules <mapping-paths-to-modules>` for details.

.. option:: --ignore-missing-imports

text
This flag makes mypy ignore all missing imports. It is equivalent
to adding ``# type: ignore`` comments 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 :option:`--ignore-missing-imports`:

.. code-block:: python

    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 :ref:`ignore-missing-imports`.

.. option:: --follow-untyped-imports

text
This flag makes mypy analyze imports from installed packages even if
missing a :ref:`py.typed marker 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.

.. option:: --follow-imports {normal,silent,skip,error}

text
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 :ref:`Following imports <follow-imports>`.

.. option:: --python-executable EXECUTABLE

text
This flag will have mypy collect type information from :pep:`561`
compliant packages installed for the Python executable ``EXECUTABLE``.
If not provided, mypy will use PEP 561 compliant packages installed for
the Python executable running mypy.

See :ref:`installed-packages` for more on making PEP 561 compliant packages.

.. option:: --no-site-packages

text
This flag will disable searching for :pep:`561` 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 :option:`--python-executable`.

.. option:: --no-silence-site-packages

text
By default, mypy will suppress any error messages generated within :pep:`561`
compliant packages. Adding this flag will disable this behavior.

.. option:: --fast-module-lookup

text
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 :option:`--fast-module-lookup` option.

.. option:: --no-namespace-packages

text
This flag disables import discovery of namespace packages (see :pep:`420`).
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 :ref:`Mapping file paths to
modules <mapping-paths-to-modules>` for details.

.. _platform-configuration:

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 :ref:version_and_platform_checks.

.. option:: --python-version X.Y

text
This flag will make mypy type check your code as if it were
run under Python version X.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` compliant packages. If you'd like to
disable this, use the :option:`--no-site-packages` flag (see
:ref:`import-discovery` for more details).

.. option:: --platform PLATFORM

text
This flag will make mypy type check your code as if it were
run under the given operating system. Without this option, mypy will
default to using whatever operating system you are currently using.

The ``PLATFORM`` parameter may be any string supported by
:py:data:`sys.platform`.

.. _always-true:

.. option:: --always-true NAME

text
This flag will treat all variables named ``NAME`` as
compile-time constants that are always true.  This flag may
be repeated.

.. option:: --always-false NAME

text
This flag will treat all variables named ``NAME`` as
compile-time constants that are always false.  This flag may
be repeated.

.. _disallow-dynamic-typing:

Disallow dynamic typing


The Any type is used to represent a value that has a :ref:dynamic type <dynamic-typing>.
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:

.. option:: --disallow-any-unimported

text
This flag disallows usage of types that come from unfollowed imports
(such types become aliases for ``Any``). Unfollowed imports occur either
when the imported module does not exist or when :option:`--follow-imports=skip <--follow-imports>`
is set.

.. option:: --disallow-any-expr

text
This flag disallows all expressions in the module that have type ``Any``.
If an expression of type ``Any`` appears anywhere in the module
mypy will output an error unless the expression is immediately
used as an argument to :py:func:`~typing.cast` or assigned to a variable with an
explicit type annotation.

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.

.. option:: --disallow-any-decorated

text
This flag disallows functions that have ``Any`` in their signature
after decorator transformation.

.. option:: --disallow-any-explicit

text
This flag disallows explicit ``Any`` in type positions such as type
annotations and generic type parameters.

.. option:: --disallow-any-generics

text
This flag disallows usage of generic types that do not specify explicit
type parameters. For example, you can't use a bare ``x: list``. Instead, you
must always write something like ``x: list[int]``.

.. option:: --disallow-subclassing-any

text
This flag reports an error whenever a class subclasses a value of
type ``Any``.  This may occur when the base class is imported from
a module that doesn't exist (when using
:option:`--ignore-missing-imports`) or is
ignored due to :option:`--follow-imports=skip <--follow-imports>` or a
``# type: ignore`` comment on the ``import`` statement.

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.

.. _untyped-definitions-and-calls:

Untyped definitions and calls


The following flags configure how mypy handles untyped function
definitions or calls.

.. option:: --disallow-untyped-calls

text
This flag reports an error whenever a function with type annotations
calls a function defined without annotations.

.. option:: --untyped-calls-exclude

text
This flag allows one to selectively disable :option:`--disallow-untyped-calls`
for 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 for ``third_party_lib`` available):

.. code-block:: python

    # 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

.. option:: --disallow-untyped-defs

text
This flag reports an error whenever it encounters a function definition
without type annotations or with incomplete type annotations.
(a superset of :option:`--disallow-incomplete-defs`).

For example, it would report an error for :code:`def f(a, b)` and :code:`def f(a: int, b)`.

.. option:: --disallow-incomplete-defs

text
This flag reports an error whenever it encounters a partly annotated
function definition, while still allowing entirely unannotated definitions.

For example, it would report an error for :code:`def f(a: int, b)` but not :code:`def f(a, b)`.

.. option:: --check-untyped-defs

text
This flag is less severe than the previous two options -- it type checks
the body of every function, regardless of whether it has type annotations.
(By default the bodies of functions without annotations are not type
checked.)

It will assume all arguments have type ``Any`` and always infer ``Any``
as the return type.

.. option:: --disallow-untyped-decorators

text
This flag reports an error whenever a function with type annotations
is decorated with a decorator without annotations.

.. _none-and-optional-handling:

None and Optional handling


The following flags adjust how mypy handles values of type None.

.. _implicit-optional:

.. option:: --implicit-optional

text
This flag causes mypy to treat parameters with a ``None``
default value as having an implicit optional type (``T | None``).

For example, if this flag is set, mypy would assume that the ``x``
parameter is actually of type ``int | None`` in the code snippet below,
since the default parameter is ``None``:

.. code-block:: python

    def foo(x: int = None) -> None:
        print(x)

**Note:** This was disabled by default starting in mypy 0.980.

.. _no_strict_optional:

.. option:: --no-strict-optional

text
This flag effectively disables checking of optional
types and ``None`` values. With this option, mypy doesn't
generally check the use of ``None`` values -- it is 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.

.. _configuring-warnings:

Configuring warnings


The following flags enable warnings for code that is sound but is
potentially problematic or redundant in some way.

.. option:: --warn-redundant-casts

text
This flag will make mypy report an error whenever your code uses
an unnecessary cast that can safely be removed.

.. option:: --warn-unused-ignores

text
This flag will make mypy report an error whenever your code uses
a ``# type: ignore`` comment on a line that is not actually
generating an error message.

This flag, along with the :option:`--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.

.. option:: --no-warn-no-return

text
By default, mypy will generate errors when a function is missing
return statements in some execution paths. The only exceptions
are when:

-   The function has a ``None`` or ``Any`` return 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

Passing in :option:`--no-warn-no-return` will disable these error
messages in all cases.

.. option:: --warn-return-any

text
This flag causes mypy to generate a warning when returning a value
with type ``Any`` from a function declared with a non-``Any`` return type.

.. option:: --warn-unreachable

text
This flag will make mypy report an error whenever it encounters
code determined to be unreachable or redundant after performing type analysis.
This can be a helpful way of detecting certain kinds of bugs in your code.

For example, enabling this flag will make mypy report that the ``x > 7``
check is redundant and that the ``else`` block below is unreachable.

.. code-block:: python

    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 three cases:

1.  When the unreachable statement is a ``raise`` statement, is an
    ``assert False`` statement, or calls a function that has the :py:data:`~typing.NoReturn`
    return type hint. In other words, when the unreachable statement
    throws an error or terminates the program in some way.
2.  When the unreachable statement is ``return NotImplemented``. This
    is allowed by mypy due to its use in operator overloading.
3.  When the unreachable statement was *intentionally* marked as unreachable
    using :ref:`version_and_platform_checks`.

.. note::

    Mypy currently cannot detect and report unreachable or redundant code
    inside any functions using :ref:`value-constrained type variables <value-constrained-type-variables>`.

    This limitation will be removed in future releases of mypy.

.. option:: --report-deprecated-as-note

text
If error code ``deprecated`` is enabled, mypy emits errors if your code
imports or uses deprecated features. This flag converts such errors to
notes, causing mypy to eventually finish with a zero exit code. Features
are considered deprecated when decorated with ``warnings.deprecated``.

.. option:: --deprecated-calls-exclude

text
This flag allows one to selectively disable :ref:`deprecated<code-deprecated>` warnings
for functions and methods defined in specific packages, modules, or classes.
Note that each exclude entry acts as a prefix. For example (assuming ``foo.A.func`` is deprecated):

.. code-block:: python

    # 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:

Miscellaneous strictness flags


This section documents any other flags that do not neatly fall under any
of the above sections.

.. option:: --allow-untyped-globals

text
This flag causes mypy to suppress errors caused by not being able to fully
infer the types of global and class variables.

.. option:: --allow-redefinition

text
By default, mypy won't allow a variable to be redefined with an
unrelated type. This flag enables the redefinition of *unannotated*
variables with an arbitrary type. This also requires
:option:`--local-partial-types <mypy --no-local-partial-types>`, which is
enabled by default starting from mypy 2.0. Example:

.. code-block:: python

    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 enabled,
mypy can infer arbitrary union types.

This also enables an unannotated variable to have different types in different
code locations:

.. code-block:: python

    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, changing their type within function body
is allowed even if they are annotated, but that annotation is used to infer
types of r.h.s. of all subsequent assignments. Such middle-ground semantics
provides good balance for majority of common use cases. For example:

.. code-block:: python

    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.

.. option:: --allow-redefinition-new

text
Deprecated alias for :option:`--allow-redefinition <mypy --allow-redefinition>`.

.. option:: --allow-redefinition-old

text
This is an older, more limited variant of
:option:`--allow-redefinition <mypy --allow-redefinition>`.
This flag 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.

We have no plans to remove this flag, but
:option:`--allow-redefinition <mypy --allow-redefinition>`
is recommended for new use cases.

Example where this can be useful:

.. code-block:: python

   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:

.. code-block:: python

    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

.. option:: --no-local-partial-types

text
Disable local partial types to enable 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. Example:

.. code-block:: python

    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. The
mypy daemon requires local partial types.

.. option:: --no-implicit-reexport

text
By default, imported values to a module are treated as exported and mypy allows
other modules to import them. This flag changes the behavior to not re-export unless
the item is imported using from-as or is included in ``__all__``. Note this is
always treated as enabled for stub files. For example:

.. code-block:: python

   # 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']

.. option:: --strict-equality

text
By default, mypy allows always-false comparisons like ``42 == 'no'``.
Use this flag to prohibit such comparisons of non-overlapping types, and
similar identity and container checks:

.. code-block:: python

   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

.. option:: --strict-equality-for-none

text
This flag extends :option:`--strict-equality <mypy --strict-equality>` for checks
against ``None``:

.. code-block:: python

   text: str
   assert text is not None  # Error: non-overlapping identity check!

Note that :option:`--strict-equality-for-none <mypy --strict-equality-for-none>`
only works in combination with :option:`--strict-equality <mypy --strict-equality>`.

.. option:: --no-strict-bytes

text
Treat ``bytearray`` and ``memoryview`` as subtypes of ``bytes``. This is not true
at runtime and can lead to unexpected behavior. This was the default behavior prior
to mypy 2.0.

.. code-block:: python

   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

.. option:: --extra-checks

text
This flag enables additional checks that are technically correct but may be
impractical. In particular, it prohibits partial overlap in ``TypedDict`` updates,
and makes arguments prepended via ``Concatenate`` positional-only. For example:

.. code-block:: python

   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.

.. option:: --strict

text
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 :option:`--warn-unreachable` flag
is not automatically enabled by the strict flag.

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
:option:`mypy --help` output.

Note: the exact list of flags enabled by running :option:`--strict` may change
over time.

.. include:: strict_list.rst
..
    The above file is autogenerated and included during html generation.
    (That's an include directive, and this is a comment.)
    It would be fine to generate it at some other time instead,
    theoretically, but we already had a convenient hook during html gen.

.. option:: --disable-error-code

text
This flag allows disabling one or multiple error codes globally.
See :ref:`error-codes` for more information.

.. code-block:: python

    # 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()

.. option:: --enable-error-code

text
This flag allows enabling one or multiple error codes globally.
See :ref:`error-codes` for more information.

Note: This flag will override disabled error codes from the
:option:`--disable-error-code <mypy --disable-error-code>` flag.

.. code-block:: python

    # 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:

Configuring error messages


The following flags let you adjust how much detail mypy displays
in error messages.

.. option:: --show-error-context

text
This flag will precede all errors with "note" messages explaining the
context of the error. For example, consider the following program:

.. code-block:: python

    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")

.. option:: --show-column-numbers

text
This flag will add column offsets to error messages.
For example, the following indicates an error in line 12, column 9
(note that column offsets are 0-based)::

    main.py:12:9: error: Unsupported operand types for / ("int" and "str")

.. option:: --show-error-code-links

text
This flag will also display a link to error code documentation, anchored to the error code reported by mypy.
The corresponding error code will be highlighted within the documentation page.
If we enable this flag, the error message now looks like this::

    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

.. option:: --show-error-end

text
This flag will make mypy show not just that start position where
an error was detected, but also the end position of the relevant expression.
This way various tools can easily highlight the whole error span. The format is
``file:line:column:end_line:end_column``. This option implies
``--show-column-numbers``.

.. option:: --hide-error-codes

text
This flag will hide the error code ``[<code>]`` from error messages. By default, the error
code is shown after each error message::

    prog.py:1: error: "str" has no attribute "trim"  [attr-defined]

See :ref:`error-codes` for more information.

.. option:: --pretty

text
Use visually nicer output in error messages: use soft word wrap,
show source code snippets, and show error location markers.

.. option:: --no-color-output

text
This flag will disable color output in error messages, enabled by default.

.. option:: --no-error-summary

text
This flag will disable error summary. By default mypy shows a summary line
including total number of errors, number of files with errors, and number
of files checked.

.. option:: --show-absolute-path

text
Show absolute paths to files.

.. option:: --soft-error-limit N

text
This flag will adjust the limit after which mypy will (sometimes)
disable reporting most additional errors. The limit only applies
if it seems likely that most of the remaining errors will not be
useful or they may be overly noisy. If ``N`` is negative, there is
no limit. The default limit is -1.

.. _incremental:

Incremental mode


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
:ref:daemon mode <mypy_daemon>.

.. option:: --no-incremental

text
This flag disables incremental mode: mypy will no longer reference
the cache when re-run.

Note that mypy will still write out to the cache even when
incremental mode is disabled: see the :option:`--cache-dir` flag below
for more details.

.. option:: --cache-dir DIR

text
By default, mypy stores all cache data inside of a folder named
``.mypy_cache`` in the current directory. This flag lets you
change this folder. This flag can also be useful for controlling
cache use when using :ref:`remote caching <remote-cache>`.

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).

.. option:: --no-sqlite-cache

text
Avoid using `SQLite`_ database to store the cache, instead write cache data
out to individual files.

.. option:: --cache-fine-grained

text
Include fine-grained dependency information in the cache for the mypy daemon.

.. option:: --skip-version-check

text
By default, mypy will ignore cache data generated by a different
version of mypy. This flag disables that behavior.

.. option:: --skip-cache-mtime-checks

text
Skip cache internal consistency checks based on mtime.

.. _parallel:

Parallel type-checking


By default, mypy checks all modules in the same Python process. This can be slow
for large code bases. Mypy offers experimental parallel type-checking mode using
multiple worker processes. In parallel mode, modules that do not depend om each
other are type-checked in parallel. :ref:Incremental cache is
used to manage most of the shared state. Parallel type-checking also requires
:option:--local-partial-types <mypy --no-local-partial-types>, which is
enabled by default starting from mypy 2.0.

.. option:: -n NUMBER, --num-workers NUMBER

text
Use ``NUMBER`` parallel worker processes (in addition to the coordinator
process) to perform type-checking. Specifying ``--num-workers 0`` (default)
disables parallel checking. Automatic detection of the optimal number
of workers is not supported yet.

This setting will override the ``MYPY_NUM_WORKERS`` environment
variable if it is set.

Notes:

  • An import cycle is always processed as a whole by a worker process. Thus,
    avoiding large import cycles in your code will significantly improve
    type-checking speed.

  • Specifying a number of workers that is larger than the number of physical
    CPU cores is not beneficial, since mypy is usually CPU bound. Best way to
    tune the number of workers on a given machine is to start from 3-4 workers
    and increase the number while you see a performance improvement.

  • Parallel mode requires and automatically enables :option:--native-parser.

Advanced options


The following flags are useful mostly for people who are interested
in developing or debugging mypy internals.

.. option:: --pdb

text
This flag will invoke the Python debugger when mypy encounters
a fatal error.

.. option:: --show-traceback, --tb

text
If set, this flag will display a full traceback when mypy
encounters a fatal error.

.. option:: --raise-exceptions

text
Raise exception on fatal error.

.. option:: --custom-typing-module MODULE

text
This flag lets you use a custom module as a substitute for the
:py:mod:`typing` module.

.. option:: --custom-typeshed-dir DIR

text
This flag specifies the directory where mypy looks for standard library typeshed
stubs, instead of the typeshed that ships with mypy.  This is
primarily intended to make it easier to test typeshed changes before
submitting them upstream, but also allows you to use a forked version of
typeshed.

Note that this doesn't affect third-party library stubs. To test third-party stubs,
for example try ``MYPYPATH=stubs/six mypy ...``.

.. _warn-incomplete-stub:

.. option:: --warn-incomplete-stub

text
This flag modifies both the :option:`--disallow-untyped-defs` and
:option:`--disallow-incomplete-defs` flags so they also report errors
if stubs in typeshed are missing type annotations or has incomplete
annotations. If both flags are missing, :option:`--warn-incomplete-stub`
also does nothing.

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
:option:`--disallow-untyped-calls` flag. See :ref:`untyped-definitions-and-calls`
for more details.

.. _shadow-file:

.. option:: --shadow-file SOURCE_FILE SHADOW_FILE

text
When mypy is asked to type check ``SOURCE_FILE``, this flag makes mypy
read from and type check the contents of ``SHADOW_FILE`` instead. However,
diagnostics will continue to refer to ``SOURCE_FILE``.

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``.

.. option:: --native-parser

text
This enables fast Rust-based parser that parses directly to mypy AST.
It will 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.

.. option:: --any-exprs-report DIR

text
Causes mypy to generate a text file report documenting how many
expressions of type ``Any`` are present within your codebase.

.. option:: --cobertura-xml-report DIR

text
Causes mypy to generate a Cobertura XML type checking coverage report.

To generate this report, you must either manually install the `lxml`_
library or specify mypy installation with the setuptools extra
``mypy[reports]``.

.. option:: --html-report / --xslt-html-report DIR

text
Causes mypy to generate an HTML type checking coverage report.

To generate this report, you must either manually install the `lxml`_
library or specify mypy installation with the setuptools extra
``mypy[reports]``.

.. option:: --linecount-report DIR

text
Causes mypy to generate a text file report documenting the functions
and lines that are typed and untyped within your codebase.

.. option:: --linecoverage-report DIR

text
Causes mypy to generate a JSON file that maps each source file's
absolute filename to a list of line numbers that belong to typed
functions in that file.

.. option:: --lineprecision-report DIR

text
Causes mypy to generate a flat text file report with per-module
statistics of how many lines are typechecked etc.

.. option:: --txt-report / --xslt-txt-report DIR

text
Causes mypy to generate a text file type checking coverage report.

To generate this report, you must either manually install the `lxml`_
library or specify mypy installation with the setuptools extra
``mypy[reports]``.

.. option:: --xml-report DIR

text
Causes mypy to generate an XML type checking coverage report.

To generate this report, you must either manually install the `lxml`_
library or specify mypy installation with the setuptools extra
``mypy[reports]``.

Enabling incomplete/experimental features


.. option:: --enable-incomplete-feature {PreciseTupleTypes,InlineTypedDict}

text
Some features may require several mypy releases to implement, for example
due to their complexity, potential for backwards incompatibility, or
ambiguous semantics that would benefit from feedback from the community.
You can enable such features for early preview using this flag. Note that
it is not guaranteed that all features will be ultimately enabled by
default. In *rare cases* we may decide to not go ahead with certain
features.

List of currently incomplete/experimental features:

  • PreciseTupleTypes: this feature will infer more precise tuple types in
    various scenarios. Before variadic types were added to the Python type system
    by :pep:646, it was impossible to express a type like "a tuple with
    at least two integers". The best type available was tuple[int, ...].
    Therefore, mypy applied very lenient checking for variable-length tuples.
    Now this type can be expressed as tuple[int, int, *tuple[int, ...]].
    For such more precise types (when explicitly defined by a user) mypy,
    for example, warns about unsafe index access, and generally handles them
    in a type-safe manner. However, to avoid problems in existing code, mypy
    does not infer these precise types when it technically can. Here are
    notable examples where PreciseTupleTypes infers more precise types:

    .. code-block:: python

    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 feature enables non-standard syntax for inline
    :ref:TypedDicts <typeddict>, for example:

    .. code-block:: python

    def test_values() -> {"width": int, "description": str}:
    return {"width": 42, "description": "test"}

Miscellaneous


.. option:: --install-types

text
This flag causes mypy to install known missing stub packages for
third-party libraries using pip.  It will display the pip command
that will be run, and expects a confirmation before installing
anything. For security reasons, these stubs are limited to only a
small subset of manually selected packages that have been
verified by the typeshed team. These packages include only stub
files and no executable code.

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 new in mypy 0.900. Previous mypy versions included a
    selection of third-party package stubs, instead of having
    them installed separately.

.. option:: --non-interactive

When used together with :option:--install-types <mypy --install-types>, this causes mypy to install all suggested stub
packages using pip without asking for confirmation, and then
continues to perform type checking using the installed stubs, if
some files or modules are provided to type check.

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.

.. option:: --junit-xml JUNIT_XML_OUTPUT_FILE

text
Causes mypy to generate a JUnit XML test result document with
type checking results. This can make it easier to integrate mypy
with continuous integration (CI) tools.

.. option:: --junit-format {global,per_file}

text
If --junit-xml is set, specifies format.
global (default): single test with all errors;
per_file: one test entry per file with failures.

.. option:: --find-occurrences CLASS.MEMBER

text
This flag will make mypy print out all usages of a class member
based on static type information. This feature is experimental.

.. option:: --scripts-are-modules

text
This flag will give command line arguments that appear to be
scripts (i.e. files whose name does not end in ``.py``)
a module name derived from the script name rather than the fixed
name :py:mod:`__main__`.

This lets you check more than one script in a single mypy invocation.
(The default :py:mod:`__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.)

.. _lxml: https://pypi.org/project/lxml/
.. _SQLite: https://www.sqlite.org/


File: docs/source/common_issues.rst

.. _common_issues:

Common issues and solutions

This section has examples of cases when you need to update your code
to use static typing, and ideas for working around issues if mypy
doesn't work as expected. Statically typed code is often identical to
normal Python code (except for type annotations), but sometimes you need
to do things slightly differently.

.. _annotations_needed:

No errors reported for obviously wrong code

There are several common reasons why obviously wrong code is not
flagged as an error.

The function containing the error is not annotated.

Functions that
do not have any annotations (neither for any argument nor for the
return type) are not type-checked, and even the most blatant type
errors (e.g. 2 + 'a') pass silently. The solution is to add
annotations. Where that isn't possible, functions without annotations
can be checked using :option:--check-untyped-defs <mypy --check-untyped-defs>.

Example:

.. code-block:: python

text
def foo(a):
    return '(' + a.split() + ')'  # No error!

This gives no error even though a.split() is "obviously" a list
(the author probably meant a.strip()). The error is reported
once you add annotations:

.. code-block:: python

text
def foo(a: str) -> str:
    return '(' + a.split() + ')'
# error: Unsupported operand types for + ("str" and "list[str]")

If you don't know what types to add, you can use Any, but beware:

One of the values involved has type 'Any'.

Extending the above
example, if we were to leave out the annotation for a, we'd get
no error:

.. code-block:: python

text
def foo(a) -> str:
    return '(' + a.split() + ')'  # No error!

The reason is that if the type of a is unknown, the type of
a.split() is also unknown, so it is inferred as having type
Any, and it is no error to add a string to an Any.

If you're having trouble debugging such situations,
:ref:reveal_type() <reveal-type> might come in handy.

Note that sometimes library stubs with imprecise type information
can be a source of Any values.

:py:meth:__init__ <object.__init__> method has no annotated
arguments and no return type annotation.

This is basically a combination of the two cases above, in that __init__
without annotations can cause Any types leak into instance variables:

.. code-block:: python

text
class Bad:
    def __init__(self):
        self.value = "asdf"
        1 + "asdf"  # No error!

bad = Bad()
bad.value + 1           # No error!
reveal_type(bad)        # Revealed type is "__main__.Bad"
reveal_type(bad.value)  # Revealed type is "Any"

class Good:
    def __init__(self) -> None:  # Explicitly return None
        self.value = value

Some imports may be silently ignored.

A common source of unexpected Any values is the
:option:--ignore-missing-imports <mypy --ignore-missing-imports> flag.

When you use :option:--ignore-missing-imports <mypy --ignore-missing-imports>,
any imported module that cannot be found is silently replaced with Any.

To help debug this, simply leave out
:option:--ignore-missing-imports <mypy --ignore-missing-imports>.
As mentioned in :ref:fix-missing-imports, setting ignore_missing_imports=True
on a per-module basis will make bad surprises less likely and is highly encouraged.

Use of the :option:--follow-imports=skip <mypy --follow-imports> flags can also
cause problems. Use of these flags is strongly discouraged and only required in
relatively niche situations. See :ref:follow-imports for more information.

mypy considers some of your code unreachable.

See :ref:unreachable for more information.

A function annotated as returning a non-optional type returns 'None'
and mypy doesn't complain
.

.. code-block:: python

text
def foo() -> str:
    return None  # No error!

You may have disabled strict optional checking (see
:ref:--no-strict-optional <no_strict_optional> for more).

.. _silencing_checker:

Spurious errors and locally silencing the checker

You can use a # type: ignore comment to silence the type checker
on a particular line. For example, let's say our code is using
the C extension module frobnicate, and there's no stub available.
Mypy will complain about this, as it has no information about the
module:

.. code-block:: python

text
import frobnicate  # Error: No module "frobnicate"
frobnicate.start()

You can add a # type: ignore comment to tell mypy to ignore this
error:

.. code-block:: python

text
import frobnicate  # type: ignore
frobnicate.start()  # Okay!

The second line is now fine, since the ignore comment causes the name
frobnicate to get an implicit Any type.

The type ignore comment must be at the start of the comments on a line.
This type ignore will not take effect:

.. code-block:: python

text
import frobnicate  #example other comment # type: ignore
frobnicate.start()

.. note::

text
You can use the form ``# type: ignore[<code>]`` to only ignore
specific errors on the line. This way you are less likely to
silence unexpected errors that are not safe to ignore, and this
will also document what the purpose of the comment is.  See
:ref:`error-codes` for more information.

.. note::

text
The ``# type: ignore`` comment will only assign the implicit ``Any``
type if mypy cannot find information about that particular module. So,
if we did have a stub available for ``frobnicate`` then mypy would
ignore the ``# type: ignore`` comment and typecheck the stub as usual.

Another option is to explicitly annotate values with type Any --
mypy will let you perform arbitrary operations on Any
values. Sometimes there is no more precise type you can use for a
particular value, especially if you use dynamic Python features
such as :py:meth:__getattr__ <object.__getattr__>:

.. code-block:: python

class Wrapper:
...
def getattr(self, a: str) -> Any:
return getattr(self._wrapped, a)

Finally, you can create a stub file (.pyi) for a file that
generates spurious errors. Mypy will only look at the stub file
and ignore the implementation, since stub files take precedence
over .py files.

Ignoring a whole file

  • To only ignore errors, use a top-level # mypy: ignore-errors comment instead.
  • To only ignore errors with a specific error code, use a top-level
    # mypy: disable-error-code="..." comment. Example: # mypy: disable-error-code="truthy-bool, ignore-without-code"
  • To replace the contents of a module with Any, use a per-module follow_imports = skip.
    See :ref:Following imports <follow-imports> for details.

Note that a # type: ignore comment at the top of a module (before any statements,
including imports or docstrings) has the effect of ignoring the entire contents of the module.
This behaviour can be surprising and result in
"Module ... has no attribute ... [attr-defined]" errors.

Issues with code at runtime

Idiomatic use of type annotations can sometimes run up against what a given
version of Python considers legal code. These can result in some of the
following errors when trying to run your code:

  • ImportError from circular imports
  • NameError: name "X" is not defined from forward references
  • TypeError: 'type' object is not subscriptable from types that are not generic at runtime
  • ImportError or ModuleNotFoundError from use of stub definitions not available at runtime
  • TypeError: unsupported operand type(s) for |: 'type' and 'type' from use of new syntax

For dealing with these, see :ref:runtime_troubles.

Mypy runs are slow

If your mypy runs feel slow, you should probably use the :ref:mypy daemon <mypy_daemon>, which can speed up incremental mypy runtimes by
a factor of 10 or more. :ref:Remote caching <remote-cache> can
make cold mypy runs several times faster.

Furthermore: as of mypy 1.13 <https://mypy-lang.blogspot.com/2024/10/mypy-113-released.html>_,
mypy allows use of the orjson library for handling the cache instead of the stdlib json, for
improved performance. You can ensure the presence of orjson using the faster-cache extra:

text
python3 -m pip install -U mypy[faster-cache]

Mypy may depend on orjson by default in the future.

Types of empty collections

You often need to specify the type when you assign an empty list or
dict to a new variable, as mentioned earlier:

.. code-block:: python

a: list[int] = []

Without the annotation mypy can't always figure out the
precise type of a.

You can use a simple empty list literal in a dynamically typed function (as the
type of a would be implicitly Any and need not be inferred), if type
of the variable has been declared or inferred before, or if you perform a simple
modification operation in the same scope (such as append for a list):

.. code-block:: python

a = [] # Okay because followed by append, inferred type list[int]
for i in range(n):
a.append(i * i)

However, in more complex cases an explicit type annotation can be
required (mypy will tell you this). Often the annotation can
make your code easier to understand, so it doesn't only help mypy but
everybody who is reading the code!

Redefinitions with incompatible types

Each name within a function only has a single 'declared' type. You can
reuse for loop indices etc., but if you want to use a variable with
multiple types within a single function, you may need to instead use
multiple variables (or maybe declare the variable with an Any type).

.. code-block:: python

def f() -> None:
n = 1
...
n = 'x' # error: Incompatible types in assignment (expression has type "str", variable has type "int")

.. note::

Using the :option:--allow-redefinition <mypy --allow-redefinition>
flag can suppress this error in several cases.

Note that you can redefine a variable with a more precise or a more
concrete type. For example, you can redefine a sequence (which does
not support sort()) as a list and sort it in-place:

.. code-block:: python

text
def f(x: Sequence[int]) -> None:
    # Type of x is Sequence[int] here; we don't know the concrete type.
    x = list(x)
    # Type of x is list[int] here.
    x.sort()  # Okay!

See :ref:type-narrowing for more information.

.. _variance:

Invariance vs covariance

Most mutable generic collections are invariant. When using the legacy
TypeVar syntax, mypy considers all user-defined generic classes invariant
by default (see :ref:variance-of-generics for motivation). When using the
:pep:695 syntax (class MyClass[T]: ...), variance is inferred from
usage rather than defaulting to invariant.

The fact that mutable sequences are usually invariant can lead to some
unexpected errors when combined with type inference. For example:

.. code-block:: python

class A: ...
class B(A): ...

lst = [A(), A()] # Inferred type is list[A]
new_lst = [B(), B()] # inferred type is list[B]
lst = new_lst # mypy will complain about this, because List is invariant

Possible strategies in such situations are:

  • Use an explicit type annotation:

    .. code-block:: python

    new_lst: list[A] = [B(), B()]
    lst = new_lst # OK

  • Make a copy of the right hand side:

    .. code-block:: python

    lst = list(new_lst) # Also OK

  • Use immutable collections as annotations whenever possible:

    .. code-block:: python

    def f_bad(x: list[A]) -> A:
    return x[0]

    f_bad(new_lst) # Fails

    def f_good(x: Sequence[A]) -> A:
    return x[0]

    f_good(new_lst) # OK

Declaring a supertype as variable type

Sometimes the inferred type is a subtype (subclass) of the desired
type. The type inference uses the first assignment to infer the type
of a name:

.. code-block:: python

class Shape: ...
class Circle(Shape): ...
class Triangle(Shape): ...

shape = Circle() # mypy infers the type of shape to be Circle
shape = Triangle() # error: Incompatible types in assignment (expression has type "Triangle", variable has type "Circle")

You can just give an explicit type for the variable in cases such the
above example:

.. code-block:: python

shape: Shape = Circle() # The variable s can be any Shape, not just Circle
shape = Triangle() # OK

Complex type tests

Mypy can usually infer the types correctly when using :py:func:isinstance ,
:py:func:issubclass ,
or type(obj) is some_class type tests,
and even :ref:user-defined type guards <type-guards>,
but for other kinds of checks you may need to add an
explicit type cast:

.. code-block:: python

from collections.abc import Sequence
from typing import cast

def find_first_str(a: Sequence[object]) -> str:
index = next((i for i, s in enumerate(a) if isinstance(s, str)), -1)
if index < 0:
raise ValueError('No str found')

text
found = a[index]  # Has type "object", despite the fact that we know it is "str"
  return cast(str, found)  # We need an explicit cast to make mypy happy

Alternatively, you can use an assert statement together with some
of the supported type inference techniques:

.. code-block:: python

def find_first_str(a: Sequence[object]) -> str:
index = next((i for i, s in enumerate(a) if isinstance(s, str)), -1)
if index < 0:
raise ValueError('No str found')

text
found = a[index]  # Has type "object", despite the fact that we know it is "str"
  assert isinstance(found, str)  # Now, "found" will be narrowed to "str"
  return found  # No need for the explicit "cast()" anymore

.. note::

text
Note that the :py:class:`object` type used in the above example is similar
to ``Object`` in Java: it only supports operations defined for *all*
objects, such as equality and :py:func:`isinstance`. The type ``Any``,
in contrast, supports all operations, even if they may fail at
runtime. The cast above would have been unnecessary if the type of
``o`` was ``Any``.

.. note::

You can read more about type narrowing techniques :ref:here <type-narrowing>.

Type inference in Mypy is designed to work well in common cases, to be
predictable and to let the type checker give useful error
messages. More powerful type inference strategies often have complex
and difficult-to-predict failure modes and could result in very
confusing error messages. The tradeoff is that you as a programmer
sometimes have to give the type checker a little help.

.. _version_and_platform_checks:

Python version and system platform checks

Mypy supports the ability to perform Python version checks and platform
checks (e.g. Windows vs Posix), ignoring code paths that won't be run on
the targeted Python version or platform. This allows you to more effectively
typecheck code that supports multiple versions of Python or multiple operating
systems.

More specifically, mypy will understand the use of :py:data:sys.version_info and
:py:data:sys.platform checks within if/elif/else statements. For example:

.. code-block:: python

import sys

Distinguishing between different versions of Python:

if sys.version_info >= (3, 13):
# Python 3.13+ specific definitions and imports
else:
# Other definitions and imports

Distinguishing between different operating systems:

if sys.platform.startswith("linux"):
# Linux-specific code
elif sys.platform == "darwin":
# Mac-specific code
elif sys.platform == "win32":
# Windows-specific code
else:
# Other systems

As a special case, you can also use one of these checks in a top-level
(unindented) assert; this makes mypy skip the rest of the file.
Example:

.. code-block:: python

import sys

assert sys.platform != 'win32'

The rest of this file doesn't apply to Windows.

Some other expressions exhibit similar behavior; in particular,
:py:data:~typing.TYPE_CHECKING, variables named MYPY or TYPE_CHECKING, and any variable
whose name is passed to :option:--always-true <mypy --always-true> or :option:--always-false <mypy --always-false>.
(However, True and False are not treated specially!)

.. note::

Mypy currently does not support more complex checks, and does not assign
any special meaning when assigning a :py:data:sys.version_info or :py:data:sys.platform
check to a variable. This may change in future versions of mypy.

By default, mypy will use your current version of Python and your current
operating system as default values for :py:data:sys.version_info and
:py:data:sys.platform.

To target a different Python version, use the :option:--python-version X.Y <mypy --python-version> flag.
For example, to verify your code typechecks if were run using Python 3.8, pass
in :option:--python-version 3.8 <mypy --python-version> from the command line. Note that you do not need
to have Python 3.8 installed to perform this check.

To target a different operating system, use the :option:--platform PLATFORM <mypy --platform> flag.
For example, to verify your code typechecks if it were run in Windows, pass
in :option:--platform win32 <mypy --platform>. See the documentation for :py:data:sys.platform
for examples of valid platform parameters.

.. _reveal-type:

Displaying the type of an expression

You can use reveal_type(expr) to ask mypy to display the inferred
static type of an expression. This can be useful when you don't quite
understand how mypy handles a particular piece of code. Example:

.. code-block:: python

reveal_type((1, 'hello')) # Revealed type is "tuple[builtins.int, builtins.str]"

You can also use reveal_locals() at any line in a file
to see the types of all local variables at once. Example:

.. code-block:: python

a = 1
b = 'one'
reveal_locals()

Revealed local types are:

a: builtins.int

b: builtins.str

.. note::

text
``reveal_type`` and ``reveal_locals`` are handled specially by mypy during
type checking, and don't have to be defined or imported.

However, if you want to run your code,
you'll have to remove any ``reveal_type`` and ``reveal_locals``
calls from your program or else Python will give you an error at runtime.

Alternatively, you can import ``reveal_type`` from ``typing_extensions``
or ``typing`` (on Python 3.11 and newer)

.. _silencing-linters:

Silencing linters

In some cases, linters will complain about unused imports or code. In
these cases, you can silence them with a comment after type comments, or on
the same line as the import:

.. code-block:: python

to silence complaints about unused imports

from typing import List # noqa
a = None # type: List[int]

To silence the linter on the same line as a type comment
put the linter comment after the type comment:

.. code-block:: python

text
a = some_complex_thing()  # type: ignore  # noqa

Covariant subtyping of mutable protocol members is rejected

Mypy rejects this because this is potentially unsafe.
Consider this example:

.. code-block:: python

from typing import Protocol

class P(Protocol):
x: float

def fun(arg: P) -> None:
arg.x = 3.14

class C:
x = 42
c = C()
fun(c) # This is not safe
c.x << 5 # Since this will fail!

To work around this problem consider whether "mutating" is actually part
of a protocol. If not, then one can use a :py:class:@property in
the protocol definition:

.. code-block:: python

from typing import Protocol

class P(Protocol):
@property
def x(self) -> float:
pass

def fun(arg: P) -> None:
...

class C:
x = 42
fun(C()) # OK

Dealing with conflicting names

Suppose you have a class with a method whose name is the same as an
imported (or built-in) type, and you want to use the type in another
method signature. E.g.:

.. code-block:: python

class Message:
def bytes(self):
...
def register(self, path: bytes): # error: Invalid type "mod.Message.bytes"
...

The third line elicits an error because mypy sees the argument type
bytes as a reference to the method by that name. Other than
renaming the method, a workaround is to use an alias:

.. code-block:: python

bytes_ = bytes
class Message:
def bytes(self):
...
def register(self, path: bytes_):
...

Using a development mypy build

You can install the latest development version of mypy from source. Clone the
mypy repository on GitHub <https://github.com/python/mypy>_, and then run
pip install locally:

.. code-block:: text

text
git clone https://github.com/python/mypy.git
cd mypy
python3 -m pip install --upgrade .

To install a development version of mypy that is mypyc-compiled, see the
instructions at the mypyc wheels repo <https://github.com/mypyc/mypy_mypyc-wheels>_.

Variables vs type aliases

Mypy has both type aliases and variables with types like type[...]. These are
subtly different, and it's important to understand how they differ to avoid pitfalls.

  1. A variable with type type[...] is defined using an assignment with an
    explicit type annotation:

    .. code-block:: python

    class A: ...
    tp: type[A] = A

  2. You can define a type alias using an assignment without an explicit type annotation
    at the top level of a module:

    .. code-block:: python

    class A: ...
    Alias = A

    You can also use TypeAlias (:pep:613) to define an explicit type alias:

    .. code-block:: python

    from typing import TypeAlias

    class A: ...
    Alias: TypeAlias = A

    You should always use TypeAlias to define a type alias in a class body or
    inside a function.

The main difference is that the target of an alias is precisely known statically, and this
means that they can be used in type annotations and other type contexts. Type aliases
can't be defined conditionally (unless using
:ref:supported Python version and platform checks <version_and_platform_checks>):

.. code-block:: python

text
class A: ...
 class B: ...

 if random() > 0.5:
     Alias = A
 else:
     # error: Cannot assign multiple types to name "Alias" without an
     # explicit "Type[...]" annotation
     Alias = B

 tp: type[object]  # "tp" is a variable with a type object value
 if random() > 0.5:
     tp = A
 else:
     tp = B  # This is OK

 def fun1(x: Alias) -> None: ...  # OK
 def fun2(x: tp) -> None: ...  # Error: "tp" is not valid as a type

Incompatible overrides

It's unsafe to override a method with a more specific argument type,
as it violates the Liskov substitution principle <https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle>_.
For return types, it's unsafe to override a method with a more general
return type.

Other incompatible signature changes in method overrides, such as
adding an extra required parameter, or removing an optional parameter,
will also generate errors. The signature of a method in a subclass
should accept all valid calls to the base class method. Mypy
treats a subclass as a subtype of the base class. An instance of a
subclass is valid everywhere where an instance of the base class is
valid.

This example demonstrates both safe and unsafe overrides:

.. code-block:: python

text
from collections.abc import Sequence, Iterable

class A:
    def test(self, t: Sequence[int]) -> Sequence[str]:
        ...

class GeneralizedArgument(A):
    # A more general argument type is okay
    def test(self, t: Iterable[int]) -> Sequence[str]:  # OK
        ...

class NarrowerArgument(A):
    # A more specific argument type isn't accepted
    def test(self, t: list[int]) -> Sequence[str]:  # Error
        ...

class NarrowerReturn(A):
    # A more specific return type is fine
    def test(self, t: Sequence[int]) -> list[str]:  # OK
        ...

class GeneralizedReturn(A):
    # A more general return type is an error
    def test(self, t: Sequence[int]) -> Iterable[str]:  # Error
        ...

You can use # type: ignore[override] to silence the error. Add it
to the line that generates the error, if you decide that type safety is
not necessary:

.. code-block:: python

text
class NarrowerArgument(A):
    def test(self, t: list[int]) -> Sequence[str]:  # type: ignore[override]
        ...

.. _unreachable:

Unreachable code

Mypy may consider some code as unreachable, even if it might not be
immediately obvious why. It's important to note that mypy will not
type check such code. Consider this example:

.. code-block:: python

text
class Foo:
    bar: str = ''

def bar() -> None:
    foo: Foo = Foo()
    return
    x: int = 'abc'  # Unreachable -- no error

It's easy to see that any statement after return is unreachable,
and hence mypy will not complain about the mistyped code below
it. For a more subtle example, consider this code:

.. code-block:: python

text
class Foo:
    bar: str = ''

def bar() -> None:
    foo: Foo = Foo()
    assert foo.bar is None
    x: int = 'abc'  # Unreachable -- no error

Again, mypy will not report any errors. The type of foo.bar is
str, and mypy reasons that it can never be None. Hence the
assert statement will always fail and the statement below will
never be executed. (Note that in Python, None is not an empty
reference but an object of type None.)

In this example mypy will go on to check the last line and report an
error, since mypy thinks that the condition could be either True or
False:

.. code-block:: python

text
class Foo:
    bar: str = ''

def bar() -> None:
    foo: Foo = Foo()
    if not foo.bar:
        return
    x: int = 'abc'  # Reachable -- error

If you use the :option:--warn-unreachable <mypy --warn-unreachable> flag, mypy will generate
an error about each unreachable code block.

Narrowing and inner functions

Because closures in Python are late-binding (https://docs.python-guide.org/writing/gotchas/#late-binding-closures),
mypy will not narrow the type of a captured variable in an inner function.
This is best understood via an example:

.. code-block:: python

text
def foo(x: int | None) -> Callable[[], int]:
    if x is None:
        x = 5
    print(x + 1)  # mypy correctly deduces x must be an int here
    def inner() -> int:
        return x + 1  # but (correctly) complains about this line

    x = None  # because x could later be assigned None
    return inner

inner = foo(5)
inner()  # this will raise an error when called

To get this code to type check, you could assign y = x after x has been
narrowed, and use y in the inner function, or add an assert in the inner
function.

.. _incorrect-self:

Incorrect use of ``Self``

Self is not the type of the current class; it's a type variable with upper
bound of the current class. That is, it represents the type of the current class
or of potential subclasses.

.. code-block:: python

text
from typing import Self

class Foo:
    @classmethod
    def constructor(cls) -> Self:
        # Instead, either call cls() or change the annotation to -> Foo
        return Foo()  # error: Incompatible return value type (got "Foo", expected "Self")

class Bar(Foo):
    ...

reveal_type(Foo.constructor())  # note: Revealed type is "Foo"
# In the context of the subclass Bar, the Self return type promises
# that the return value will be Bar
reveal_type(Bar.constructor())  # note: Revealed type is "Bar"

File: docs/source/config_file.rst

.. _config-file:

The mypy configuration file

Mypy is very configurable. This is most useful when introducing typing to
an existing codebase. See :ref:existing-code for concrete advice for
that situation.

Mypy supports reading configuration settings from a file. By default, mypy will
discover configuration files by walking up the file system (up until the root of
a repository or the root of the filesystem). In each directory, it will look for
the following configuration files (in this order):

text
1. ``mypy.ini``
2. ``.mypy.ini``
3. ``pyproject.toml`` (containing a ``[tool.mypy]`` section)
4. ``setup.cfg`` (containing a ``[mypy]`` section)

If no configuration file is found by this method, mypy will then look for
configuration files in the following locations (in this order):

text
1. ``$XDG_CONFIG_HOME/mypy/config``
2. ``~/.config/mypy/config``
3. ``~/.mypy.ini``

The :option:--config-file <mypy --config-file> command-line flag has the
highest precedence and must point towards a valid configuration file;
otherwise mypy will report an error and exit. Without the command line option,
mypy will look for configuration files in the precedence order above.

It is important to understand that there is no merging of configuration
files, as it would lead to ambiguity.

Most flags correspond closely to :ref:command-line flags <command-line> but there are some differences in flag names and some
flags may take a different value based on the module being processed.

Some flags support user home directory and environment variable expansion.
To refer to the user home directory, use ~ at the beginning of the path.
To expand environment variables use $VARNAME or ${VARNAME}.

Config file format


The configuration file format is the usual
:doc:ini file format. It should contain
section names in square brackets and flag settings of the form
NAME = VALUE. Comments start with # characters.

  • A section named [mypy] must be present. This specifies
    the global flags.

  • Additional sections named [mypy-PATTERN1,PATTERN2,...] may be
    present, where PATTERN1, PATTERN2, etc., are comma-separated
    patterns of fully-qualified module names, with some components optionally
    replaced by the '*' character (e.g. foo.bar, foo.bar.*, foo.*.baz).
    These sections specify additional flags that only apply to modules
    whose name matches at least one of the patterns.

    A pattern of the form qualified_module_name matches only the named module,
    while dotted_module_name.* matches dotted_module_name and any
    submodules (so foo.bar.* would match all of foo.bar,
    foo.bar.baz, and foo.bar.baz.quux).

    Patterns may also be "unstructured" wildcards, in which stars may
    appear in the middle of a name (e.g
    site.*.migrations.*). Stars match zero or more module
    components (so site.*.migrations.* can match site.migrations).

    .. _config-precedence:

    When options conflict, the precedence order for configuration is:

    1. :ref:Inline configuration in the source file
    2. Sections with concrete module names (foo.bar)
    3. Sections with "unstructured" wildcard patterns (foo.*.baz),
      with sections later in the configuration file overriding
      sections earlier.
    4. Sections with "well-structured" wildcard patterns
      (foo.bar.*), with more specific overriding more general.
    5. Command line options.
    6. Top-level configuration file options.

The difference in precedence order between "structured" patterns (by
specificity) and "unstructured" patterns (by order in the file) is
unfortunate, and is subject to change in future versions.

.. note::

The :confval:warn_unused_configs flag may be useful to debug misspelled
section names.

.. note::

Configuration flags are liable to change between releases.

Per-module and global options


Some of the config options may be set either globally (in the [mypy] section)
or on a per-module basis (in sections like [mypy-foo.bar]).

If you set an option both globally and for a specific module, the module configuration
options take precedence. This lets you set global defaults and override them on a
module-by-module basis. If multiple pattern sections match a module, :ref:the options from the most specific section are used where they disagree <config-precedence>.

Some other options, as specified in their description,
may only be set in the global section ([mypy]).

Inverting option values


Options that take a boolean value may be inverted by adding no_ to
their name or by (when applicable) swapping their prefix from
disallow to allow (and vice versa).

Example mypy.ini


Here is an example of a mypy.ini file. To use this config file, place it at the root
of your repo and run mypy.

.. code-block:: ini

text
# Global options:

[mypy]
warn_return_any = True
warn_unused_configs = True

# Per-module options:

[mypy-mycode.foo.*]
disallow_untyped_defs = True

[mypy-mycode.bar]
warn_return_any = False

[mypy-somelibrary]
ignore_missing_imports = True

This config file specifies two global options in the [mypy] section. These two
options will:

  1. Report an error whenever a function returns a value that is inferred
    to have type Any.

  2. Report any config options that are unused by mypy. (This will help us catch typos
    when making changes to our config file).

Next, this module specifies three per-module options. The first two options change how mypy
type checks code in mycode.foo.* and mycode.bar, which we assume here are two modules
that you wrote. The final config option changes how mypy type checks somelibrary, which we
assume here is some 3rd party library you've installed and are importing. These options will:

  1. Selectively disallow untyped function definitions only within the mycode.foo
    package -- that is, only for function definitions defined in the
    mycode/foo directory.

  2. Selectively disable the "function is returning any" warnings within
    mycode.bar only. This overrides the global default we set earlier.

  3. Suppress any error messages generated when your codebase tries importing the
    module somelibrary. This is useful if somelibrary is some 3rd party library
    missing type hints.

.. _config-file-import-discovery:

Import discovery


For more information, see the :ref:Import discovery
section of the command line docs.

.. confval:: mypy_path

text
:type: string

Specifies the paths to use, after trying the paths from ``MYPYPATH`` environment
variable.  Useful if you'd like to keep stubs in your repo, along with the config file.
Multiple paths are always separated with a ``:`` or ``,`` regardless of the platform.
User home directory and environment variables will be expanded.

Relative paths are treated relative to the working directory of the mypy command,
not the config file.
Use the ``MYPY_CONFIG_FILE_DIR`` environment variable to refer to paths relative to
the config file (e.g. ``mypy_path = $MYPY_CONFIG_FILE_DIR/src``).

This option may only be set in the global section (``[mypy]``).

**Note:** On Windows, use UNC paths to avoid using ``:`` (e.g. ``\\127.0.0.1\X$\MyDir`` where ``X`` is the drive letter).

.. confval:: files

text
:type: comma-separated list of strings

A comma-separated list of paths which should be checked by mypy if none are given on the command
line. Supports recursive file globbing using :py:mod:`glob`, where ``*`` (e.g. ``*.py``) matches
files in the current directory and ``**/`` (e.g. ``**/*.py``) matches files in any directories below
the current one. User home directory and environment variables will be expanded.

This option may only be set in the global section (``[mypy]``).

.. confval:: modules

text
:type: comma-separated list of strings

A comma-separated list of packages which should be checked by mypy if none are given on the command
line. Mypy *will not* recursively type check any submodules of the provided
module.

This option may only be set in the global section (``[mypy]``).

.. confval:: packages

text
:type: comma-separated list of strings

A comma-separated list of packages which should be checked by mypy if none are given on the command
line.  Mypy *will* recursively type check any submodules of the provided
package. This flag is identical to :confval:`modules` apart from this
behavior.

This option may only be set in the global section (``[mypy]``).

.. confval:: exclude

text
:type: regular expression

A regular expression that matches file names, directory names and paths
which mypy should ignore while recursively discovering files to check.
Use forward slashes (``/``) as directory separators on all platforms.

.. code-block:: ini

  [mypy]
  exclude = (?x)(
      ^one\.py$    # files named "one.py"
      | two\.pyi$  # or files ending with "two.pyi"
      | ^three\.   # or files starting with "three."
    )

Crafting a single regular expression that excludes multiple files while remaining
human-readable can be a challenge. The above example demonstrates one approach.
``(?x)`` enables the ``VERBOSE`` flag for the subsequent regular expression, which
:py:data:`ignores most whitespace and supports comments <re.VERBOSE>`.
The above is equivalent to: ``(^one\.py$|two\.pyi$|^three\.)``.

For more details, see :option:`--exclude <mypy --exclude>`.

This option may only be set in the global section (``[mypy]``).

.. note::

   Note that the TOML equivalent differs slightly. It can be either a single string
   (including a multi-line string) -- which is treated as a single regular
   expression -- or an array of such strings. The following TOML examples are
   equivalent to the above INI example.

   Array of strings:

   .. code-block:: toml

      [tool.mypy]
      exclude = [
          "^one\\.py$",  # TOML's double-quoted strings require escaping backslashes
          'two\.pyi$',  # but TOML's single-quoted strings do not
          '^three\.',
      ]

   A single, multi-line string:

   .. code-block:: toml

      [tool.mypy]
      exclude = '''(?x)(
          ^one\.py$    # files named "one.py"
          | two\.pyi$  # or files ending with "two.pyi"
          | ^three\.   # or files starting with "three."
      )'''  # TOML's single-quoted strings do not require escaping backslashes

   See :ref:`using-a-pyproject-toml`.

.. confval:: exclude_gitignore

text
:type: boolean
:default: False

This flag will add everything that matches ``.gitignore`` file(s) to :confval:`exclude`.
This option may only be set in the global section (``[mypy]``).

.. confval:: namespace_packages

text
:type: boolean
:default: True

Enables :pep:`420` style namespace packages.  See the
corresponding flag :option:`--no-namespace-packages <mypy --no-namespace-packages>`
for more information.

This option may only be set in the global section (``[mypy]``).

.. confval:: explicit_package_bases

text
:type: boolean
:default: False

This flag tells mypy that top-level packages will be based in either the
current directory, or a member of the ``MYPYPATH`` environment variable or
:confval:`mypy_path` config option. This option is only useful in
the absence of `__init__.py`. See :ref:`Mapping file
paths to modules <mapping-paths-to-modules>` for details.

This option may only be set in the global section (``[mypy]``).

.. confval:: ignore_missing_imports

text
:type: boolean
:default: False

Suppresses error messages about imports that cannot be resolved.

If this option is used in a per-module section, the module name should
match the name of the *imported* module, not the module containing the
import statement.

.. confval:: follow_untyped_imports

text
:type: boolean
:default: False

Makes mypy analyze imports from installed packages even if missing a
:ref:`py.typed marker or stubs `.

If this option is used in a per-module section, the module name should
match the name of the *imported* module, not the module containing the
import statement.

.. 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.

.. confval:: follow_imports

text
:type: string
:default: ``normal``

Directs what to do with imports when the imported module is found
as a ``.py`` file and not part of the files, modules and packages
provided on the command line.

The four possible values are ``normal``, ``silent``, ``skip`` and
``error``.  For explanations see the discussion for the
:option:`--follow-imports <mypy --follow-imports>` command line flag.

Using this option in a per-module section (potentially with a wildcard,
as described at the top of this page) is a good way to prevent mypy from
checking portions of your code.

If this option is used in a per-module section, the module name should
match the name of the *imported* module, not the module containing the
import statement.

.. confval:: follow_imports_for_stubs

text
:type: boolean
:default: False

Determines whether to respect the :confval:`follow_imports` setting even for
stub (``.pyi``) files.

Used in conjunction with :confval:`follow_imports=skip <follow_imports>`, this can be used
to suppress the import of a module from ``typeshed``, replacing it
with ``Any``.

Used in conjunction with :confval:`follow_imports=error <follow_imports>`, this can be used
to make any use of a particular ``typeshed`` module an error.

.. note::

     This is not supported by the mypy daemon.

.. confval:: python_executable

text
:type: string

Specifies the path to the Python executable to inspect to collect
a list of available :ref:`PEP 561 packages `. User
home directory and environment variables will be expanded. Defaults to
the executable used to run mypy.

This option may only be set in the global section (``[mypy]``).

.. confval:: no_site_packages

text
:type: boolean
:default: False

Disables using type information in installed packages (see :pep:`561`).
This will also disable searching for a usable Python executable. This acts
the same as :option:`--no-site-packages <mypy --no-site-packages>` command
line flag.

.. confval:: no_silence_site_packages

text
:type: boolean
:default: False

Enables reporting error messages generated within installed packages (see
:pep:`561` for more details on distributing type information). Those error
messages are suppressed by default, since you are usually not able to
control errors in 3rd party code.

This option may only be set in the global section (``[mypy]``).

Platform configuration


.. confval:: python_version

text
:type: string

Specifies the Python version used to parse and check the target
program.  The string should be in the format ``MAJOR.MINOR`` --
for example ``3.10``.  The default is the version of the Python
interpreter used to run mypy.

This option may only be set in the global section (``[mypy]``).

.. confval:: platform

text
:type: string

Specifies the OS platform for the target program, for example
``darwin`` or ``win32`` (meaning OS X or Windows, respectively).
The default is the current platform as revealed by Python's
:py:data:`sys.platform` variable.

This option may only be set in the global section (``[mypy]``).

.. confval:: always_true

text
:type: comma-separated list of strings

Specifies a list of variables that mypy will treat as
compile-time constants that are always true.

.. confval:: always_false

text
:type: comma-separated list of strings

Specifies a list of variables that mypy will treat as
compile-time constants that are always false.

Disallow dynamic typing


For more information, see the :ref:Disallow dynamic typing <disallow-dynamic-typing>
section of the command line docs.

.. confval:: disallow_any_unimported

text
:type: boolean
:default: False

Disallows usage of types that come from unfollowed imports (anything imported from
an unfollowed import is automatically given a type of ``Any``).

.. confval:: disallow_any_expr

text
:type: boolean
:default: False

Disallows all expressions in the module that have type ``Any``.

.. confval:: disallow_any_decorated

text
:type: boolean
:default: False

Disallows functions that have ``Any`` in their signature after decorator transformation.

.. confval:: disallow_any_explicit

text
:type: boolean
:default: False

Disallows explicit ``Any`` in type positions such as type annotations and generic
type parameters.

.. confval:: disallow_any_generics

text
:type: boolean
:default: False

Disallows usage of generic types that do not specify explicit type parameters.

.. confval:: disallow_subclassing_any

text
:type: boolean
:default: False

Disallows subclassing a value of type ``Any``.

Untyped definitions and calls


For more information, see the :ref:Untyped definitions and calls
section of the command line docs.

.. confval:: disallow_untyped_calls

text
:type: boolean
:default: False

Disallows calling functions without type annotations from functions with type
annotations. Note that when used in per-module options, it enables/disables
this check **inside** the module(s) specified, not for functions that come
from that module(s), for example config like this:

.. code-block:: ini

    [mypy]
    disallow_untyped_calls = True

    [mypy-some.library.*]
    disallow_untyped_calls = False

will disable this check inside ``some.library``, not for your code that
imports ``some.library``. If you want to selectively disable this check for
all your code that imports ``some.library`` you should instead use
:confval:`untyped_calls_exclude`, for example:

.. code-block:: ini

    [mypy]
    disallow_untyped_calls = True
    untyped_calls_exclude = some.library

.. confval:: untyped_calls_exclude

text
:type: comma-separated list of strings

Selectively excludes functions and methods defined in specific packages,
modules, and classes from action of :confval:`disallow_untyped_calls`.
This also applies to all submodules of packages (i.e. everything inside
a given prefix). Note, this option does not support per-file configuration,
the exclusions list is defined globally for all your code.

.. confval:: disallow_untyped_defs

text
:type: boolean
:default: False

Disallows defining functions without type annotations or with incomplete type
annotations (a superset of :confval:`disallow_incomplete_defs`).

For example, it would report an error for :code:`def f(a, b)` and :code:`def f(a: int, b)`.

.. confval:: disallow_incomplete_defs

text
:type: boolean
:default: False

Disallows defining functions with incomplete type annotations, while still
allowing entirely unannotated definitions.

For example, it would report an error for :code:`def f(a: int, b)` but not :code:`def f(a, b)`.

.. confval:: check_untyped_defs

text
:type: boolean
:default: False

Type-checks the interior of functions without type annotations.

.. confval:: disallow_untyped_decorators

text
:type: boolean
:default: False

Reports an error whenever a function with type annotations is decorated with a
decorator without annotations.

.. _config-file-none-and-optional-handling:

None and Optional handling


For more information, see the :ref:None and Optional handling <none-and-optional-handling>
section of the command line docs.

.. confval:: implicit_optional

text
:type: boolean
:default: False

Causes mypy to treat parameters with a ``None``
default value as having an implicit optional type (``T | None``).

**Note:** This was True by default in mypy versions 0.980 and earlier.

.. confval:: strict_optional

text
:type: boolean
:default: True

Effectively disables checking of optional
types and ``None`` values. With this option, mypy doesn't
generally check the use of ``None`` values -- it is treated
as compatible with every type.

.. warning::

    ``strict_optional = false`` is evil. Avoid using it and definitely do
    not use it without understanding what it does.

Configuring warnings


For more information, see the :ref:Configuring warnings <configuring-warnings>
section of the command line docs.

.. confval:: warn_redundant_casts

text
:type: boolean
:default: False

Warns about casting an expression to its inferred type.

This option may only be set in the global section (``[mypy]``).

.. confval:: warn_unused_ignores

text
:type: boolean
:default: False

Warns about unneeded ``# type: ignore`` comments.

.. confval:: warn_no_return

text
:type: boolean
:default: True

Shows errors for missing return statements on some execution paths.

.. confval:: warn_return_any

text
:type: boolean
:default: False

Shows a warning when returning a value with type ``Any`` from a function
declared with a non- ``Any`` return type.

.. confval:: warn_unreachable

text
:type: boolean
:default: False

Shows a warning when encountering any code inferred to be unreachable or
redundant after performing type analysis.

.. confval:: deprecated_calls_exclude

text
:type: comma-separated list of strings

Selectively excludes functions and methods defined in specific packages,
modules, and classes from the :ref:`deprecated<code-deprecated>` error code.
This also applies to all submodules of packages (i.e. everything inside
a given prefix). Note, this option does not support per-file configuration,
the exclusions list is defined globally for all your code.

Suppressing errors


Note: these configuration options are available in the config file only. There is
no analog available via the command line options.

.. confval:: ignore_errors

text
:type: boolean
:default: False

Ignores all non-fatal errors.

Miscellaneous strictness flags


For more information, see the :ref:Miscellaneous strictness flags <miscellaneous-strictness-flags>
section of the command line docs.

.. confval:: allow_untyped_globals

text
:type: boolean
:default: False

Causes mypy to suppress errors caused by not being able to fully
infer the types of global and class variables.

.. confval:: allow_redefinition

text
:type: boolean
:default: False

By default, mypy won't allow a variable to be redefined with an
unrelated type. This flag enables the redefinition of unannotated
variables with an arbitrary type. This also requires
:confval:`local_partial_types`, which is enabled by default starting
from mypy 2.0. Example:

.. code-block:: python

    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

This also enables an unannotated variable to have different types in different
code locations:

.. code-block:: python

    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, changing their type within function body
is allowed even if they are annotated, but that annotation is used to infer
types of r.h.s. of all subsequent assignments. Such middle-ground semantics
provides good balance for majority of common use cases. For example:

.. code-block:: python

    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.

.. confval:: allow_redefinition_new

text
:type: boolean
:default: False

Deprecated alias for :confval:`allow_redefinition`.

.. confval:: allow_redefinition_old

text
:type: boolean
:default: False

Allows variables to be redefined with an arbitrary type, as long as the redefinition
is in the same block and nesting level as the original definition.
Example where this can be useful:

.. code-block:: python

   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:

.. code-block:: python

    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

.. confval:: local_partial_types

text
:type: boolean
:default: True

This prevents inferring a variable type from an empty container (such as a list or
a dictionary) created at module top level or class body and updated in
a function. This must be enabled when using the :ref:`mypy daemon <mypy_daemon>`.

.. confval:: disable_error_code

text
:type: comma-separated list of strings

Allows disabling one or multiple error codes globally.

.. confval:: enable_error_code

text
:type: comma-separated list of strings

Allows enabling one or multiple error codes globally.

Note: This option will override disabled error codes from the disable_error_code option.

.. confval:: extra_checks

:type: boolean
:default: False

This flag enables additional checks that are technically correct but may be impractical.
See :option:mypy --extra-checks for more info.

.. confval:: implicit_reexport

text
:type: boolean
:default: True

By default, imported values to a module are treated as exported and mypy allows
other modules to import them. When false, mypy will not re-export unless
the item is imported using from-as or is included in ``__all__``. Note that mypy
treats stub files as if this is always disabled. For example:

.. code-block:: python

   # This won't re-export the value
   from foo import bar
   # 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']

.. confval:: strict_equality

:type: boolean
:default: False

Prohibit equality checks, identity checks, and container checks between
non-overlapping types (except None).

.. confval:: strict_equality_for_none

:type: boolean
:default: False

Include None in strict equality checks (requires :confval:strict_equality
to be activated).

.. confval:: strict_bytes

:type: boolean
:default: True

If disabled, mypy treats bytearray and memoryview as subtypes of bytes.
This has been enabled by default since mypy 2.0.

.. confval:: strict

:type: boolean
:default: False

Enable all optional error checking flags. You can see the list of
flags enabled by strict mode in the full :option:mypy --help
output.

Note: the exact list of flags enabled by :confval:strict may
change over time.

Configuring error messages


For more information, see the :ref:Configuring error messages <configuring-error-messages>
section of the command line docs.

These options may only be set in the global section ([mypy]).

.. confval:: show_error_context

text
:type: boolean
:default: False

Prefixes each error with the relevant context.

.. confval:: show_column_numbers

text
:type: boolean
:default: False

Shows column numbers in error messages.

.. confval:: show_error_code_links

text
:type: boolean
:default: False

Shows documentation link to corresponding error code.

.. confval:: hide_error_codes

text
:type: boolean
:default: False

Hides error codes in error messages. See :ref:`error-codes` for more information.

.. confval:: pretty

text
:type: boolean
:default: False

Use visually nicer output in error messages: use soft word wrap,
show source code snippets, and show error location markers.

.. confval:: color_output

text
:type: boolean
:default: True

Shows error messages with color enabled.

.. confval:: error_summary

text
:type: boolean
:default: True

Shows a short summary line after error messages.

.. confval:: show_absolute_path

text
:type: boolean
:default: False

Show absolute paths to files.

Incremental mode


These options may only be set in the global section ([mypy]).

.. confval:: incremental

text
:type: boolean
:default: True

Enables :ref:`incremental mode `.

.. confval:: cache_dir

text
:type: string
:default: ``.mypy_cache``

Specifies the location where mypy stores incremental cache info.
User home directory and environment variables will be expanded.
This setting will be overridden by the ``MYPY_CACHE_DIR`` environment
variable.

Note that the cache is only read when incremental mode is enabled
but is always written to, unless the value is set to ``/dev/null``
(UNIX) or ``nul`` (Windows).

.. confval:: sqlite_cache

text
:type: boolean
:default: True

Use an `SQLite`_ database to store the cache.

.. confval:: cache_fine_grained

text
:type: boolean
:default: False

Include fine-grained dependency information in the cache for the mypy daemon.

.. confval:: skip_version_check

text
:type: boolean
:default: False

Makes mypy use incremental cache data even if it was generated by a
different version of mypy. (By default, mypy will perform a version
check and regenerate the cache if it was written by older versions of mypy.)

.. confval:: skip_cache_mtime_checks

text
:type: boolean
:default: False

Skip cache internal consistency checks based on mtime.

Parallel type-checking configuration


These options may only be set in the global section ([mypy]).

.. confval:: num_workers

text
:type: integer
:default: 0

Use specific number of parallel worker processes for type-checking, see
:ref:`parallel type-checking ` for more details.
This setting will be overridden by the ``MYPY_NUM_WORKERS`` environment
variable.

Advanced options


These options may only be set in the global section ([mypy]).

.. confval:: plugins

text
:type: comma-separated list of strings

A comma-separated list of mypy plugins. See :ref:`extending-mypy-using-plugins`.

.. confval:: pdb

text
:type: boolean
:default: False

Invokes :mod:`pdb` on fatal error.

.. confval:: show_traceback

text
:type: boolean
:default: False

Shows traceback on fatal error.

.. confval:: raise_exceptions

text
:type: boolean
:default: False

Raise exception on fatal error.

.. confval:: custom_typing_module

text
:type: string

Specifies a custom module to use as a substitute for the :py:mod:`typing` module.

.. confval:: custom_typeshed_dir

text
:type: string

This specifies the directory where mypy looks for standard library typeshed
stubs, instead of the typeshed that ships with mypy.  This is
primarily intended to make it easier to test typeshed changes before
submitting them upstream, but also allows you to use a forked version of
typeshed.

User home directory and environment variables will be expanded.

Note that this doesn't affect third-party library stubs. To test third-party stubs,
for example try ``MYPYPATH=stubs/six mypy ...``.

.. confval:: warn_incomplete_stub

text
:type: boolean
:default: False

Warns about missing type annotations in typeshed.  This is only relevant
in combination with :confval:`disallow_untyped_defs` or :confval:`disallow_incomplete_defs`.

.. confval:: native_parser

text
:type: boolean
:default: False

This enables fast Rust-based parser that parses directly to mypy AST.
It will become the default parser in one of the next mypy releases.

Report generation


If these options are set, mypy will generate a report in the specified
format into the specified directory.

.. warning::

Generating reports disables incremental mode and can significantly slow down
your workflow. It is recommended to enable reporting only for specific runs
(e.g. in CI).

.. confval:: any_exprs_report

text
:type: string

Causes mypy to generate a text file report documenting how many
expressions of type ``Any`` are present within your codebase.

.. confval:: cobertura_xml_report

text
:type: string

Causes mypy to generate a Cobertura XML type checking coverage report.

To generate this report, you must either manually install the `lxml`_
library or specify mypy installation with the setuptools extra
``mypy[reports]``.

.. confval:: html_report / xslt_html_report

text
:type: string

Causes mypy to generate an HTML type checking coverage report.

To generate this report, you must either manually install the `lxml`_
library or specify mypy installation with the setuptools extra
``mypy[reports]``.

.. confval:: linecount_report

text
:type: string

Causes mypy to generate a text file report documenting the functions
and lines that are typed and untyped within your codebase.

.. confval:: linecoverage_report

text
:type: string

Causes mypy to generate a JSON file that maps each source file's
absolute filename to a list of line numbers that belong to typed
functions in that file.

.. confval:: lineprecision_report

text
:type: string

Causes mypy to generate a flat text file report with per-module
statistics of how many lines are typechecked etc.

.. confval:: txt_report / xslt_txt_report

text
:type: string

Causes mypy to generate a text file type checking coverage report.

To generate this report, you must either manually install the `lxml`_
library or specify mypy installation with the setuptools extra
``mypy[reports]``.

.. confval:: xml_report

text
:type: string

Causes mypy to generate an XML type checking coverage report.

To generate this report, you must either manually install the `lxml`_
library or specify mypy installation with the setuptools extra
``mypy[reports]``.

Miscellaneous


These options may only be set in the global section ([mypy]).

.. confval:: junit_xml

text
:type: string

Causes mypy to generate a JUnit XML test result document with
type checking results. This can make it easier to integrate mypy
with continuous integration (CI) tools.

.. confval:: junit_format

text
:type: string
:default: ``global``

If junit_xml is set, specifies format.
global (default): single test with all errors;
per_file: one test entry per file with failures.

.. confval:: scripts_are_modules

text
:type: boolean
:default: False

Makes script ``x`` become module ``x`` instead of ``__main__``.  This is
useful when checking multiple scripts in a single run.

.. confval:: warn_unused_configs

text
:type: boolean
:default: False

Warns about per-module sections in the config file that do not
match any files processed when invoking mypy.
(This requires turning off incremental mode using :confval:`incremental = False `.)

.. confval:: verbosity

text
:type: integer
:default: 0

Controls how much debug output will be generated.  Higher numbers are more verbose.

.. _using-a-pyproject-toml:

Using a pyproject.toml file


Instead of using a mypy.ini file, a pyproject.toml file (as specified by
PEP 518_) may be used instead. A few notes on doing so:

  • The [mypy] section should have tool. prepended to its name:

    • I.e., [mypy] would become [tool.mypy]
  • The module specific sections should be moved into [[tool.mypy.overrides]] sections:

    • For example, [mypy-packagename] would become:

.. code-block:: toml

[[tool.mypy.overrides]]
module = 'packagename'
...

  • Multi-module specific sections can be moved into a single [[tool.mypy.overrides]] section with a
    module property set to an array of modules:

    • For example, [mypy-packagename,packagename2] would become:

.. code-block:: toml

[[tool.mypy.overrides]]
module = [
'packagename',
'packagename2'
]
...

  • The following care should be given to values in the pyproject.toml files as compared to ini files:

    • Strings must be wrapped in double quotes, or single quotes if the string contains special characters

    • Boolean values should be all lower case

Please see the TOML Documentation_ for more details and information on
what is allowed in a toml file. See PEP 518_ for more information on the layout
and structure of the pyproject.toml file.

Example pyproject.toml


Here is an example of a pyproject.toml file. To use this config file, place it at the root
of your repo (or append it to the end of an existing pyproject.toml file) and run mypy.

.. code-block:: toml

text
# mypy global options:

[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
exclude = [
    '^file1\.py$',  # TOML literal string (single-quotes, no escaping necessary)
    "^file2\\.py$",  # TOML basic string (double-quotes, backslash and other characters need escaping)
]

# mypy per-module options:

[[tool.mypy.overrides]]
module = "mycode.foo.*"
disallow_untyped_defs = true

[[tool.mypy.overrides]]
module = "mycode.bar"
warn_return_any = false

[[tool.mypy.overrides]]
module = [
    "somelibrary",
    "some_other_library"
]
ignore_missing_imports = true

.. _lxml: https://pypi.org/project/lxml/
.. _SQLite: https://www.sqlite.org/
.. _PEP 518: https://www.python.org/dev/peps/pep-0518/
.. _TOML Documentation: https://toml.io/


File: docs/source/duck_type_compatibility.rst

Duck type compatibility

In Python, certain types are compatible even though they aren't subclasses of
each other. For example, int objects are valid whenever float objects
are expected. Mypy supports this idiom via duck type compatibility. This is
supported for a small set of built-in types:

  • int is duck type compatible with float and complex.
  • float is duck type compatible with complex.

.. note::
bytearray and memoryview were duck type compatible with bytes
by default prior to mypy 2.0. This can still be enabled with
:option:--no-strict-bytes <mypy --no-strict-bytes>.

For example, mypy considers an int object to be valid whenever a
float object is expected. Thus code like this is nice and clean
and also behaves as expected:

.. code-block:: python

import math

def degrees_to_radians(degrees: float) -> float:
return math.pi * degrees / 180

n = 90 # Inferred type 'int'
print(degrees_to_radians(n)) # Okay!

You can also often use :ref:protocol-types to achieve a similar effect in
a more principled and extensible fashion. Protocols don't apply to
cases like int being compatible with float, since float is not
a protocol class but a regular, concrete class, and many standard library
functions expect concrete instances of float (or int).


File: docs/source/dynamic_typing.rst

.. _dynamic-typing:

Dynamically typed code

In :ref:getting-started-dynamic-vs-static, we discussed how bodies of functions
that don't have any explicit type annotations in their function are "dynamically typed"
and that mypy will not check them. In this section, we'll talk a little bit more
about what that means and how you can enable dynamic typing on a more fine grained basis.

In cases where your code is too magical for mypy to understand, you can make a
variable or parameter dynamically typed by explicitly giving it the type
Any. Mypy will let you do basically anything with a value of type Any,
including assigning a value of type Any to a variable of any type (or vice
versa).

.. code-block:: python

from typing import Any

num = 1 # Statically typed (inferred to be int)
num = 'x' # error: Incompatible types in assignment (expression has type "str", variable has type "int")

dyn: Any = 1 # Dynamically typed (type Any)
dyn = 'x' # OK

num = dyn # No error, mypy will let you assign a value of type Any to any variable
num += 1 # Oops, mypy still thinks num is an int

You can think of Any as a way to locally disable type checking.
See :ref:silencing-type-errors for other ways you can shut up
the type checker.

Operations on Any values

You can do anything using a value with type Any, and the type checker
will not complain:

.. code-block:: python

text
def f(x: Any) -> int:
    # All of these are valid!
    x.foobar(1, y=2)
    print(x[3] + 'f')
    if x:
        x.z = x(2)
    open(x).read()
    return x

Values derived from an Any value also usually have the type Any
implicitly, as mypy can't infer a more precise result type. For
example, if you get the attribute of an Any value or call a
Any value the result is Any:

.. code-block:: python

text
def f(x: Any) -> None:
    y = x.foo()
    reveal_type(y)  # Revealed type is "Any"
    z = y.bar("mypy will let you do anything to y")
    reveal_type(z)  # Revealed type is "Any"

Any types may propagate through your program, making type checking
less effective, unless you are careful.

Function parameters without annotations are also implicitly Any:

.. code-block:: python

text
def f(x) -> None:
    reveal_type(x)  # Revealed type is "Any"
    x.can.do["anything", x]("wants", 2)

You can make mypy warn you about untyped function parameters using the
:option:--disallow-untyped-defs <mypy --disallow-untyped-defs> flag.

Generic types missing type parameters will have those parameters implicitly
treated as Any:

.. code-block:: python

text
def f(x: list) -> None:
    reveal_type(x)        # Revealed type is "builtins.list[Any]"
    reveal_type(x[0])     # Revealed type is "Any"
    x[0].anything_goes()  # OK

You can make mypy warn you about missing generic parameters using the
:option:--disallow-any-generics <mypy --disallow-any-generics> flag.

Finally, another major source of Any types leaking into your program is from
third party libraries that mypy does not know about. This is particularly the case
when using the :option:--ignore-missing-imports <mypy --ignore-missing-imports>
flag. See :ref:fix-missing-imports for more information about this.

.. _any-vs-object:

Any vs. object

The type :py:class:object is another type that can have an instance of arbitrary
type as a value. Unlike Any, :py:class:object is an ordinary static type (it
is similar to Object in Java), and only operations valid for all
types are accepted for :py:class:object values. These are all valid:

.. code-block:: python

text
def f(o: object) -> None:
    if o:
        print(o)
    print(isinstance(o, int))
    o = 2
    o = 'foo'

These are, however, flagged as errors, since not all objects support these
operations:

.. code-block:: python

text
def f(o: object) -> None:
    o.foo()       # Error!
    o + 2         # Error!
    open(o)       # Error!
    n: int = 1
    n = o         # Error!

If you're not sure whether you need to use :py:class:object or Any, use
:py:class:object -- only switch to using Any if you get a type checker
complaint.

You can use different :ref:type narrowing <type-narrowing>
techniques to narrow :py:class:object to a more specific
type (subtype) such as int. Type narrowing is not needed with
dynamically typed values (values with type Any).