如何为 pytest 固定装置指定 mypy 类型

Ren*_*ann 5 python pytest mypy

我正在尝试为我在测试项目中使用的 pytest 本机装置指定 mypy 类型提示,例如:

import pytest

def pytest_configure(config):
    # Do something useful here
Run Code Online (Sandbox Code Playgroud)

所述config固定装置返回一个_pytest.config.Config对象。如果我尝试天真地建模:

import pytest

def pytest_configure(config: Config) -> None:
    # Do something useful here
Run Code Online (Sandbox Code Playgroud)

我收到一个 mypy 错误: conftest.py:3: error: Name 'Config' is not defined [name-defined]

我可以from _pytest.config import Config,但这似乎不是一个好方法,因为 _pytest 是私有的。另一种选择是忽略带有# type: ignore. 如果这是推荐的方式,我当然会这样做,但我想知道是否有更好的选择。

我在使用任何类型的 pytest 本机装置时都有同样的问题,例如request用于参数化装置。这将是一个_pytest.fixtures.FixtureRequest.

hoe*_*ing 4

输入from _pytest.config

由于pytest当前不导出Config(从 6.2 开始),因此输入的唯一方法是使用from _pytest.config import Config. 这也是我打字的方式config,例如在我的这个问题中可以看出:

from _pytest.config import Config

def pytest_configure(config: Config) -> None:
    ...
Run Code Online (Sandbox Code Playgroud)

您可以在本期跟踪打字进度pytest#7469

自定义类型存根

您还可以引入一个隐藏重新导出的小型自定义类型存根。它在这里是否有用值得怀疑,只值得一提的是替代解决方案。_typeshed/pytest.pyi如果您创建一个包含以下内容的文件:

from typing import Any
from _pytest.config import Config as Config

def __getattr__(name: str) -> Any: ...  # incomplete
Run Code Online (Sandbox Code Playgroud)

并使其可mypy访问mypy.ini

[mypy]
mypy_path = _typeshed
Run Code Online (Sandbox Code Playgroud)

现在您from pytest import Config至少可以在类型检查模式下导入 - 运行时导入仍然会失败。所以导入看起来像

from typing import Any, TYPE_CHECKING

if TYPE_CHECKING:
    from pytest import Config
else:
    Config = Any


def pytest_configure(config: Config) -> None:
    pass
Run Code Online (Sandbox Code Playgroud)

该解决方案的唯一好处是私人导入现在被隐藏了;不过我仍然会选择私人进口。