如何使用 mypy 检查类型*不*兼容

问题描述 投票:0回答:2

想象一下我正在编写一个带有一个(废话)函数的小型 Python 库:

def takes_a_str(x: str) -> str:
    if x.startswith("."):
        raise RuntimeError("Must not start with '.'")
    return x + ";"

对于功能的运行时测试,我可以检查它在正确条件(例如

assert takes_a_str('x')=='x;'
)和错误条件(例如
with pytest.raises(RuntimeError): takes_a_str('.')
)下的行为是否符合预期。

如果我想检查类型提示是否有错误,我还可以执行积极测试:我可以在单独的文件中创建一个小测试函数并运行 mypy 或 Pyright 以查看没有错误:

def check_types():
    x: str = takes_a_str("")

但我也想通过检查一些负面案例是否失败来确保我的类型提示不会太松散:

def should_fail_type_checking():
    x: dict = takes_a_str("")
    takes_a_str(2)

我可以对此运行 mypy 并观察到它在我预期的地方出现错误,但这不是一个自动化的解决方案。例如,如果我有 20 个这样的案例,我无法立即看到它们都失败了,也可能不会注意到其中是否存在其他错误。

有没有办法要求类型检查器通过,并且仅在类型转换不匹配的情况下通过?类似于

pytest.raises()
的类型检查?

python mypy typechecking pyright
2个回答
0
投票

有没有办法要求类型检查器通过,并且仅在类型转换不匹配的情况下通过?类似于

pytest.raises()
的类型检查?

我认为普通工具不可能做到这一点,因为同样的原因,如果某个函数中存在

语法错误
,则无法要求python.exe仅接受文件。

类型检查的目的是验证程序是否自洽。它不会检查特定实例并给您一个分数,这是测试套件的工作。

如果您确实想确保负面示例始终无法进行类型检查,您可以随时编写对

mypy
的调用脚本,并在每个文件的基础上检查报告的错误。不像
pytest.raises()
那么干净,但比在运行时测试类型注释的框架简单得多。


0
投票

mypy 和 Pyright 都支持在检测到不必要的错误抑制注释时发出错误。您可以利用它来执行相当于

pytest.raises
的操作,当事物 类型安全时,检查失败。需要打开的静态类型检查选项是:

演示(mypy PlaygroundPyright Playground):

def should_fail_type_checking() -> None:
    # no errors
    x: dict = takes_a_str("")  # type: ignore[assignment] OR # pyright: ignore[reportAssignmentType]
    takes_a_str(2)  # type: ignore[arg-type] OR # pyright: ignore[reportArgumentType]

def check_types() -> None:
    # Failures with mypy and pyright
    # mypy: Unused "type: ignore" comment  [unused-ignore]
    # pyright: Unnecessary "# pyright: ignore" rule: "reportAssignmentType"
    x: str = takes_a_str("")  # type: ignore[assignment] OR # pyright: ignore[reportAssignmentType]

备注:

  • 应该提供准确的错误抑制代码,就像你不提供具体的代码一样,mypy和pyright将抑制一行上的所有错误;在您的上下文中,这相当于执行
    pytest.raises(BaseException)
  • 如果您支持多种类型检查器(例如 mypy 和 Pyright),则更喜欢 mypy 诊断
    type: ignore[<mypy error code>]
    - 注释字符序列
    # type: ignore...
    是符合 Python 类型的代码,所有类型检查器都应该识别它。
© www.soinside.com 2019 - 2024. All rights reserved.