Skip to content

Commit

Permalink
Update basic mypy docs.
Browse files Browse the repository at this point in the history
- Remove some phrasings that still sound like mypy is a separate language.
- Remove mention of `import typing` to trigger type checking.
- Note spurious messages from semantic analysis.
- Update instructions for writing stubs.
- Warn against setting MYPYPATH to sys.path or site-packages.
  • Loading branch information
Guido van Rossum committed Apr 20, 2016
1 parent 110842c commit 4825e34
Showing 1 changed file with 81 additions and 83 deletions.
164 changes: 81 additions & 83 deletions docs/source/basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,29 @@ as the rest of documentation may not make much sense otherwise.
Function signatures
*******************

A function without a type signature is dynamically typed. 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 (the type checker reports type errors within
the function). A function without a type annotation is dynamically
typed, and identical to ordinary Python:
A function without a type annotation is considered dynamically typed:

.. code-block:: python
def greeting(name):
return 'Hello, {}'.format(name)
This version of the above function is statically typed (but it's still
valid Python):
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 is statically typed and will be
type checked:

.. code-block:: python
def greeting(name: str) -> str:
return 'Hello, {}'.format(name)
A ``None`` return type indicates a function that does not explicitly
return a value. Using a ``None`` result in a statically typed context
results in a type check error:
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
Expand All @@ -39,22 +39,36 @@ results in a type check error:
a = p() # Type check error: p has None return value
The typing module
*****************
Mixing dynamic and static typing
********************************

We cheated a bit in the above examples: a module is type checked only
if it imports the module ``typing``. Here is a complete statically typed
example from the previous section:
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
import typing
def f():
1 + 'x' # No static type error (dynamically typed)
def greeting(name: str) -> str:
return 'Hello, {}'.format(name)
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 can also use ``from ... import`` to import
statically typed code. You typically use ``from ... import`` to import
them (we'll explain ``Iterable`` later in this document):

.. code-block:: python
Expand All @@ -69,32 +83,9 @@ For brevity, we often omit the ``typing`` import in code examples, but
you should always include it in modules that contain statically typed
code.

You can still have dynamically typed functions in modules that import ``typing``:

.. code-block:: python
import typing
def f():
1 + 'x' # No static type error (dynamically typed)
def g() -> None:
1 + 'x' # Type check error (statically typed)
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.

.. note::

Currently the type checker checks the top levels and annotated
functions of all modules, even those that don't import
``typing``. However, you should not rely on this, as this will change
in the future.
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 and running programs
**********************************
Expand All @@ -105,22 +96,19 @@ running it::

$ mypy program.py

You can always run a mypy program as a Python program, without type
checking, even if it has type errors::

$ python3 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/JukkaL/mypy/blob/master/README.md>`_
The `README <https://github.com/python/mypy/blob/master/README.md>`_
explains how to download and install mypy.

.. note::

Depending on how mypy is configured, you may have to explicitly use
the Python interpreter to run mypy. The mypy tool is an ordinary
mypy (and so also Python) program.
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:

Expand All @@ -131,57 +119,67 @@ 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 empty function bodies (containing only ``pass``).
their types, but dummy function bodies.

For example, consider this code:

.. code-block:: python
x = chr(4)
Without a library stub, the type checker has no way of inferring the
type of ``x`` and checking that the argument to ``chr`` has a valid
type. Mypy contains the `typeshed <http://github.com/python/typeshed>`_ project,
which contains library stubs for Python builtins that contains a definition
like this for ``chr``:
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: pass
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 for a library module that you
import. You can create a stub easily; here is an overview:
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 within
the mypy module search path. The Python interpreter will ignore the ``.pyi`` file,
so you can have stubs and normal Python files in the same directory.
* Alternatively, create a ``.py`` file in
a directory reserved for stubs (e.g., ``myproject/stubs``). Also, you have
to set the environment variable ``MYPYPATH`` to refer to the above directory.
For example::
* 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``, and use a subdirectory with ``__init__.pyi`` for packages.

If there is both a ``.py`` and a ``.pyi`` file for a 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.
for module ``csv``. Use a subdirectory with ``__init__.pyi`` for packages.

You can also override the stubs mypy uses for standard library modules, in case
you need to make local modifications. (Note that if you want to submit your
changes, please submit a pull request to `typeshed <http://github.com/python/typeshed>`_
first, and then update the submodule in mypy using a commit that only touches
the typeshed submodule and nothing else)
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 or
contributing it to mypy.
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.

0 comments on commit 4825e34

Please # to comment.