如何告诉mypy我明确在测试一个错误的类型?

huangapple go评论55阅读模式
英文:

How to tell mypy that I am explicitly testing for an incorrect type?

问题

考虑以下玩具示例:

import pytest

def add(a: float) -> float:
    if not isinstance(a, float):
        raise ValueError("a must be of type float")
    return 10 + a

def test_add_wrong_type() -> None:
    with pytest.raises(ValueError) as err:
        add("foo")  # mypy is complaining here

    assert str(err.value) == "a must be of type float"

“mypy” 报错如下:
“add”的第1个参数具有不兼容的类型“str”;预期为“float” [arg-type]

“mypy”是正确的。然而,在这种情况下,我是故意输入了错误的类型。我如何告诉“mypy”忽略这一行?

换句话说,有什么一种符合 Python 风格的方式来测试不正确的输入类型?

英文:

Consider the following toy example:

import pytest


def add(a: float) -> float:
    if not isinstance(a, float):
        raise ValueError("a must be of type float")
    return 10 + a


def test_add_wrong_type() -> None:
    with pytest.raises(ValueError) as err:
        add("foo")  # mypy is complaining here

    assert str(err.value) == "a must be of type float"

mypy is complaining as follows:
Argument 1 to "add" has incompatible type "str"; expected "float" [arg-type]

Well, mypy is correct. However, in that case I put in an incorrect type on purpose. How can I tell mypy to ignore this line`?

Put it differently, what is a pythonic way to test for an incorrect input type?

答案1

得分: 1

以下是翻译好的内容:

Python类型注解的测试社区至少有两种单元测试类型注解的方法。请注意,# type: ignoretyping.cast 不是测试它们 - 它们是忽略它们和覆盖它们的方式,分别是:

根据您的目的,您可能想选择以下之一:

  • stubtest,它与mypy一起提供。这在typeshed中广泛使用,但更适用于检查.pyi文件中的任何给定类型注解是否与运行时实现匹配。
  • pytest-mypy-plugins,听起来是您在示例中应该选择的。从README.md中获取一个示例,您可能想编写类似于以下内容:
    # test_add.yml
    - case: test_add_wrong_type
      main: |
        from my_module import add
    
        add("")  # E: Argument 1 to "add" has incompatible type "str"; expected "float" [arg-type]    
    

    (我没有测试过这个 - 他们的文档没有提到内联测试错误。我从mypy/test-data/unit中的示例中获取了# E: ...的语法)。

您还可以将mypy作为pytest测试套件的运行时依赖项,如果是这种情况,您可能不需要pytest-mypy-plugins - 他们的测试套件在他们自己的非公开pytest挂钩上运行,您可以直接在您的conftest.py中编写类似于他们的check-*.test文件的示例。

英文:

The Python typing community has at least 2 ways of unit-testing type annotations. Note that # type: ignore and typing.cast are not testing them - they're ignoring them and overriding them, respectively.

Depending on your purpose, you'd want to go for one of the following:

  • stubtest, which ships with mypy. This is extensively used by typeshed, but is more suited to check that any given type annotations in .pyi files match with the runtime implementation.
  • pytest-mypy-plugins, which sounds like what you should go for in your example. Taking an example from README.md, you'd probably want to write something like this:
    # test_add.yml
    - case: test_add_wrong_type
      main: |
        from my_module import add
    
        add("")  # E: Argument 1 to "add" has incompatible type "str"; expected "float" [arg-type]    
    

    (I haven't tested this - their documentation doesn't mention inline-testing errors. I took the # E: ... syntax from the examples in mypy/test-data/unit).

You can also make mypy a runtime dependency for your pytest test suite, in which case you probably don't need pytest-mypy-plugins - their test suite runs on their own non-exposed pytest hooks, which you can import directly in your conftest.py. Just write out examples like their check-*.test files.

答案2

得分: 0

Use typing.cast to assert that "foo" is a float.

from typing import cast


def test_add_wrong_type() -> None:
    with pytest.raises(ValueError) as err:
        add(cast(float, "foo"))

    assert str(err.value) == "a must be of type float"

cast doesn't do type conversions; at runtime, it simply returns its second argument. Its purpose is to provide a standard way to assert a static type for a given value, independent of whatever type checker you might be using.

英文:

Use typing.cast to assert that "foo" is a float.

from typing import cast


def test_add_wrong_type() -> None:
    with pytest.raises(ValueError) as err:
        add(cast(float, "foo"))

    assert str(err.value) == "a must be of type float"

cast doesn't do type conversions; at runtime, it simply returns its second argument. Its purpose is to provide a standard way to assert a static type for a given value, independent of whatever type checker you might be using.

huangapple
  • 本文由 发表于 2023年2月14日 00:47:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/75438855.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定