Class mypy 使用 --strict-equality 将其实例视为 Any

Class whose instances are treated as Any by mypy with --strict-equality

我正在创建一个匹配器库,用于通过 == 与值进行比较。不幸的是,在将包含匹配器实例的复合类型与具有非 Any 类型的值进行比较时,如下所示:

assert {"foo": SomeMatcher(arg)} == {"foo": 3}

然后带有 --strict-equality 标志的 mypy 抱怨“非重叠相等性检查”。现在,我正在通过 return 类型被注释为 Any 的函数调用构造函数来解决这个问题,但我想知道是否有可能让 mypy 像往常一样对待我的匹配器实例 Any 自动。我知道这样的事情是可能的,因为 mypy 允许传递 unittest.mock.Mock 实例来代替非 Mock 参数,就好像 Mock 实例都具有类型 Any —或者是硬编码到 mypy 中的东西?

我已经尝试通过为我的匹配器提供一个用 return 类型 Any 注释的琐碎 __new__ 以及使用其 __new__ 有 return 类型 Any,但都不起作用。

失败匹配器的 MVCE:

from typing import Any

class InRange:
    def __init__(self, start: int, end: int) -> None:
        self.start = start
        self.end = end

    def __eq__(self, other: Any) -> bool:
        try:
            return bool(self.start <= other <= self.end)
        except (TypeError, ValueError):
            return False


assert {"foo": InRange(1, 5)} == {"foo": 3}
assert {"foo": 3} == {"foo": InRange(1, 5)}

Mypy 确实有一些 certain cases, for example set and frozenset. Although not for unittest.mock.Mock, there it's solved by subclassing Any.

的硬编码异常

子类化 Any 适用于类型存根,但在运行时 python 会抛出错误:TypeError: Cannot subclass typing.Any。以下解决了该问题:

from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    Base = Any
else:
    Base = object

class InRange(Base):
    def __init__(self, start: int, end: int) -> None:
        self.start = start
        self.end = end

    def __eq__(self, other: Any) -> bool:
        try:
            return bool(self.start <= other <= self.end)
        except (TypeError, ValueError):
            return False


assert {"foo": InRange(1, 5)} == {"foo": 3}
assert {"foo": 3} == {"foo": InRange(1, 5)}