Skip to content
Commits on Source (3)
Metadata-Version: 2.1
Name: mypy
Version: 0.600
Version: 0.610
Summary: Optional static typing for Python
Home-page: http://www.mypy-lang.org/
Author: Jukka Lehtosalo
......
......@@ -136,7 +136,7 @@ this:
$ python3 -m pip install -U mypy
This should automatically installed the appropriate version of
This should automatically install the appropriate version of
mypy's parser, typed-ast. If for some reason it does not, you
can install it manually:
......
mypy (0.610-1) unstable; urgency=medium
* New upstream release.
-- Michael R. Crusoe <michael.crusoe@gmail.com> Mon, 11 Jun 2018 02:48:28 -0700
mypy (0.600-1) unstable; urgency=medium
* New upstream release.
......
......@@ -21,7 +21,6 @@ Standards-Version: 4.1.4
Vcs-Browser: https://salsa.debian.org/med-team/mypy
Vcs-Git: https://salsa.debian.org/med-team/mypy.git
Homepage: http://www.mypy-lang.org/
X-Python3-Version: >= 3.2
Package: mypy
Architecture: all
......
......@@ -17,9 +17,12 @@ include /usr/share/dpkg/pkg-info.mk
override_dh_auto_build:
dh_auto_build
PYTHONPATH=$(PPATH) help2man scripts/mypy --no-info \
PYTHONPATH=$(PPATH) help2man 'python3 -m mypy' --no-info \
--version-string="${DEB_VERSION_UPSTREAM}" \
--name 'Optional Static Typing for Python' > debian/mypy.1
sed -i 's/python3 -m mypy/mypy/g' debian/mypy.1
sed -i 's/python3/mypy/g' debian/mypy.1
sed -i 's/PYTHON3/MYPY/g' debian/mypy.1
PYTHONPATH=$(PPATH) help2man scripts/dmypy --no-info \
--version-string="${DEB_VERSION_UPSTREAM}" \
--name 'Client for mypy daemon mode' > debian/dmypy.1
......
Additional features
-------------------
This section discusses various features outside core mypy features.
This section discusses various features that did not fit in naturally in one
of the previous sections.
.. _function-overloading:
Function overloading
********************
Sometimes the types in a function depend on each other in ways that
can't be captured with a ``Union``. For example, the ``__getitem__``
(``[]`` bracket indexing) method can take an integer and return a
single item, or take a ``slice`` and return a ``Sequence`` of items.
You might be tempted to annotate it like so:
.. code-block:: python
from typing import Sequence, TypeVar, Union
T = TypeVar('T')
class MyList(Sequence[T]):
def __getitem__(self, index: Union[int, slice]) -> Union[T, Sequence[T]]:
if isinstance(index, int):
... # Return a T here
elif isinstance(index, slice):
... # Return a sequence of Ts here
else:
raise TypeError(...)
But this is too loose, as it implies that when you pass in an ``int``
you might sometimes get out a single item and sometimes a sequence.
The return type depends on the parameter type in a way that can't be
expressed using a type variable. Instead, we can use `overloading
<https://www.python.org/dev/peps/pep-0484/#function-method-overloading>`_
to give the same function multiple type annotations (signatures) and
accurately describe the function's behavior.
.. code-block:: python
from typing import overload, Sequence, TypeVar, Union
T = TypeVar('T')
class MyList(Sequence[T]):
# The @overload definitions are just for the type checker,
# and overwritten by the real implementation below.
@overload
def __getitem__(self, index: int) -> T:
pass # Don't put code here
# All overloads and the implementation must be adjacent
# in the source file, and overload order may matter:
# when two overloads may overlap, the more specific one
# should come first.
@overload
def __getitem__(self, index: slice) -> Sequence[T]:
pass # Don't put code here
# The implementation goes last, without @overload.
# It may or may not have type hints; if it does,
# these are checked against the overload definitions
# as well as against the implementation body.
def __getitem__(self, index: Union[int, slice]) -> Union[T, Sequence[T]]:
# This is exactly the same as before.
if isinstance(index, int):
... # Return a T here
elif isinstance(index, slice):
... # Return a sequence of Ts here
else:
raise TypeError(...)
Calls to overloaded functions are type checked against the variants,
not against the implementation. A call like ``my_list[5]`` would have
type ``T``, not ``Union[T, Sequence[T]]`` because it matches the
first overloaded definition, and ignores the type annotations on the
implementation of ``__getitem__``. The code in the body of the
definition of ``__getitem__`` is checked against the annotations on
the corresponding declaration. In this case the body is checked
with ``index: Union[int, slice]`` and a return type
``Union[T, Sequence[T]]``. If there are no annotations on the
corresponding definition, then code in the function body is not type
checked.
The annotations on the function body must be compatible with the
types given for the overloaded variants listed above it. The type
checker will verify that all the types for the overloaded variants
are compatible with the types given for the implementation. In this
case it checks that the parameter type ``int`` and the return type
``T`` are compatible with ``Union[int, slice]`` and
``Union[T, Sequence[T]]`` for the first variant. For the second
variant it verifies that the parameter type ``slice`` and the return
type ``Sequence[T]`` are compatible with ``Union[int, slice]`` and
``Union[T, Sequence[T]]``.
Overloaded function variants are still ordinary Python functions and
they still define a single runtime object. There is no automatic
dispatch happening, and you must manually handle the different types
in the implementation (usually with :func:`isinstance` checks, as
shown in the example).
The overload variants must be adjacent in the code. This makes code
clearer, as you don't have to hunt for overload variants across the
file.
Overloads in stub files are exactly the same, except there is no
implementation.
.. note::
As generic type variables are erased at runtime when constructing
instances of generic types, an overloaded function cannot have
variants that only differ in a generic type argument,
e.g. ``List[int]`` and ``List[str]``.
.. note::
If you just need to constrain a type variable to certain types or
subtypes, you can use a :ref:`value restriction
<type-variable-value-restriction>`.
.. _attrs_package:
......@@ -17,6 +134,7 @@ Type annotations can be added as follows:
.. code-block:: python
import attr
@attr.s
class A:
one: int = attr.ib() # Variable annotation (Python 3.6+)
......@@ -28,6 +146,7 @@ If you're using ``auto_attribs=True`` you must use variable annotations.
.. code-block:: python
import attr
@attr.s(auto_attribs=True)
class A:
one: int
......@@ -43,6 +162,7 @@ That enables this to work:
import attr
from typing import Dict
@attr.s(auto_attribs=True)
class A:
one: int = attr.ib(8)
......@@ -175,7 +295,7 @@ 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 the first ``dmypy check``
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
......@@ -187,7 +307,7 @@ build::
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 ``dymypy start`` or
``--use-fine-grained-cache`` option with ``dmypy start`` or
``dmypy restart``. Example::
$ dmypy start -- --use-fine-grained-cache <options...>
......@@ -231,3 +351,129 @@ at least if your codebase is hundreds of thousands of lines or more:
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
***********************
As an experimental mypy extension, you can specify ``Callable`` types
that support keyword arguments, optional arguments, and more. When
you specify the arguments of a 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 ``Callable``:
.. code-block:: python
from typing 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
``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 ``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::
This feature is experimental. Details of the implementation may
change and there may be unknown limitations. **IMPORTANT:**
Each of the functions above currently just returns its ``type``
argument, 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.
Basics
======
This chapter introduces some core concepts of mypy, including function
annotations, the ``typing`` module and library stubs. Read it carefully,
as the rest of documentation may not make much sense otherwise.
Function signatures
*******************
A function without a type annotation is considered dynamically typed:
.. code-block:: python
def greeting(name):
return 'Hello, {}'.format(name)
You can declare the signature of a function using the Python 3
annotation syntax (Python 2 is discussed later in :ref:`python2`).
This makes the function statically typed, and that causes type
checker report type errors within the function.
Here's a version of the above function that is statically typed and
will be type checked:
.. code-block:: python
def greeting(name: str) -> str:
return 'Hello, {}'.format(name)
If a function does not explicitly return a value we give the return
type as ``None``. Using a ``None`` result in a statically typed
context results in a type check error:
.. code-block:: python
def p() -> None:
print('hello')
a = p() # Type check error: p has None return value
Arguments with default values can be annotated as follows:
.. code-block:: python
def greeting(name: str, prefix: str = 'Mr.') -> str:
return 'Hello, {} {}'.format(name, prefix)
Mixing dynamic and static typing
********************************
Mixing dynamic and static typing within a single file is often
useful. For example, if you are migrating existing Python code to
static typing, it may be easiest to do this incrementally, such as by
migrating a few functions at a time. Also, when prototyping a new
feature, you may decide to first implement the relevant code using
dynamic typing and only add type signatures later, when the code is
more stable.
.. code-block:: python
def f():
1 + 'x' # No static type error (dynamically typed)
def g() -> None:
1 + 'x' # Type check error (statically typed)
.. note::
The earlier stages of mypy, known as the semantic analysis, may
report errors even for dynamically typed functions. However, you
should not rely on this, as this may change in the future.
The typing module
*****************
The ``typing`` module contains many definitions that are useful in
statically typed code. You typically use ``from ... import`` to import
them (we'll explain ``Iterable`` later in this document):
.. code-block:: python
from typing import Iterable
def greet_all(names: Iterable[str]) -> None:
for name in names:
print('Hello, {}'.format(name))
For brevity, we often omit the ``typing`` import in code examples, but
you should always include it in modules that contain statically typed
code.
The presence or absence of the ``typing`` module does not affect
whether your code is type checked; it is only required when you use
one or more special features it defines.
Type checking programs
**********************
You can type check a program by using the ``mypy`` tool, which is
basically a linter -- it checks your program for errors without actually
running it::
$ mypy program.py
All errors reported by mypy are essentially warnings that you are free
to ignore, if you so wish.
The next chapter explains how to download and install mypy:
:ref:`getting-started`.
More command line options are documented in :ref:`command-line`.
.. note::
Depending on how mypy is configured, you may have to explicitly use
the Python 3 interpreter to run mypy. The mypy tool is an ordinary
mypy (and so also Python) program. For example::
$ python3 -m mypy program.py
.. _library-stubs:
Library stubs and the Typeshed repo
***********************************
In order to type check code that uses library modules such as those
included in the Python standard library, you need to have library
*stubs*. A library stub defines a skeleton of the public interface
of the library, including classes, variables and functions and
their types, but dummy function bodies.
For example, consider this code:
.. code-block:: python
x = chr(4)
Without a library stub, the type checker would have no way of
inferring the type of ``x`` and checking that the argument to ``chr``
has a valid type. Mypy incorporates the `typeshed
<https://github.com/python/typeshed>`_ project, which contains library
stubs for the Python builtins and the standard library. The stub for
the builtins contains a definition like this for ``chr``:
.. code-block:: python
def chr(code: int) -> str: ...
In stub files we don't care about the function bodies, so we use
an ellipsis instead. That ``...`` is three literal dots!
Mypy complains if it can't find a stub (or a real module) for a
library module that you import. You can create a stub easily; here is
an overview:
* Write a stub file for the library and store it as a ``.pyi`` file in
the same directory as the library module.
* Alternatively, put your stubs (``.pyi`` files) in a directory
reserved for stubs (e.g., ``myproject/stubs``). In this case you
have to set the environment variable ``MYPYPATH`` to refer to the
directory. For example::
$ export MYPYPATH=~/work/myproject/stubs
Use the normal Python file name conventions for modules, e.g. ``csv.pyi``
for module ``csv``. Use a subdirectory with ``__init__.pyi`` for packages.
If a directory contains both a ``.py`` and a ``.pyi`` file for the
same module, the ``.pyi`` file takes precedence. This way you can
easily add annotations for a module even if you don't want to modify
the source code. This can be useful, for example, if you use 3rd party
open source libraries in your program (and there are no stubs in
typeshed yet).
That's it! Now you can access the module in mypy programs and type check
code that uses the library. If you write a stub for a library module,
consider making it available for other programmers that use mypy
by contributing it back to the typeshed repo.
There is more information about creating stubs in the
`mypy wiki <https://github.com/python/mypy/wiki/Creating-Stubs-For-Python-Modules>`_.
The following sections explain the kinds of type annotations you can use
in your programs and stub files.
.. note::
You may be tempted to point ``MYPYPATH`` to the standard library or
to the ``site-packages`` directory where your 3rd party packages
are installed. This is almost always a bad idea -- you will likely
get tons of error messages about code you didn't write and that
mypy can't analyze all that well yet, and in the worst case
scenario mypy may crash due to some construct in a 3rd party
package that it didn't expect.
......@@ -3,13 +3,13 @@ Built-in types
These are examples of some of the most common built-in types:
=================== ===============================
====================== ===============================
Type Description
=================== ===============================
``int`` integer of arbitrary size
====================== ===============================
``int`` integer
``float`` floating point number
``bool`` boolean value
``str`` unicode string
``str`` string (unicode)
``bytes`` 8-bit string
``object`` an arbitrary object (``object`` is the common base class)
``List[str]`` list of ``str`` objects
......@@ -17,11 +17,12 @@ Type Description
``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
``Sequence[bool]`` sequence of booleans (read-only)
``Mapping[str, int]`` mapping from ``str`` keys to ``int`` values (read-only)
``Any`` dynamically typed value with an arbitrary type
=================== ===============================
====================== ===============================
The type ``Any`` and type constructors ``List``, ``Dict``,
The type ``Any`` and type constructors such as ``List``, ``Dict``,
``Iterable`` and ``Sequence`` are defined in the ``typing`` module.
The type ``Dict`` is a *generic* class, signified by type arguments within
......@@ -30,7 +31,7 @@ strings and and ``Dict[Any, Any]`` is a dictionary of dynamically typed
(arbitrary) values and keys. ``List`` is another generic class. ``Dict`` and
``List`` are aliases for the built-ins ``dict`` and ``list``, respectively.
``Iterable`` and ``Sequence`` are generic abstract base classes that
``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. Note that even though
......
.. _casts:
Casts
=====
Casts and type assertions
=========================
Mypy supports type casts that are usually used to coerce a statically
typed value to a subtype. Unlike languages such as Java or C#,
......@@ -13,17 +13,27 @@ cast:
from typing import cast, List
o = [1] # type: object
o: object = [1]
x = cast(List[int], o) # OK
y = cast(List[str], o) # OK (cast performs no actual runtime check)
To support runtime checking of casts such as the above, we'd have to check
the types of all list items, which would be very inefficient for large lists.
Use assertions if you want to
perform an actual runtime check. Casts are used to silence spurious
Casts are used to silence spurious
type checker warnings and give the type checker a little help when it can't
quite understand what is going on.
.. note::
You can use an assertion if you want to perform an actual runtime check:
.. code-block:: python
def foo(o: object) -> None:
print(o + 5) # Error: can't add 'object' and 'int'
assert isinstance(o, int)
print(o + 5) # OK: type of 'o' is 'int' here
You don't need a cast for expressions with type ``Any``, or when
assigning to a variable with type ``Any``, as was explained earlier.
You can also use ``Any`` as the cast target type -- this lets you perform
......@@ -34,6 +44,6 @@ any operations on the result. For example:
from typing import cast, Any
x = 1
x + 'x' # Type check error
x.whatever() # Type check error
y = cast(Any, x)
y + 'x' # Type check OK (runtime error)
y.whatever() # Type check OK (runtime error)
.. _cheat-sheet-py2:
Mypy syntax cheat sheet (Python 2)
==================================
Type hints cheat sheet (Python 2)
=================================
This document is a quick cheat sheet showing how the `PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_ type
This document is a quick cheat sheet showing how the
`PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_ type
language represents various common types in Python 2.
.. note::
......@@ -21,7 +22,7 @@ Built-in types
from typing import List, Set, Dict, Tuple, Text, Optional
# For simple built-in types, just use the name of the type.
# For simple built-in types, just use the name of the type
x = 1 # type: int
x = 1.0 # type: float
x = True # type: bool
......@@ -29,27 +30,24 @@ Built-in types
x = u"test" # type: unicode
# For collections, the name of the type is capitalized, and the
# name of the type inside the collection is in brackets.
# name of the type inside the collection is in brackets
x = [1] # type: List[int]
x = set([6, 7]) # type: Set[int]
x = {6, 7} # type: Set[int]
# Empty Tuple types are a bit special
x = () # type: Tuple[()]
# For mappings, we need the types of both keys and values
x = {'field': 2.0} # type: Dict[str, float]
# For mappings, we need the types of both keys and values.
x = dict(field=2.0) # type: Dict[str, float]
# For tuples, we specify the types of all the elements.
# For tuples, we specify the types of all the elements
x = (3, "yes", 7.5) # type: Tuple[int, str, float]
# For textual data, use Text.
# This is `unicode` in Python 2 and `str` in Python 3.
x = ["string", u"unicode"] # type: List[Text]
# For textual data, use Text
# ("Text" means "unicode" in Python 2 and "str" in Python 3)
x = [u"one", u"two"] # type: List[Text]
# Use Optional for values that could be None.
input_str = f() # type: Optional[str]
if input_str is not None:
print input_str
# Use Optional[] for values that could be None
x = some_function() # type: Optional[str]
if x is not None:
print x
Functions
......@@ -57,9 +55,9 @@ Functions
.. code-block:: python
from typing import Callable, Iterable
from typing import Callable, Iterable, Union, Optional, List
# This is how you annotate a function definition.
# This is how you annotate a function definition
def stringify(num):
# type: (int) -> str
"""Your function docstring goes here after the type definition."""
......@@ -70,29 +68,31 @@ Functions
def greet_world(): # type: () -> None
print "Hello, world!"
# And here's how you specify multiple arguments.
# And here's how you specify multiple arguments
def plus(num1, num2):
# type: (int, int) -> int
return num1 + num2
# Add type annotations for kwargs as though they were positional args.
# Add type annotations for arguments with default values as though they
# had no defaults
def f(num1, my_float=3.5):
# type: (int, float) -> float
return num1 + my_float
# An argument can be declared positional-only by giving it a name
# starting with two underscores:
# starting with two underscores
def quux(__x):
# type: (int) -> None
pass
quux(3) # Fine
quux(__x=3) # Error
# This is how you annotate a function value.
# This is how you annotate a callable (function) value
x = f # type: Callable[[int, float], float]
# A generator function that yields ints is secretly just a function that
# returns an iterable (see below) of ints, so that's how we annotate it.
# returns an iterable (see below) of ints, so that's how we annotate it
def f(n):
# type: (int) -> Iterable[int]
i = 0
......@@ -100,7 +100,7 @@ Functions
yield i
i += 1
# There's alternative syntax for functions with many arguments.
# There's an alternative syntax for functions with many arguments
def send_email(address, # type: Union[str, List[str]]
sender, # type: str
cc, # type: Optional[List[str]]
......@@ -117,59 +117,63 @@ When you're puzzled or when things are complicated
.. code-block:: python
from typing import Union, Any, cast
from typing import Union, Any, List, Optional, 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
# 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) # -> error: Revealed type is 'builtins.int'
reveal_type(1) # -> Revealed type is 'builtins.int'
# Use Union when something could be one of a few types.
# Use Union when something could be one of a few types
x = [3, 5, "test", "fun"] # type: List[Union[int, str]]
# Use Any if you don't know the type of something or it's too
# dynamic to write a type for.
# dynamic to write a type for
x = mystery_function() # type: Any
# This is how to deal with varargs.
# This makes each positional arg and each keyword arg a 'str'.
# If you initialize a variable with an empty container or "None"
# you may have to help mypy a bit by providing a type annotation
x = [] # type: List[str]
x = None # type: Optional[str]
# This makes each positional arg and each keyword arg a "str"
def call(self, *args, **kwargs):
# type: (*str, **str) -> str
request = make_request(*args, **kwargs)
return self.do_api_query(request)
# Use `ignore` to suppress type-checking on a given line, when your
# code confuses mypy or runs into an outright bug in mypy.
# Good practice is to comment every `ignore` with a bug link
# 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 comment every "ignore" with a bug link
# (in mypy, typeshed, or your own code) or an explanation of the issue.
x = confusing_function() # type: ignore # https://github.com/python/mypy/issues/1167
# cast is a helper function for mypy that allows for guidance of how to convert types.
# it does not cast at runtime
# "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 (no runtime check)
reveal_type(c) # -> error: Revealed type is 'builtins.list[builtins.str]'
print(c) # -> [4] the object is not cast
# if you want dynamic attributes on your class, have it override __setattr__ or __getattr__
# in a stub or in your source code.
# __setattr__ allows for dynamic assignment to names
# __getattr__ allows for dynamic access to names
b = cast(List[int], a) # Passes fine
c = cast(List[str], a) # Passes fine (no runtime check)
reveal_type(c) # -> Revealed type is 'builtins.list[builtins.str]'
print c # -> [4]; the object is not cast
# If you want dynamic attributes on your class, have it override "__setattr__"
# or "__getattr__" in a stub or in your source code.
#
# "__setattr__" allows for dynamic assignment to names
# "__getattr__" allows for dynamic access to names
class A:
# this will allow assignment to any A.x, if x is the same type as `value`
# 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, value):
# type: (str, int) -> None
...
a.foo = 42 # works
a.bar = 'Ex-parrot' # fails type checking
# TODO: explain "Need type annotation for variable" when
# initializing with None or an empty container
a.foo = 42 # Works
a.bar = 'Ex-parrot' # Fails type checking
Standard duck types
*******************
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
......@@ -181,23 +185,28 @@ that are common in idiomatic Python are standardized.
from typing import Mapping, MutableMapping, Sequence, Iterable
# Use Iterable for generic iterables (anything usable in `for`),
# and Sequence where a sequence (supporting `len` and `__getitem__`) is required.
# Use Iterable for generic iterables (anything usable in "for"),
# and Sequence where a sequence (supporting "len" and "__getitem__") is
# required
def f(iterable_of_ints):
# type: (Iterable[int]) -> List[str]
return [str(x) for x in iterator_of_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.
# Mapping describes a dict-like object (with "__getitem__") that we won't
# mutate, and MutableMapping one (with "__setitem__") that we might
def f(my_dict):
# type: (Mapping[int, str]) -> List[int]
return list(my_dict.keys())
f({3: 'yes', 4: 'no'})
def f(my_mapping):
# type: (MutableMapping[int, str]) -> Set[str]
my_dict[5] = 'maybe'
return set(my_dict.values())
f({3: 'yes', 4: 'no'})
......@@ -207,43 +216,36 @@ Classes
.. code-block:: python
class MyClass(object):
# For instance methods, omit `self`.
# For instance methods, omit type for "self"
def my_method(self, num, str1):
# type: (int, str) -> str
return num * str1
# The __init__ method doesn't return anything, so it gets return
# type None just like any other method that doesn't return anything.
# 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):
# type: () -> None
pass
# User-defined classes are written with just their own names.
# User-defined classes are valid as types in annotations
x = MyClass() # type: MyClass
Other stuff
***********
Miscellaneous
*************
.. code-block:: python
import sys
# typing.Match describes regex matches from the re module.
import re
from typing import Match, AnyStr, IO
x = re.match(r'[0-9]+', "15") # type: Match[str]
# Use AnyStr for functions that should accept any kind of string
# without allowing different kinds of strings to mix.
def concat(a, b):
# type: (AnyStr, AnyStr) -> AnyStr
return a + b
concat(u"foo", u"bar") # type: unicode
concat(b"foo", b"bar") # type: bytes
# "typing.Match" describes regex matches from the re module
x = re.match(r'[0-9]+', "15") # type: Match[str]
# Use IO[] for functions that should accept or return any
# object that comes from an open() call. The IO[] does not
# distinguish between reading, writing or other modes.
# object that comes from an open() call (IO[] does not
# distinguish between reading, writing or other modes)
def get_sys_IO(mode='w'):
# type: (str) -> IO[str]
if mode == 'w':
......@@ -252,6 +254,3 @@ Other stuff
return sys.stdin
else:
return sys.stdout
# TODO: add TypeVar and a simple generic function
.. _cheat-sheet-py3:
Mypy syntax cheat sheet (Python 3)
==================================
Type hints cheat sheet (Python 3)
=================================
This document is a quick cheat sheet showing how the `PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_ type
language represents various common types in Python 3. Unless otherwise noted, the syntax is valid on all versions of Python 3.
This document is a quick cheat sheet showing how the
`PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_ type
annotation notation represents various common types in Python 3.
.. note::
......@@ -14,6 +15,33 @@ language represents various common types in Python 3. Unless otherwise noted, th
annotation, and show the inferred types.
Variables
*********
Python 3.6 introduced a syntax for annotating variables in
`PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_ and
we use it in most examples.
.. code-block:: python
# This is how you declare the type of a variable type in Python 3.6
x: int = 1
# In Python 3.5 and earlier you can use a type comment instead
# (equivalent to the previous definition)
x = 1 # type: int
# You don't need to initialize a variable to annotate it
a: int # Ok (no value at runtime until assigned)
# The latter is useful in conditional branches
child: bool
if age < 18:
child = True
else:
child = False
Built-in types
**************
......@@ -21,188 +49,151 @@ Built-in types
from typing import List, Set, Dict, Tuple, Text, Optional, AnyStr
# For simple built-in types, just use the name of the type.
x = 1 # type: int
x = 1.0 # type: float
x = True # type: bool
x = "test" # type: str
x = u"test" # type: str
x = b"test" # type: bytes
# For simple built-in types, just use the name of the type
x: int = 1
x: float = 1.0
x: bool = True
x: str = "test"
x: str = u"test"
x: bytes = b"test"
# For collections, the name of the type is capitalized, and the
# name of the type inside the collection is in brackets.
x = [1] # type: List[int]
x = {6, 7} # type: Set[int]
# Empty Tuple types are a bit special
x = () # type: Tuple[()]
# name of the type inside the collection is in brackets
x: List[int] = [1]
x: Set[int] = {6, 7}
# For mappings, we need the types of both keys and values.
x = {'field': 2.0} # type: Dict[str, float]
# For tuples, we specify the types of all the elements.
x = (3, "yes", 7.5) # type: Tuple[int, str, float]
# Same as above, but with type comment syntax
x = [1] # type: List[int]
# For textual data, use Text.
# This is `unicode` in Python 2 and `str` in Python 3.
x = ["string", u"unicode"] # type: List[Text]
# For mappings, we need the types of both keys and values
x: Dict[str, float] = {'field': 2.0}
# For tuples, we specify the types of all the elements
x: Tuple[int, str, float] = (3, "yes", 7.5)
# For textual data, use Text if you care about Python 2 compatibility
# ("Text" means "unicode" in Python 2 and "str" in Python 3)
x: List[Text] = ["string", u"unicode"]
# Use Optional for values that could be None.
input_str = f() # type: Optional[str]
if input_str is not None:
print(input_str)
# Use Optional[] for values that could be None
x: Optional[str] = some_function()
if x is not None:
print(x)
Functions
*********
Python 3 introduces an annotation syntax for function declarations in `PEP 3107 <https://www.python.org/dev/peps/pep-3107/>`_.
Python 3 supports an annotation syntax for function declarations.
.. code-block:: python
from typing import Callable, Iterable, Union, Optional, List
# This is how you annotate a function definition.
# This is how you annotate a function definition
def stringify(num: int) -> str:
return str(num)
# And here's how you specify multiple arguments.
# And here's how you specify multiple arguments
def plus(num1: int, num2: int) -> int:
return num1 + num2
# Add type annotations for kwargs as though they were positional args.
# Add default value for an argument after the type annotation
def f(num1: int, my_float: float = 3.5) -> float:
return num1 + my_float
# An argument can be declared positional-only by giving it a name
# starting with two underscores:
def quux(__x: int) -> None:
pass
quux(3) # Fine
quux(__x=3) # Error
# This is how you annotate a function value.
x = f # type: Callable[[int, float], float]
# This is how you annotate a callable (function) value
x: Callable[[int, float], float] = f
# A generator function that yields ints is secretly just a function that
# returns an iterable (see below) of ints, so that's how we annotate it.
# returns an iterable (see below) of ints, so that's how we annotate it
def f(n: int) -> Iterable[int]:
i = 0
while i < n:
yield i
i += 1
# For a function with many arguments, you can of course split it over multiple lines
# You can of course split a function annotation over multiple lines
def send_email(address: Union[str, List[str]],
sender: str,
cc: Optional[List[str]],
bcc: Optional[List[str]],
subject='',
body: List[str] = None
body: Optional[List[str]] = None
) -> bool:
...
Coroutines and asyncio
**********************
See :ref:`async-and-await` for the full detail on typing coroutines and asynchronous code.
.. code-block:: python
import asyncio
from typing import Generator, Any
# A generator-based coroutine created with @asyncio.coroutine should have a
# return type of Generator[Any, None, T], where T is the type it returns.
@asyncio.coroutine
def countdown34(tag: str, count: int) -> Generator[Any, None, str]:
while count > 0:
print('T-minus {} ({})'.format(count, tag))
yield from asyncio.sleep(0.1)
count -= 1
return "Blastoff!"
# mypy currently does not support converting functions into generator-based
# coroutines in Python 3.4, so you need to add a 'yield' to make it
# typecheck.
@asyncio.coroutine
def async1(obj: object) -> Generator[None, None, str]:
if False:
yield
return "placeholder"
# An argument can be declared positional-only by giving it a name
# starting with two underscores:
def quux(__x: int) -> None:
pass
# A Python 3.5+ coroutine is typed like a normal function.
async def countdown35(tag: str, count: int) -> str:
while count > 0:
print('T-minus {} ({})'.format(count, tag))
await asyncio.sleep(0.1)
count -= 1
return "Blastoff!"
quux(3) # Fine
quux(__x=3) # Error
async def async2(obj: object) -> str:
return "placeholder"
When you're puzzled or when things are complicated
**************************************************
.. code-block:: python
from typing import Union, Any, List, cast
from typing import Union, Any, List, Optional, 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
# 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) # -> error: Revealed type is 'builtins.int'
reveal_type(1) # -> Revealed type is 'builtins.int'
# Use Union when something could be one of a few types.
x = [3, 5, "test", "fun"] # type: List[Union[int, str]]
# Use Union when something could be one of a few types
x: List[Union[int, str]] = [3, 5, "test", "fun"]
# Use Any if you don't know the type of something or it's too
# dynamic to write a type for.
x = mystery_function() # type: Any
# dynamic to write a type for
x: Any = mystery_function()
# This is how to deal with varargs.
# This makes each positional arg and each keyword arg a 'str'.
# If you initialize a variable with an empty container or "None"
# you may have to help mypy a bit by providing a type annotation
x: List[str] = []
x: Optional[str] = None
# This makes each positional arg and each keyword arg a "str"
def call(self, *args: str, **kwargs: str) -> str:
request = make_request(*args, **kwargs)
return self.do_api_query(request)
# Use `ignore` to suppress type-checking on a given line, when your
# code confuses mypy or runs into an outright bug in mypy.
# Good practice is to comment every `ignore` with a bug link
# 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 comment every "ignore" with a bug link
# (in mypy, typeshed, or your own code) or an explanation of the issue.
x = confusing_function() # type: ignore # https://github.com/python/mypy/issues/1167
# cast is a helper function for mypy that allows for guidance of how to convert types.
# it does not cast at runtime
# "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 (no runtime check)
reveal_type(c) # -> error: Revealed type is 'builtins.list[builtins.str]'
print(c) # -> [4] the object is not cast
# if you want dynamic attributes on your class, have it override __setattr__ or __getattr__
# in a stub or in your source code.
# __setattr__ allows for dynamic assignment to names
# __getattr__ allows for dynamic access to names
b = cast(List[int], a) # Passes fine
c = cast(List[str], a) # Passes fine (no runtime check)
reveal_type(c) # -> Revealed type is 'builtins.list[builtins.str]'
print(c) # -> [4]; the object is not cast
# If you want dynamic attributes on your class, have it override "__setattr__"
# or "__getattr__" in a stub or in your source code.
#
# "__setattr__" allows for dynamic assignment to names
# "__getattr__" allows for dynamic access to names
class A:
# this will allow assignment to any A.x, if x is the same type as `value`
# 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: ...
# this will allow access to any A.x, if x is compatible with the return type
def __getattr__(self, name: str) -> int: ...
a.foo = 42 # works
a.bar = 'Ex-parrot' # fails type checking
# This will allow access to any A.x, if x is compatible with the return type
def __getattr__(self, name: str) -> int: ...
# TODO: explain "Need type annotation for variable" when
# initializing with None or an empty container
a.foo = 42 # Works
a.bar = 'Ex-parrot' # Fails type checking
Standard duck types
*******************
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
......@@ -214,20 +205,25 @@ that are common in idiomatic Python are standardized.
from typing import Mapping, MutableMapping, Sequence, Iterable, List, Set
# Use Iterable for generic iterables (anything usable in `for`),
# and Sequence where a sequence (supporting `len` and `__getitem__`) is required.
def f(iterable_of_ints: Iterable[int]) -> List[str]:
return [str(x) for x in iterable_of_ints]
# 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.
# Mapping describes a dict-like object (with "__getitem__") that we won't
# mutate, and MutableMapping one (with "__setitem__") that we might
def f(my_dict: Mapping[int, str]) -> List[int]:
return list(my_dict.keys())
f({3: 'yes', 4: 'no'})
def f(my_mapping: MutableMapping[int, str]) -> Set[str]:
my_mapping[5] = 'maybe'
return set(my_mapping.values())
f({3: 'yes', 4: 'no'})
......@@ -237,43 +233,69 @@ Classes
.. code-block:: python
class MyClass:
# The __init__ method doesn't return anything, so it gets return
# type None just like any other method that doesn't return anything.
# You can optionally declare instance variables in the class body
attr: int
# This is an instance variable with a default value
charge_percent: int = 100
# 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) -> None:
...
# For instance methods, omit `self`.
# For instance methods, omit type for "self"
def my_method(self, num: int, str1: str) -> str:
return num * str1
# User-defined classes are valid as types in annotations
x: MyClass = MyClass()
# You can use the ClassVar annotation to declare a class variable
class Car:
seats: ClassVar[int] = 4
passengers: ClassVar[List[str]]
# You can also declare the type of an attribute in "__init__"
class Box:
def __init__(self) -> None:
self.items: List[str] = []
Coroutines and asyncio
**********************
See :ref:`async-and-await` for the full detail on typing coroutines and asynchronous code.
# User-defined classes are written with just their own names.
x = MyClass() # type: MyClass
.. code-block:: python
import asyncio
from typing import Generator, Any
# A coroutine is typed like a normal function
async def countdown35(tag: str, count: int) -> str:
while count > 0:
print('T-minus {} ({})'.format(count, tag))
await asyncio.sleep(0.1)
count -= 1
return "Blastoff!"
Other stuff
***********
Miscellaneous
*************
.. code-block:: python
import sys
import re
# typing.Match describes regex matches from the re module.
from typing import Match, AnyStr, IO
x = re.match(r'[0-9]+', "15") # type: Match[str]
# You can use AnyStr to indicate that any string type will work
# but not to mix types
def full_name(first: AnyStr, last: AnyStr) -> AnyStr:
return first+last
full_name('Jon','Doe') # same str ok
full_name(b'Bill', b'Bit') # same binary ok
full_name(b'Terry', 'Trouble') # different str types, fails
# "typing.Match" describes regex matches from the re module
x: Match[str] = re.match(r'[0-9]+', "15")
# Use IO[] for functions that should accept or return any
# object that comes from an open() call. The IO[] does not
# distinguish between reading, writing or other modes.
def get_sys_IO(mode='w') -> IO[str]:
# object that comes from an open() call (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':
......@@ -281,69 +303,15 @@ Other stuff
else:
return sys.stdout
# forward references are useful if you want to reference a class before it is designed
def f(foo: A) -> int: # this will fail
# Forward references are useful if you want to reference a class before
# it is defined
def f(foo: A) -> int: # This will fail
...
class A:
...
# however, using the string 'A', it will pass as long as there is a class of that name later on
def f(foo: 'A') -> int:
# If you use the string literal 'A', it will pass as long as there is a
# class of that name later on in the file
def f(foo: 'A') -> int: # Ok
...
# TODO: add TypeVar and a simple generic function
Variable Annotation in Python 3.6 with PEP 526
**********************************************
Python 3.6 brings new syntax for annotating variables with `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_.
Mypy brings limited support for PEP 526 annotations.
.. code-block:: python
# annotation is similar to arguments to functions
name: str = "Eric Idle"
# class instances can be annotated as follows
mc : MyClass = MyClass()
# tuple packing can be done as follows
tu: Tuple[str, ...] = ('a', 'b', 'c')
# annotations are not checked at runtime
year: int = '1972' # error in type checking, but works at runtime
# these are all equivalent
hour = 24 # type: int
hour: int; hour = 24
hour: int = 24
# you do not (!) need to initialize a variable to annotate it
a: int # ok for type checking and runtime
# which is useful in conditional branches
child: bool
if age < 18:
child = True
else:
child = False
# annotations for classes are for instance variables (those created in __init__ or __new__)
class Battery:
charge_percent: int = 100 # this is an instance variable with a default value
capacity: int # an instance variable without a default
# you can use the ClassVar annotation to make the variable a class variable instead of an instance variable.
class Car:
seats: ClassVar[int] = 4
passengers: ClassVar[List[str]]
# You can also declare the type of an attribute in __init__
class Box:
def __init__(self) -> None:
self.items: List[str] = []
Please see :ref:`python-36` for more on mypy's compatibility with Python 3.6's new features.
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
*****************************
......@@ -13,29 +17,42 @@ initialized within the class. Mypy infers the types of attributes:
class A:
def __init__(self, x: int) -> None:
self.x = x # Attribute x of type int
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
a.x = 2 # OK!
a.y = 3 # Error: 'A' has no attribute 'y'
This is a bit like each class having an implicitly defined
``__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 comment:
a type annotation:
.. code-block:: python
class A:
x = None # type: List[int] # Declare attribute x of type List[int]
x: List[int] # Declare attribute 'x' of type List[int]
a = A()
a.x = [1] # OK
As in Python, a variable defined in the class body can used as a class
or an instance variable.
As in Python generally, a variable defined in the class body can used
as a class or an instance variable.
Type comments work as well, if you need to support Python versions earlier
than 3.6:
.. code-block:: python
class A:
x = None # type: List[int] # Declare attribute 'x' of type List[int]
Note that attribute definitions in the class body that use a type comment
are special: a ``None`` value is valid as the initializer, even though
the declared type is not optional. This should be used sparingly, as this can
result in ``None``-related runtime errors that mypy can't detect.
Similarly, you can give explicit types to instance variables defined
in a method:
......@@ -44,10 +61,10 @@ in a method:
class A:
def __init__(self) -> None:
self.x = [] # type: List[int]
self.x: List[int] = []
def f(self) -> None:
self.y = 0 # type: Any
self.y: Any = 0
You can only define an instance variable within a method if you assign
to it explicitly using ``self``:
......@@ -56,9 +73,9 @@ to it explicitly using ``self``:
class A:
def __init__(self) -> None:
self.y = 1 # Define y
self.y = 1 # Define 'y'
a = self
a.x = 1 # Error: x not defined
a.x = 1 # Error: 'x' not defined
Overriding statically typed methods
***********************************
......@@ -73,7 +90,7 @@ override has a compatible signature:
...
class B(A):
def f(self, x: str) -> None: # Error: type of x incompatible
def f(self, x: str) -> None: # Error: type of 'x' incompatible
...
class C(A):
......@@ -88,16 +105,18 @@ override has a compatible signature:
You can also vary return types **covariantly** in overriding. For
example, you could override the return type ``object`` with a subtype
such as ``int``.
such as ``int``. Similarly, you can vary argument types
**contravariantly** -- subclasses can have more general argument types.
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.
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:
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
......@@ -107,12 +126,7 @@ annotations have no effect at runtime:
class B(A):
def inc(self, x): # Override, dynamically typed
return 'hello'
b = B()
print(b.inc(1)) # hello
a = b # type: A
print(a.inc(1)) # hello
return 'hello' # Incompatible with 'A', but no mypy error
Abstract base classes and multiple inheritance
**********************************************
......@@ -139,7 +153,7 @@ by a subclass. You can define abstract base classes using the
def bar(self) -> str:
return 'x'
a = A() # Error: A is abstract
a = A() # Error: 'A' is abstract
b = B() # OK
Note that mypy performs checking for unimplemented abstract methods
......@@ -153,414 +167,3 @@ 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.
.. _protocol-types:
Protocols and structural subtyping
**********************************
Mypy supports two ways of deciding whether two classes are compatible
as types: nominal subtyping and structural subtyping. *Nominal*
subtyping is strictly based on the class hierarchy. If class ``D``
inherits class ``C``, it's also a subtype of ``C``, and instances of
``D`` can be used when ``C`` instances are expected. This form of
subtyping is used by default in mypy, since it's easy to understand
and produces clear and concise error messages, and since it matches
how the native ``isinstance()`` check works -- based on class
hierarchy. *Structural* subtyping can also be useful. Class ``D`` is
a structural subtype of class ``C`` if the former has all attributes
and methods of the latter, and with compatible types.
Structural subtyping can be seen as a static equivalent of duck
typing, which is well known to Python programmers. Mypy provides
support for structural subtyping via protocol classes described
below. See `PEP 544 <https://www.python.org/dev/peps/pep-0544/>`_ for
the detailed specification of protocols and structural subtyping in
Python.
.. _predefined_protocols:
Predefined protocols
********************
The ``typing`` module defines various protocol classes that correspond
to common Python protocols, such as ``Iterable[T]``. If a class
defines a suitable ``__iter__`` method, mypy understands that it
implements the iterable protocol and is compatible with ``Iterable[T]``.
For example, ``IntList`` below is iterable, over ``int`` values:
.. code-block:: python
from typing import Iterator, Iterable, Optional
class IntList:
def __init__(self, value: int, next: Optional[IntList]) -> None:
self.value = value
self.next = next
def __iter__(self) -> Iterator[int]:
current = self
while current:
yield current.value
current = current.next
def print_numbered(items: Iterable[int]) -> None:
for n, x in enumerate(items):
print(n + 1, x)
x = IntList(3, IntList(5, None))
print_numbered(x) # OK
print_numbered([4, 5]) # Also OK
The subsections below introduce all built-in protocols defined in
``typing`` and the signatures of the corresponding methods you need to define
to implement each protocol (the signatures can be left out, as always, but mypy
won't type check unannotated methods).
Iteration protocols
...................
The iteration protocols are useful in many contexts. For example, they allow
iteration of objects in for loops.
``Iterable[T]``
---------------
The :ref:`example above <predefined_protocols>` has a simple implementation of an
``__iter__`` method.
.. code-block:: python
def __iter__(self) -> Iterator[T]
``Iterator[T]``
---------------
.. code-block:: python
def __next__(self) -> T
def __iter__(self) -> Iterator[T]
Collection protocols
....................
Many of these are implemented by built-in container types such as
``list`` and ``dict``, and these are also useful for user-defined
collection objects.
``Sized``
---------
This is a type for objects that support ``len(x)``.
.. code-block:: python
def __len__(self) -> int
``Container[T]``
----------------
This is a type for objects that support the ``in`` operator.
.. code-block:: python
def __contains__(self, x: object) -> bool
``Collection[T]``
-----------------
.. code-block:: python
def __len__(self) -> int
def __iter__(self) -> Iterator[T]
def __contains__(self, x: object) -> bool
One-off protocols
.................
These protocols are typically only useful with a single standard
library function or class.
``Reversible[T]``
-----------------
This is a type for objects that support ``reversed(x)``.
.. code-block:: python
def __reversed__(self) -> Iterator[T]
``SupportsAbs[T]``
------------------
This is a type for objects that support ``abs(x)``. ``T`` is the type of
value returned by ``abs(x)``.
.. code-block:: python
def __abs__(self) -> T
``SupportsBytes``
-----------------
This is a type for objects that support ``bytes(x)``.
.. code-block:: python
def __bytes__(self) -> bytes
.. _supports-int-etc:
``SupportsComplex``
-------------------
This is a type for objects that support ``complex(x)``. Note that no arithmetic operations
are supported.
.. code-block:: python
def __complex__(self) -> complex
``SupportsFloat``
-----------------
This is a type for objects that support ``float(x)``. Note that no arithmetic operations
are supported.
.. code-block:: python
def __float__(self) -> float
``SupportsInt``
---------------
This is a type for objects that support ``int(x)``. Note that no arithmetic operations
are supported.
.. code-block:: python
def __int__(self) -> int
``SupportsRound[T]``
--------------------
This is a type for objects that support ``round(x)``.
.. code-block:: python
def __round__(self) -> T
Async protocols
...............
These protocols can be useful in async code.
``Awaitable[T]``
----------------
.. code-block:: python
def __await__(self) -> Generator[Any, None, T]
``AsyncIterable[T]``
--------------------
.. code-block:: python
def __aiter__(self) -> AsyncIterator[T]
``AsyncIterator[T]``
--------------------
.. code-block:: python
def __anext__(self) -> Awaitable[T]
def __aiter__(self) -> AsyncIterator[T]
Context manager protocols
.........................
There are two protocols for context managers -- one for regular context
managers and one for async ones. These allow defining objects that can
be used in ``with`` and ``async with`` statements.
``ContextManager[T]``
---------------------
.. code-block:: python
def __enter__(self) -> T
def __exit__(self,
exc_type: Optional[Type[BaseException]],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType]) -> Optional[bool]
``AsyncContextManager[T]``
--------------------------
.. code-block:: python
def __aenter__(self) -> Awaitable[T]
def __aexit__(self,
exc_type: Optional[Type[BaseException]],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType]) -> Awaitable[Optional[bool]]
Simple user-defined protocols
*****************************
You can define your own protocol class by inheriting the special
``typing_extensions.Protocol`` class:
.. code-block:: python
from typing import Iterable
from typing_extensions import Protocol
class SupportsClose(Protocol):
def close(self) -> None:
... # Explicit '...'
class Resource: # No SupportsClose base class!
# ... some methods ...
def close(self) -> None:
self.resource.release()
def close_all(items: Iterable[SupportsClose]) -> None:
for item in items:
item.close()
close_all([Resource(), open('some/file')]) # Okay!
``Resource`` is a subtype of the ``SupportClose`` protocol since it defines
a compatible ``close`` method. Regular file objects returned by ``open()`` are
similarly compatible with the protocol, as they support ``close()``.
.. note::
The ``Protocol`` base class is currently provided in the ``typing_extensions``
package. Once structural subtyping is mature and
`PEP 544 <https://www.python.org/dev/peps/pep-0544/>`_ has been accepted,
``Protocol`` will be included in the ``typing`` module.
Defining subprotocols and subclassing protocols
***********************************************
You can also define subprotocols. Existing protocols can be extended
and merged using multiple inheritance. Example:
.. code-block:: python
# ... continuing from the previous example
class SupportsRead(Protocol):
def read(self, amount: int) -> bytes: ...
class TaggedReadableResource(SupportsClose, SupportsRead, Protocol):
label: str
class AdvancedResource(Resource):
def __init__(self, label: str) -> None:
self.label = label
def read(self, amount: int) -> bytes:
# some implementation
...
resource: TaggedReadableResource
resource = AdvancedResource('handle with care') # OK
Note that inheriting from an existing protocol does not automatically
turn the subclass into a protocol -- it just creates a regular
(non-protocol) class or ABC that implements the given protocol (or
protocols). The ``typing_extensions.Protocol`` base class must always
be explicitly present if you are defining a protocol:
.. code-block:: python
class NewProtocol(SupportsClose): # This is NOT a protocol
new_attr: int
class Concrete:
new_attr: int = 0
def close(self) -> None:
...
# Error: nominal subtyping used by default
x: NewProtocol = Concrete() # Error!
You can also include default implementations of methods in
protocols. If you explicitly subclass these protocols you can inherit
these default implementations. Explicitly including a protocol as a
base class is also a way of documenting that your class implements a
particular protocol, and it forces mypy to verify that your class
implementation is actually compatible with the protocol.
.. note::
You can use Python 3.6 variable annotations (`PEP 526
<https://www.python.org/dev/peps/pep-0526/>`_)
to declare protocol attributes. On Python 2.7 and earlier Python 3
versions you can use type comments and properties.
Recursive protocols
*******************
Protocols can be recursive (self-referential) and mutually
recursive. This is useful for declaring abstract recursive collections
such as trees and linked lists:
.. code-block:: python
from typing import TypeVar, Optional
from typing_extensions import Protocol
class TreeLike(Protocol):
value: int
@property
def left(self) -> Optional['TreeLike']: ...
@property
def right(self) -> Optional['TreeLike']: ...
class SimpleTree:
def __init__(self, value: int) -> None:
self.value = value
self.left: Optional['SimpleTree'] = None
self.right: Optional['SimpleTree'] = None
root = SimpleTree(0) # type: TreeLike # OK
Using ``isinstance()`` with protocols
*************************************
You can use a protocol class with ``isinstance()`` if you decorate it
with the ``typing_extensions.runtime`` class decorator. The decorator
adds support for basic runtime structural checks:
.. code-block:: python
from typing_extensions import Protocol, runtime
@runtime
class Portable(Protocol):
handles: int
class Mug:
def __init__(self) -> None:
self.handles = 1
mug = Mug()
if isinstance(mug, Portable):
use(mug.handles) # Works statically and at runtime
``isinstance()`` also works with the :ref:`predefined protocols <predefined_protocols>`
in ``typing`` such as ``Iterable``.
.. note::
``isinstance()`` with protocols is not completely safe at runtime.
For example, signatures of methods are not checked. The runtime
implementation only checks that all protocol members are defined.
......@@ -393,7 +393,7 @@ Here are some more useful flags:
Otherwise, use ``--python-executable``.
- ``--platform PLATFORM`` will make mypy typecheck your code as if it were
run under the the given operating system. Without this option, mypy will
run under the given operating system. Without this option, mypy will
default to using whatever operating system you are currently using. See
:ref:`version_and_platform_checks` for more about this feature.
......@@ -463,12 +463,20 @@ Here are some more useful flags:
.. _shadow-file:
- ``--shadow-file SOURCE_FILE SHADOW_FILE`` makes mypy typecheck SHADOW_FILE in
place of SOURCE_FILE. Primarily intended for tooling. Allows tooling to
make transformations to a file before type checking without having to change
the file in-place. (For example, tooling could use this to display the type
of an expression by wrapping it with a call to reveal_type in the shadow
file and then parsing the output.)
- ``--shadow-file SOURCE_FILE SHADOW_FILE``: when mypy is asked to typecheck
``SOURCE_FILE``, this makes it read from and typecheck 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 typecheck the contents of ``temp.py`` instead of ``original.py``,
but error messages will still reference ``original.py``.
.. _no-implicit-optional:
......
.. _common_issues:
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, but sometimes you need to do things slightly
differently.
normal Python code (except for type annotations), but sometimes you need
to do things slightly differently.
Can't install mypy using pip
----------------------------
......@@ -30,7 +30,8 @@ flagged as an error.
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.
annotations. Where that isn't possible, functions without annotations
can be checked using ``--check-untyped-defs``.
Example:
......@@ -130,16 +131,44 @@ The second line is now fine, since the ignore comment causes the name
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 ``__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.
Unexpected errors about 'None' and/or 'Optional' types
------------------------------------------------------
Starting from mypy 0.600, mypy uses
:ref:`strict optional checking <strict_optional>` by default,
and ``None`` is not compatible with non-optional types. It's
easy to switch back to the older behavior where ``None`` was
and the ``None`` value is not compatible with non-optional types.
It's easy to switch back to the older behavior where ``None`` was
compatible with arbitrary types (see :ref:`no_strict_optional`).
You can also fall back to this behavior if strict optional
checking would require a large number of ``assert foo is not None``
checks to be inserted, and you want to minimize the number
of code changes required to get a clean mypy run.
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.
Types of empty collections
--------------------------
......@@ -149,7 +178,7 @@ dict to a new variable, as mentioned earlier:
.. code-block:: python
a = [] # type: List[int]
a: List[int] = []
Without the annotation mypy can't always figure out the
precise type of ``a``.
......@@ -248,48 +277,6 @@ Possible strategies in such situations are:
return x[0]
f_good(new_lst) # OK
Covariant subtyping of mutable protocol members is rejected
-----------------------------------------------------------
Mypy rejects this because this is potentially unsafe.
Consider this example:
.. code-block:: python
from typing_extensions 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 ``@property`` in
the protocol definition:
.. code-block:: python
from typing_extensions import Protocol
class P(Protocol):
@property
def x(self) -> float:
pass
def fun(arg: P) -> None:
...
class C:
x = 42
fun(C()) # OK
Declaring a supertype as variable type
--------------------------------------
......@@ -429,12 +416,25 @@ understand how mypy handles a particular piece of code. Example:
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::
``reveal_type`` is only understood by mypy and doesn't exist
in Python, if you try to run your program. You'll have to remove
any ``reveal_type`` calls before you can run your code.
``reveal_type`` is always available and you don't need to import it.
``reveal_type`` and ``reveal_locals`` are only understood by mypy and
don't exist in Python. If you try to run your program, you'll have to
remove any ``reveal_type`` and ``reveal_locals`` calls before you can
run your code. Both are always available and you don't need to import
them.
.. _import-cycles:
......@@ -518,3 +518,86 @@ put the linter comment *after* the type comment:
.. code-block:: python
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_extensions 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 ``@property`` in
the protocol definition:
.. code-block:: python
from typing_extensions 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 work-around is to use an alias:
.. code-block:: python
bytes_ = bytes
class Message:
def bytes(self):
...
def register(self, path: bytes_):
...
I need a mypy bug fix that hasn't been released yet
---------------------------------------------------
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
git clone --recurse-submodules https://github.com/python/mypy.git
cd mypy
sudo python3 -m pip install --upgrade .
......@@ -31,15 +31,35 @@ characters.
- Additional sections named ``[mypy-PATTERN1,PATTERN2,...]`` may be
present, where ``PATTERN1``, ``PATTERN2``, etc., are comma-separated
patterns of the form ``dotted_module_name`` or ``dotted_module_name.*``.
patterns of fully-qualified module names, with some components optionally
replaced by `*`s (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 ``dotted_module_name`` matches only the named module,
while ``dotted_module_name.*`` matches ``dotted_module_name`` and any
A pattern of the form ``qualified_module_name`` matches only the named module,
while ``qualified_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``).
When options conflict, the precedence order for the configuration sections is:
1. Sections with concrete module names (``foo.bar``)
2. Sections with "unstructured" wildcard patterns (``foo.*.baz``),
with sections later in the configuration file overriding
sections earlier.
3. Sections with "well-structured" wildcard patterns
(``foo.bar.*``), with more specific overriding more general.
4. Command line options.
5. 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 ``warn_unused_configs`` flag may be useful to debug misspelled
......@@ -163,7 +183,7 @@ overridden by the pattern sections matching the module name.
Used in conjunction with ``follow_imports=skip``, this can be used
to suppress the import of a module from ``typeshed``, replacing it
with `Any`.
Used in conjuncation with ``follow_imports=error``, this can be used
Used in conjunction with ``follow_imports=error``, this can be used
to make any use of a particular ``typeshed`` module an error.
- ``ignore_missing_imports`` (Boolean, default False) suppress error
......
......@@ -16,7 +16,7 @@ dynamically typed by defining it explicitly with the type ``Any``:
from typing import Any
s = 1 # Statically typed (type int)
d = 1 # type: Any # Dynamically typed (type Any)
d: Any = 1 # Dynamically typed (type Any)
s = 'x' # Type check error
d = 'x' # OK
......
.. _existing-code:
Using mypy with an existing codebase
====================================
This section explains how to get started using mypy with an existing,
significant codebase that has little or no type annotations. If you are
a beginner, you can skip this section.
These steps will get you started with mypy on an existing codebase:
1. Start small -- get a clean mypy build for some files, with few
annotations
2. Write a mypy runner script to ensure consistent results
3. Run mypy in Continuous Integration to prevent type errors
4. Gradually annotate commonly imported modules
5. Write annotations as you modify existing code and write new code
6. Use MonkeyType or PyAnnotate to automatically annotate legacy code
We discuss all of these points in some detail below, and a few optional
follow-up steps.
Start small
-----------
If your codebase is large, pick a subset of your codebase (say, 5,000
to 50,000 lines) and run mypy only on this subset at first,
*without any annotations*. This shouldn't take more than a day or two
to implement, so you start enjoying benefits soon.
You'll likely need to fix some mypy errors, either by inserting
annotations requested by mypy or by adding ``# type: ignore``
comments to silence errors you don't want to fix now.
In particular, mypy often generates errors about modules that it can't
find or that don't have stub files:
.. code-block:: text
core/config.py:7: error: Cannot find module named 'frobnicate'
core/model.py:9: error: Cannot find module named 'acme'
...
This is normal, and you can easily ignore these errors. For example,
here we ignore an error about a third-party module ``frobnicate`` that
doesn't have stubs using ``# type: ignore``:
.. code-block:: python
import frobnicate # type: ignore
...
frobnicate.initialize() # OK (but not checked)
You can also use a mypy configuration file, which is convenient if
there are a large number of errors to ignore. For example, to disable
errors about importing ``frobnicate`` and ``acme`` everywhere in your
codebase, use a config like this:
.. code-block:: text
[mypy-frobnicate.*]
ignore_missing_imports = True
[mypy-acme.*]
ignore_missing_imports = True
You can add multiple sections for different modules that should be
ignored.
If your config file is named ``mypy.ini``, this is how you run mypy:
.. code-block:: text
mypy --config-file mypy.ini mycode/
If you get a large number of errors, you may want to ignore all errors
about missing imports. This can easily cause problems later on and
hide real errors, and it's only recommended as a last resort.
For more details, look :ref:`here <follow-imports>`.
Mypy follows imports by default. This can result in a few files passed
on the command line causing mypy to process a large number of imported
files, resulting in lots of errors you don't want to deal with at the
moment. There is a config file option to disable this behavior, but
since this can hide errors, it's not recommended for most users.
Mypy runner script
------------------
Introduce a mypy runner script that runs mypy, so that every developer
will use mypy consistently. Here are some things you may want to do in
the script:
* Ensure that the correct version of mypy is installed.
* Specify mypy config file or command-line options.
* Provide set of files to type check. You may want to implement
inclusion and exclusion filters for full control of the file
list.
Continuous Integration
----------------------
Once you have a clean mypy run and a runner script for a part
of your codebase, set up your Continuous Integration (CI) system to
run mypy to ensure that developers won't introduce bad annotations.
A simple CI script could look something like this:
.. code-block:: text
python3 -m pip install mypy==0.600 # Pinned version avoids surprises
scripts/mypy # Runs with the correct options
Annotate widely imported modules
--------------------------------
Most projects have some widely imported modules, such as utilities or
model classes. It's a good idea to annotate these pretty early on,
since this allows code using these modules to be type checked more
effectively. Since mypy supports gradual typing, it's okay to leave
some of these modules unannotated. The more you annotate, the more
useful mypy will be, but even a little annotation coverage is useful.
Write annotations as you go
---------------------------
Now you are ready to include type annotations in your development
workflows. Consider adding something like these in your code style
conventions:
1. Developers should add annotations for any new code.
2. It's also encouraged to write annotations when you modify existing code.
This way you'll gradually increase annotation coverage in your
codebase without much effort.
Automate annotation of legacy code
----------------------------------
There are tools for automatically adding draft annotations
based on type profiles collected at runtime. Tools include
`MonkeyType <https://github.com/Instagram/MonkeyType>`_
(Python 3) and `PyAnnotate <https://github.com/dropbox/pyannotate>`_
(type comments only).
A simple approach is to collect types from test runs. This may work
well if your test coverage is good (and if your tests aren't very
slow).
Another approach is to enable type collection for a small, random
fraction of production network requests. This clearly requires more
care, as type collection could impact the reliability or the
performance of your service.
Speed up mypy runs
------------------
You can use :ref:`mypy daemon <mypy_daemon>` to get much faster
incremental mypy runs. The larger your project is, the more useful
this will be. If your project has at least 100,000 lines of code or
so, you may also want to set up :ref:`remote caching <remote-cache>`
for further speedups.
Introduce stricter options
--------------------------
Mypy is very configurable. Once you get started with static typing,
you may want to explore the various
strictness options mypy provides to
catch more bugs. For example, you can ask mypy to require annotations
for all functions in certain modules to avoid accidentally introducing
code that won't be type checked. Refer to :ref:`command-line` for the
details.
......@@ -6,7 +6,8 @@ Why have both dynamic and static typing?
Dynamic typing can be flexible, powerful, convenient and easy. But
it's not always the best approach; there are good reasons why many
developers choose to use statically typed languages.
developers choose to use statically typed languages or static typing
for Python.
Here are some potential benefits of mypy-style static typing:
......@@ -54,26 +55,26 @@ may be useful:
- Multiple developers are working on the same code.
- Running tests takes a lot of time or work (type checking may help
you find errors early in development, reducing the number of testing
iterations).
- Running tests takes a lot of time or work (type checking helps
you find errors quickly early in development, reducing the number of
testing iterations).
- Some project members (devs or management) don't like dynamic typing,
but others prefer dynamic typing and Python syntax. Mypy could be a
solution that everybody finds easy to accept.
- You want to future-proof your project even if currently none of the
above really apply.
above really apply. The earlier you start, the easier it will be to
adopt static typing.
Can I use mypy to type check my existing Python code?
*****************************************************
It depends. Compatibility is pretty good, but some Python features are
not yet implemented or fully supported. The ultimate goal is to make
using mypy practical for most Python code. Code that uses complex
Mypy supports most Python features and idioms, and many large Python
projects are using mypy successfully. Code that uses complex
introspection or metaprogramming may be impractical to type check, but
it should still be possible to use static typing in other parts of a
program.
codebase that are less dynamic.
Will static typing make my programs run faster?
***********************************************
......@@ -82,10 +83,7 @@ Mypy only does static type checking and it does not improve
performance. It has a minimal performance impact. In the future, there
could be other tools that can compile statically typed mypy code to C
modules or to efficient JVM bytecode, for example, but this is outside
the scope of the mypy project. It may also be possible to modify
existing Python VMs to take advantage of static type information, but
whether this is feasible is still unknown. This is nontrivial since
the runtime types do not necessarily correspond to the static types.
the scope of the mypy project.
How do I type check my Python 2 code?
*************************************
......@@ -101,13 +99,14 @@ Is mypy free?
Yes. Mypy is free software, and it can also be used for commercial and
proprietary projects. Mypy is available under the MIT license.
Can I use structural subtyping?
*******************************
Can I use duck typing with mypy?
********************************
Mypy provides support for both `nominal subtyping
<https://en.wikipedia.org/wiki/Nominative_type_system>`_ and
`structural subtyping
<https://en.wikipedia.org/wiki/Structural_type_system>`_.
Structural subtyping can be thought of as "static duck typing".
Some argue that structural subtyping is better suited for languages with duck
typing such as Python. Mypy however primarily uses nominal subtyping,
leaving structural subtyping mostly opt-in (except for built-in protocols
......@@ -138,11 +137,12 @@ subtyping see :ref:`protocol-types` and
I like Python and I have no need for static typing
**************************************************
That wasn't really a question, was it? Mypy is not aimed at replacing
Python. The goal is to give more options for Python programmers, to
The aim of mypy is not to convince everybody to write statically typed
Python -- static typing is entirely optional, now and in the
future. The goal is to give more options for Python programmers, to
make Python a more competitive alternative to other statically typed
languages in large projects, to improve programmer productivity and to
improve software quality.
languages in large projects, to improve programmer productivity, and
to improve software quality.
How are mypy programs different from normal Python?
***************************************************
......@@ -156,16 +156,11 @@ supported by mypy, but this is gradually improving.
The obvious difference is the availability of static type
checking. The section :ref:`common_issues` mentions some
modifications to Python code that may be required to make code type
check without errors. Also, your code must make attributes explicit and
use a explicit protocol representation. For example, you may want to
subclass an Abstract Base Class such as ``typing.Iterable``.
check without errors. Also, your code must make attributes explicit.
Mypy will support modular, efficient type checking, and this seems to
Mypy supports modular, efficient type checking, and this seems to
rule out type checking some language features, such as arbitrary
runtime addition of methods. However, it is likely that many of these
features will be supported in a restricted form (for example, runtime
modification is only supported for classes or methods registered as
dynamic or 'patchable').
monkey patching of methods.
How is mypy different from Cython?
**********************************
......@@ -205,53 +200,6 @@ the following aspects, among others:
Python semantics, and mypy does not deal with accessing C library
functionality.
How is mypy different from Nuitka?
**********************************
`Nuitka <http://nuitka.net/>`_ is a static compiler that can translate
Python programs to C++. Nuitka integrates with the CPython
runtime. Nuitka has additional future goals, such as using type
inference and whole-program analysis to further speed up code. Here
are some differences:
- Nuitka is primarily focused on speeding up Python code. Mypy focuses
on static type checking and facilitating better tools.
- Whole-program analysis tends to be slow and scale poorly to large or
complex programs. It is still unclear if Nuitka can solve these
issues. Mypy does not use whole-program analysis and will support
modular type checking (though this has not been implemented yet).
How is mypy different from RPython or Shed Skin?
************************************************
`RPython <http://doc.pypy.org/en/latest/coding-guide.html>`_ and `Shed
Skin <http://shed-skin.blogspot.co.uk/>`_ are basically statically
typed subsets of Python. Mypy does the following important things
differently:
- RPython is primarily designed for implementing virtual machines;
mypy is a general-purpose tool.
- Mypy supports both static and dynamic typing. Dynamically typed and
statically typed code can be freely mixed and can interact
seamlessly.
- Mypy aims to support (in the future) fast and modular type
checking. Both RPython and Shed Skin use whole-program type
inference which is very slow, does not scale well to large programs
and often produces confusing error messages. Mypy can support
modularity since it only uses local type inference; static type
checking depends on having type annotations for functions
signatures.
- Mypy will support introspection, dynamic loading of code and many
other dynamic language features (though using these may make static
typing less effective). RPython and Shed Skin only support a
restricted Python subset without several of these features.
- Mypy supports user-defined generic types.
Mypy is a cool project. Can I help?
***********************************
......
.. _function-overloading:
Function Overloading
====================
Sometimes the types in a function depend on each other in ways that
can't be captured with a ``Union``. For example, the ``__getitem__``
(``[]`` bracket indexing) method can take an integer and return a
single item, or take a ``slice`` and return a ``Sequence`` of items.
You might be tempted to annotate it like so:
.. code-block:: python
from typing import Sequence, TypeVar, Union
T = TypeVar('T')
class MyList(Sequence[T]):
def __getitem__(self, index: Union[int, slice]) -> Union[T, Sequence[T]]:
if isinstance(index, int):
... # Return a T here
elif isinstance(index, slice):
... # Return a sequence of Ts here
else:
raise TypeError(...)
But this is too loose, as it implies that when you pass in an ``int``
you might sometimes get out a single item and sometimes a sequence.
The return type depends on the parameter type in a way that can't be
expressed using a type variable. Instead, we can use `overloading
<https://www.python.org/dev/peps/pep-0484/#function-method-overloading>`_
to give the same function multiple type annotations (signatures) and
accurately describe the function's behavior.
.. code-block:: python
from typing import overload, Sequence, TypeVar, Union
T = TypeVar('T')
class MyList(Sequence[T]):
# The @overload definitions are just for the type checker,
# and overwritten by the real implementation below.
@overload
def __getitem__(self, index: int) -> T:
pass # Don't put code here
# All overloads and the implementation must be adjacent
# in the source file, and overload order may matter:
# when two overloads may overlap, the more specific one
# should come first.
@overload
def __getitem__(self, index: slice) -> Sequence[T]:
pass # Don't put code here
# The implementation goes last, without @overload.
# It may or may not have type hints; if it does,
# these are checked against the overload definitions
# as well as against the implementation body.
def __getitem__(self, index: Union[int, slice]) -> Union[T, Sequence[T]]:
# This is exactly the same as before.
if isinstance(index, int):
... # Return a T here
elif isinstance(index, slice):
... # Return a sequence of Ts here
else:
raise TypeError(...)
Calls to overloaded functions are type checked against the variants,
not against the implementation. A call like ``my_list[5]`` would have
type ``T``, not ``Union[T, Sequence[T]]`` because it matches the
first overloaded definition, and ignores the type annotations on the
implementation of ``__getitem__``. The code in the body of the
definition of ``__getitem__`` is checked against the annotations on
the the corresponding declaration. In this case the body is checked
with ``index: Union[int, slice]`` and a return type
``Union[T, Sequence[T]]``. If there are no annotations on the
corresponding definition, then code in the function body is not type
checked.
The annotations on the function body must be compatible with the
types given for the overloaded variants listed above it. The type
checker will verify that all the types listed the overloaded variants
are compatible with the types given for the implementation. In this
case it checks that the parameter type ``int`` and the return type
``T`` are compatible with ``Union[int, slice]`` and
``Union[T, Sequence[T]]`` for the first variant. For the second
variant it verifies that the parameter type ``slice`` are the return
type ``Sequence[T]`` are compatible with ``Union[int, slice]`` and
``Union[T, Sequence[T]]``.
Overloaded function variants are still ordinary Python functions and
they still define a single runtime object. There is no automatic
dispatch happening, and you must manually handle the different types
in the implementation (usually with :func:`isinstance` checks, as
shown in the example).
The overload variants must be adjacent in the code. This makes code
clearer, as you don't have to hunt for overload variants across the
file.
Overloads in stub files are exactly the same, except there is no
implementation.
.. note::
As generic type variables are erased at runtime when constructing
instances of generic types, an overloaded function cannot have
variants that only differ in a generic type argument,
e.g. ``List[int]`` and ``List[str]``.
.. note::
If you just need to constrain a type variable to certain types or
subtypes, you can use a :ref:`value restriction
<type-variable-value-restriction>`.
Generics
========
This section explains how you can define your own generic classes that take
one or more type parameters, similar to built-in types such as ``List[X]``.
User-defined generics are a moderately advanced feature and you can get far
without ever using them -- feel free to skip this section and come back later.
.. _generic-classes:
Defining generic classes
......@@ -23,7 +28,7 @@ generic class that represents a stack:
class Stack(Generic[T]):
def __init__(self) -> None:
# Create an empty list with items of type T
self.items = [] # type: List[T]
self.items: List[T] = []
def push(self, item: T) -> None:
self.items.append(item)
......@@ -644,3 +649,76 @@ Generic protocols can also be recursive. Example:
... # implementation omitted
result = last(L()) # Inferred type of 'result' is 'int'
Generic type aliases
********************
Type aliases can be generic. In this case they can be used in two ways:
Subscripted aliases are equivalent to original types with substituted type
variables, so the number of type arguments must match the number of free type variables
in the generic type alias. Unsubscripted aliases are treated as original types with free
variables replaced with ``Any``. Examples (following `PEP 484
<https://www.python.org/dev/peps/pep-0484/#type-aliases>`_):
.. code-block:: python
from typing import TypeVar, Iterable, Tuple, Union, Callable
S = TypeVar('S')
TInt = Tuple[int, S]
UInt = Union[S, int]
CBack = Callable[..., S]
def response(query: str) -> UInt[str]: # Same as Union[str, int]
...
def activate(cb: CBack[S]) -> S: # Same as Callable[..., S]
...
table_entry: TInt # Same as Tuple[int, Any]
T = TypeVar('T', int, float, complex)
Vec = Iterable[Tuple[T, T]]
def inproduct(v: Vec[T]) -> T:
return sum(x*y for x, y in v)
def dilate(v: Vec[T], scale: T) -> Vec[T]:
return ((x * scale, y * scale) for x, y in v)
v1: Vec[int] = [] # Same as Iterable[Tuple[int, int]]
v2: Vec = [] # Same as Iterable[Tuple[Any, Any]]
v3: Vec[int, int] = [] # Error: Invalid alias, too many type arguments!
Type aliases can be imported from modules just like other names. An
alias can also target another alias, although building complex chains
of aliases is not recommended -- this impedes code readability, thus
defeating the purpose of using aliases. Example:
.. code-block:: python
from typing import TypeVar, Generic, Optional
from example1 import AliasType
from example2 import Vec
# AliasType and Vec are type aliases (Vec as defined above)
def fun() -> AliasType:
...
T = TypeVar('T')
class NewVec(Vec[T]):
...
for i, j in NewVec[int]():
...
OIntVec = Optional[Vec[int]]
.. note::
A type alias does not define a new type. For generic type aliases
this means that variance of type variables used for alias definition does not
apply to aliases. A parameterized generic alias is treated simply as an original
type with the corresponding type variables substituted.