使用已安装的包(Using installed packages)

通过 pip 安装的包可以声明它们支持类型检查。例如, aiohttp 包内置支持类型检查。

包也可以为库提供存根。例如, types-requests 是一个仅提供存根的包,它为 requests 包提供存根。存根包通常从 typeshed 发布,这是一个共享的 Python 库存根仓库,存根包的命名格式通常为 types-<library>。注意,许多存根包并非由原包的维护者维护。

以下部分解释了 mypy 如何使用这些包,以及如何创建此类包。

备注

PEP 561 规定了一个包如何声明它支持类型检查。

备注

新版本的存根包通常使用不被较旧甚至最近版本的 mypy 支持的类型系统功能。如果你将 mypy 固定为较旧版本(例如使用 requirements.txt ),建议你也将所有存根包依赖项的版本固定。

备注

从 mypy 0.900 开始,大多数第三方包存根必须显式安装。这将 mypy 与存根版本进行解耦,使得存根可以独立更新而不需要更新 mypy。这也允许安装最初未包含在 mypy 中的存根。早期版本的 mypy 包含了一组固定的第三方包存根。

在 mypy 中使用已安装的包(PEP 561)

通常,mypy 会自动找到并使用支持类型检查或提供存根的已安装包。这要求你在运行 mypy 的 Python 环境中安装这些包。由于许多包尚不支持类型检查,你可能还需要安装一个单独的存根包,通常命名为 types-<library>。 (有关如何处理不支持类型检查且缺少存根的库,请参阅 缺失导入(Missing imports))。

如果你在另一个 Python 安装或环境中安装了已键入的包,mypy 不会自动找到它们。一个选项是将这些包的副本安装在你安装了 mypy 的环境中。或者,你可以使用 --python-executable 选项指向另一个环境的 Python 可执行文件,mypy 将找到为该 Python 可执行文件安装的包。

请注意,mypy 不支持一些更高级的导入功能,如 zip 导入和自定义导入钩子。

如果你不想使用任何提供类型信息的已安装包,可以使用 --no-site-packages 选项禁用搜索已安装包。

注意,仅存根包不能与 MYPYPATH 一起使用。如果你希望 mypy 找到该包,则必须安装它。对于包 foo,仅存根包的名称( foo-stubs )不是合法的包名称,因此 mypy 不会找到它,除非它已被安装(有关更多信息,请参阅 PEP 561: Stub-only Packages)。

创建符合 PEP 561 的包(Creating PEP 561 compatible packages)

备注

除非你维护一个在 PyPI 上的包,或者想为现有的 PyPI 包发布类型信息,否则你通常可以忽略此部分。

PEP 561 描述了分发类型信息的三种主要方式:

  1. 包在 Python 实现中包含内联类型注解。

  2. 包随 Python 实现一起提供带有类型信息的 存根文件

  3. 包将类型信息作为存根文件单独分发给另一个包(也称为“仅存根包”)。

如果你想为现有的库创建仅存根包,最简单的方法是向 typeshed 仓库贡献存根文件,存根包将自动上传到 PyPI。

如果你想将库包发布到包仓库(例如 PyPI)用于内部或外部类型检查,提供类型信息的包应在代码中的类型注解或类型标注旁边放置一个 py.typed 文件在包目录中。例如,下面是一个典型的目录结构:

setup.py
package_a/
    __init__.py
    lib.py
    py.typed

setup.py 文件可以是这样的:

from setuptools import setup

setup(
    name="SuperPackageA",
    author="Me",
    version="0.1",
    package_data={"package_a": ["py.typed"]},
    packages=["package_a"]
)

有些包包含存根文件和运行时文件的混合。这些包也需要一个 py.typed 文件。下面是一个示例:

setup.py
package_b/
    __init__.py
    lib.py
    lib.pyi
    py.typed

setup.py 文件可能是这样的:

from setuptools import setup

setup(
    name="SuperPackageB",
    author="Me",
    version="0.1",
    package_data={"package_b": ["py.typed", "lib.pyi"]},
    packages=["package_b"]
)

在这个示例中,lib.pylib.pyi 存根文件都存在。运行时,Python 解释器将使用 lib.py,但 mypy 会使用 lib.pyi

如果包是仅存根包(运行时不导入),该包的前缀应为运行时包名,后缀为 -stubs 。仅存根包不需要 py.typed 文件。例如,如果我们有 package_c 的存根,我们可以这样做:

setup.py
package_c-stubs/
    __init__.pyi
    lib.pyi

setup.py 可能是这样的:

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"]
)

上述指令足以确保生成的 wheels 包含适当的文件。然而,为了确保包含在 sdist (.tar.gz 压缩包)中,你还可能需要修改 MANIFEST.in 中的包含规则:

global-include *.pyi
global-include *.typed