| .. _stub-files: | |
| Stub files | |
| ========== | |
| A *stub file* is a file containing a skeleton of the public interface | |
| of that Python module, including classes, variables, functions -- and | |
| most importantly, their types. | |
| Mypy uses stub files stored in the | |
| `typeshed <https://github.com/python/typeshed>`_ repository to determine | |
| the types of standard library and third-party library functions, classes, | |
| and other definitions. You can also create your own stubs that will be | |
| used to type check your code. | |
| Creating a stub | |
| *************** | |
| Here is an overview of how to create a stub file: | |
| * Write a stub file for the library (or an arbitrary module) 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., :file:`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. :file:`csv.pyi` | |
| for module ``csv``. Use a subdirectory with :file:`__init__.pyi` for packages. Note | |
| that :pep:`561` stub-only packages must be installed, and may not be pointed | |
| at through the ``MYPYPATH`` (see :ref:`PEP 561 support <installed-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. | |
| Mypy also ships with two tools for making it easier to create and maintain | |
| stubs: :ref:`stubgen` and :ref:`stubtest`. | |
| 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 :file:`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. | |
| Stub file syntax | |
| **************** | |
| Stub files are written in normal Python syntax, but generally | |
| leaving out runtime logic like variable initializers, function bodies, | |
| and default arguments. | |
| If it is not possible to completely leave out some piece of runtime | |
| logic, the recommended convention is to replace or elide them with ellipsis | |
| expressions (``...``). Each ellipsis below is literally written in the | |
| stub file as three dots: | |
| .. code-block:: python | |
| # Variables with annotations do not need to be assigned a value. | |
| # So by convention, we omit them in the stub file. | |
| x: int | |
| # Function bodies cannot be completely removed. By convention, | |
| # we replace them with `...` instead of the `pass` statement. | |
| def func_1(code: str) -> int: ... | |
| # We can do the same with default arguments. | |
| def func_2(a: int, b: int = ...) -> int: ... | |
| .. note:: | |
| The ellipsis ``...`` is also used with a different meaning in | |
| :ref:`callable types <callable-types>` and :ref:`tuple types | |
| <tuple-types>`. | |
| Using stub file syntax at runtime | |
| ********************************* | |
| You may also occasionally need to elide actual logic in regular | |
| Python code -- for example, when writing methods in | |
| :ref:`overload variants <function-overloading>` or | |
| :ref:`custom protocols <protocol-types>`. | |
| The recommended style is to use ellipses to do so, just like in | |
| stub files. It is also considered stylistically acceptable to | |
| throw a :py:exc:`NotImplementedError` in cases where the user of the | |
| code may accidentally call functions with no actual logic. | |
| You can also elide default arguments as long as the function body | |
| also contains no runtime logic: the function body only contains | |
| a single ellipsis, the pass statement, or a ``raise NotImplementedError()``. | |
| It is also acceptable for the function body to contain a docstring. | |
| For example: | |
| .. code-block:: python | |
| from typing import Protocol | |
| class Resource(Protocol): | |
| def ok_1(self, foo: list[str] = ...) -> None: ... | |
| def ok_2(self, foo: list[str] = ...) -> None: | |
| raise NotImplementedError() | |
| def ok_3(self, foo: list[str] = ...) -> None: | |
| """Some docstring""" | |
| pass | |
| # Error: Incompatible default for parameter "foo" (default has | |
| # type "ellipsis", parameter has type "list[str]") | |
| def not_ok(self, foo: list[str] = ...) -> None: | |
| print(foo) |