I would like to annotate both parameters of a function – supposed to perform simple comparison between them – in order to indicate that their types should be the same and should support simple equality comparison.
The second part should be normally trivial, as every type implicitly inherits from object which promises to support this:
class object:
def __eq__(self, value: object, /) -> bool: ...
and yet numpy.ndarray does not, because its parent class overrides the method as
class _ArrayOrScalarCommon:
def __eq__(self, other: Any) -> Any: ...
in order to return arrays of booleans with the shape of the argument instead of a unique boolean. This should already be marked as incompatible override as it represents a violation of the LSP.
Nevertheless, I want to enforce correctness of the function at type level so that users know that it should not be used with two arguments of type numpy.ndarray or of different types.
Simple protocol annotation does not work:
from typing import Protocol
from numpy import array
class SupportsSimpleComparison(Protocol):
def __eq__(self, other: object, /) -> bool: ...
def check_equal(a: SupportsSimpleComparison, b: SupportsSimpleComparison) -> bool:
return a == b
# no errors reported from pyright
check_equal(array([0, 0, 0]), array([0, 0, 1]))
check_equal(1.0, "hello world")
Nor does making the function generic with a type variable bound to the protocol:
T = TypeVar("T", bound=SupportsSimpleComparison)
def check_equal(a: T, b: T) -> bool:
return a == b
# no errors reported from pyright
check_equal(array([0, 0, 0]), array([0, 0, 1]))
check_equal(1.0, "hello world")
Anyas the return type fundamentally disables the type check. In general you are allowed to pass anAnyas abool, it would be very frustrating if you couldn't. Without updating numpy, I don't know if there is a solution. You might need to fall back to runtime validation.