Using installed packages¶
Packages installed with pip can declare that they support type checking. For example, the aiohttp package has built-in support for type checking.
Packages can also provide stubs for a library. For example,
types-requests
is a stub-only package that provides stubs for the
requests package.
Stub packages are usually published from typeshed, a shared repository for Python
library stubs, and have a name of form types-<library>
. Note that
many stub packages are not maintained by the original maintainers of
the package.
The sections below explain how mypy can use these packages, and how you can create such packages.
Note
PEP 561 specifies how a package can declare that it supports type checking.
Note
New versions of stub packages often use type system features not
supported by older, and even fairly recent mypy versions. If you
pin to an older version of mypy (using requirements.txt
, for
example), it is recommended that you also pin the versions of all
your stub package dependencies.
Note
Starting in mypy 0.900, most third-party package stubs must be installed explicitly. This decouples mypy and stub versioning, allowing stubs to updated without updating mypy. This also allows stubs not originally included with mypy to be installed. Earlier mypy versions included a fixed set of stubs for third-party packages.
Using installed packages with mypy (PEP 561)¶
Typically mypy will automatically find and use installed packages that
support type checking or provide stubs. This requires that you install
the packages in the Python environment that you use to run mypy. As
many packages don’t support type checking yet, you may also have to
install a separate stub package, usually named
types-<library>
. (See Missing imports for how to deal
with libraries that don’t support type checking and are also missing
stubs.)
If you have installed typed packages in another Python installation or
environment, mypy won’t automatically find them. One option is to
install another copy of those packages in the environment in which you
installed mypy. Alternatively, you can use the
--python-executable
flag to point
to the Python executable for another environment, and mypy will find
packages installed for that Python executable.
Note that mypy does not support some more advanced import features, such as zip imports and custom import hooks.
If you don’t want to use installed packages that provide type
information at all, use the --no-site-packages
flag to disable searching for installed packages.
Note that stub-only packages cannot be used with MYPYPATH
. If you
want mypy to find the package, it must be installed. For a package
foo
, the name of the stub-only package (foo-stubs
) is not a
legal package name, so mypy will not find it, unless it is installed
(see PEP 561: Stub-only Packages for
more information).
Creating PEP 561 compatible packages¶
Note
You can generally ignore this section unless you maintain a package on PyPI, or want to publish type information for an existing PyPI package.
PEP 561 describes three main ways to distribute type information:
A package has inline type annotations in the Python implementation.
A package ships stub files with type information alongside the Python implementation.
A package ships type information for another package separately as stub files (also known as a “stub-only package”).
If you want to create a stub-only package for an existing library, the simplest way is to contribute stubs to the typeshed repository, and a stub package will automatically be uploaded to PyPI.
If you would like to publish a library package to a package repository
yourself (e.g. on PyPI) for either internal or external use in type
checking, packages that supply type information via type comments or
annotations in the code should put a py.typed
file in their
package directory. For example, here is a typical directory structure:
setup.py
package_a/
__init__.py
lib.py
py.typed
The setup.py
file could look like this:
from setuptools import setup
setup(
name="SuperPackageA",
author="Me",
version="0.1",
package_data={"package_a": ["py.typed"]},
packages=["package_a"]
)
Some packages have a mix of stub files and runtime files. These packages also
require a py.typed
file. An example can be seen below:
setup.py
package_b/
__init__.py
lib.py
lib.pyi
py.typed
The setup.py
file might look like this:
from setuptools import setup
setup(
name="SuperPackageB",
author="Me",
version="0.1",
package_data={"package_b": ["py.typed", "lib.pyi"]},
packages=["package_b"]
)
In this example, both lib.py
and the lib.pyi
stub file exist. At
runtime, the Python interpreter will use lib.py
, but mypy will use
lib.pyi
instead.
If the package is stub-only (not imported at runtime), the package should have
a prefix of the runtime package name and a suffix of -stubs
.
A py.typed
file is not needed for stub-only packages. For example, if we
had stubs for package_c
, we might do the following:
setup.py
package_c-stubs/
__init__.pyi
lib.pyi
The setup.py
might look like this:
from setuptools import setup
setup(
name="SuperPackageC",
author="Me",
version="0.1",
package_data={"package_c-stubs": ["__init__.pyi", "lib.pyi"]},
packages=["package_c-stubs"]
)
The instructions above are enough to ensure that the built wheels
contain the appropriate files. However, to ensure inclusion inside the
sdist
(.tar.gz
archive), you may also need to modify the
inclusion rules in your MANIFEST.in
:
global-include *.pyi
global-include *.typed