问题描述
我正在尝试为我在测试项目中使用的 pytest 本机装置指定 mypy 类型提示,例如:
import pytest
def pytest_configure(config):
# Do something useful here
config
固定装置返回一个 _pytest.config.Config
对象。如果我尝试天真地建模:
import pytest
def pytest_configure(config: Config) -> None:
# Do something useful here
我收到一个 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
。
解决方法
导入 from _pytest.config
由于 pytest
当前不导出 Config
(从 6.2 开始),输入的唯一方法是使用 from _pytest.config import Config
。这也是我输入 config
的方式,例如可以看到在this question of mine:
from _pytest.config import Config
def pytest_configure(config: Config) -> None:
...
您可以在此 pytest
问题中跟踪打字进度:#7469。
自定义类型存根
您还可以引入一个小的自定义类型存根来隐藏重新导出。它在这里是否有用是值得怀疑的,仅值得一提的是替代解决方案。如果您使用以下内容创建文件 _typeshed/pytest.pyi
:
from typing import Any
from _pytest.config import Config as Config
def __getattr__(name: str) -> Any: ... # incomplete
并使其在 mypy
中可供 mypy.ini
访问:
[mypy]
mypy_path = _typeshed
现在您至少可以在类型检查模式下导入 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
该解决方案的唯一好处是现在隐藏了私有导入;不过我还是会选择私人进口。