diff --git a/docs/source/basics.rst b/docs/source/basics.rst index 4dda2306e515..9b060313600c 100644 --- a/docs/source/basics.rst +++ b/docs/source/basics.rst @@ -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 @@ -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 @@ -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 ********************************** @@ -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 `_ +The `README `_ 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: @@ -131,7 +119,7 @@ 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: @@ -139,49 +127,59 @@ For example, consider this code: 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 `_ 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 +`_ 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 `_ -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 `_. 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.