3.15. Typing Check

  • mypy - the reference implementation for type checkers

  • pyre - written in OCaml and optimized for performance

  • pyright - a type checker that emphasizes speed

  • pytype - checks and infers types for unannotated code

3.15.1. Python

Setup:

>>> def add(a: int, b: int) -> int:
...     return a + b

Attribute __annotations__ (will change behavior in Python 3.14):

>>> add.__annotations__
{'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}

Function typing.get_type_hints():

>>> from typing import get_type_hints
>>>
>>> get_type_hints(add)
{'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}

Function inspect.get_annotations() (preferred until Python 3.14):

>>> from inspect import get_annotations
>>>
>>> get_annotations(add)
{'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}

Python 3.10 adds a new function to the standard library: inspect.get_annotations(). In Python versions 3.10 and newer, calling this function is the best practice for accessing the annotations dict of any object that supports annotations. This function can also 'un-stringize' stringized annotations for you. [2]

In Python 3.14, there is a new annotationlib module with functionality for working with annotations. This includes a annotationlib.get_annotations() function, which supersedes inspect.get_annotations(). [2]

Implications for readers of __annotations__:

If your code reads the __annotations__ attribute on objects, you may want to make changes in order to support code that relies on deferred evaluation of annotations. For example, you may want to use annotationlib.get_annotations() with the FORWARDREF format, as the dataclasses module now does. [1] [3]

You should avoid accessing __annotations__ directly on any object. Instead, use annotationlib.get_annotations() (Python 3.14+) or inspect.get_annotations() (Python 3.10+). [2]

3.15.2. MyPy

$ python3 -m pip install mypy
$ python3 -m mypy myfile.py

Configuration in pyproject.toml file:

[tool.mypy]
# Import discovery
files = ["src"]
namespace_packages = false
explicit_package_bases = false
ignore_missing_imports = false
follow_imports = "normal"
follow_imports_for_stubs = false
no_site_packages = false
no_silence_site_packages = false
# Platform configuration
python_version = "3.10"
platform = "linux-64"
# Disallow dynamic typing
disallow_any_unimported = false # TODO
disallow_any_expr = false # TODO
disallow_any_decorated = false # TODO
disallow_any_explicit = false # TODO
disallow_any_generics = true
disallow_subclassing_any = true
# Untyped definitions and calls
disallow_untyped_calls = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
# None and Optional handling
no_implicit_optional = true
strict_optional = true
# Configuring warnings
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_return_any = true
warn_unreachable = false # GH#27396
# Suppressing errors
show_none_errors = true
ignore_errors = false
enable_error_code = "ignore-without-code"
# Miscellaneous strictness flags
allow_untyped_globals = false
allow_redefinition = false
local_partial_types = false
implicit_reexport = true
strict_equality = true
# Configuring error messages
show_error_context = false
show_column_numbers = false
show_error_codes = true

3.15.3. PyType

$ python3 -m pip install pytype
$ python3 -m pytype -V 3.13 myfile.py

3.15.4. Pyright

3.15.5. Pyre

3.15.6. References