在编写特定于项目的pytest
插件时,我经常发现Config
对象对于附加我自己的属性很有用。例如:
from _pytest.config import Config
def pytest_configure(config: Config) -> None:
config.fizz = "buzz"
def pytest_unconfigure(config: Config) -> None:
print(config.fizz)
显然,在_pytest.config.Config
类中没有fizz
属性,因此在上述代码段上运行mypy
会产生
conftest.py:5: error: "Config" has no attribute "fizz"
conftest.py:8: error: "Config" has no attribute "fizz"
(请注意,pytest
还没有带有类型提示的发行版,因此如果您想在本地实际重现错误,请按照this comment中的步骤安装一个fork)
有时,重新定义用于类型检查的类可以提供快速帮助:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from _pytest.config import Config as _Config
class Config(_Config):
fizz: str
else:
from _pytest.config import Config
def pytest_configure(config: Config) -> None:
config.fizz = "buzz"
def pytest_unconfigure(config: Config) -> None:
print(config.fizz)
然而,除了使代码混乱之外,子类化的解决方法非常有限:添加例如
from pytest import Session
def pytest_sessionstart(session: Session) -> None:
session.config.fizz = "buzz"
将迫使我也重写Session
以进行类型检查
解决这个问题的最佳方法是什么Config
是一个例子,但我通常在每个项目中都有多个(针对测试收集/调用/报告等的项目特定调整)。我可以想象写我自己版本的pytest
存根,但是我需要在每个项目中重复这一点,这非常乏味
一种方法是让
Config
对象定义__getattr__
和__setattr__
方法。如果这些方法是在类中定义的,mypy将使用这些方法来检查您正在访问或设置某些未定义属性的位置例如:
如果您确实知道您的特殊属性将始终是STR或其他内容,则可以键入
__getattr__
和__setattr__
以返回或接受str
,而不是分别键入Any
以获得更紧凑的类型不幸的是,您仍然需要使用子类型技巧,否则就需要自己制作存根。这给您带来的唯一好处是,您至少不必列出要设置的每个自定义属性,从而可以创建真正可重用的内容。这可能会让你更喜欢这个选择,不确定
您可以探索的其他选项包括:
# type: ignore
注释。这将是一种有点精确(如果是侵入性的)抑制错误消息的方法李>pytest_configure
和pytest_unconfigure
,以便它们接受类型为Any
的对象。这将是一种抑制错误消息的干扰性较小的方法。如果您想最小化使用Any
的爆炸半径,那么您可以将希望使用这些自定义属性的任何逻辑限制为它们自己的专用函数,并继续在其他任何地方使用Config
李>pytest_configure
内部,您可以执行config = cast(MutableConfig, config)
,其中MutableConfig
是您编写的一个类,它将_pytest.Config
子类化,并定义__getattr__
和__setattr__
。这可能是上述两种方法之间的一个中间点李>Config
和类似类添加特殊属性是一种常见的做法,那么可以尝试说服pytest维护人员在其类型提示中只键入__getattr__
和__setattr__
定义,或者以其他更专用的方式让用户添加这些动态属性李>您可以通过一个新属性来扩展
Config
类,该属性是dict
并存储所有自定义信息。例如:这样一来,一个自定义存根文件适合所有项目。当然,它不会立即帮助您的旧项目,因为您需要重写相关部分以使用
data['fizz']
而不是fizz
。但是,使用dict
的另一个优点是,它可以防止现有属性和自定义属性之间可能出现的名称冲突如果将自定义数据附加到
Config
对象是常见的做法,那么可能值得尝试以数据dict的形式对此进行标准化,并在pytest
项目中打开相应的问题如果您不喜欢重写代码,但仍然希望使用静态类型检查器,那么仍然可以使用从某个模板生成的自定义每个项目存根文件。您可以将所有自定义属性直接列为自定义类上的注释,然后让脚本从中生成相应的存根文件:
相关问题 更多 >
编程相关推荐