blob: ff5a96ae98ca0e6ee34df52c477932f05f833837 [file]
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 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
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 `README <https://github.com/python/mypy/blob/master/README.md>`_
explains how to download and install mypy.
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
<http://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 stubs 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.