PyHamcrest
PyHamcrest copied to clipboard
Matchers should be contravariant
Currently, the Matcher
class has a type arg T
as it should, but Matcher
s are currently invariant with respect to T
. However, I think it's quite clear that the following should be legal code:
matcher: Matcher[str] = has_length(greater_than(0))
I've recreated that definition here:
from typing import Any, Generic, Sequence, Sized, TypeVar
T = TypeVar("T")
class Matcher(Generic[T]):
def matches(self, _: T) -> bool:
...
def greater_than(_: Any) -> Matcher[Any]:
...
def has_length(_: int | Matcher[int]) -> Matcher[Sized]:
...
matcher: Matcher[str] = has_length(greater_than(0))
Pyright provides the following error:
» pyright test.py
[...]
test.py
test.py:23:25 - error: Expression of type "Matcher[Sized]" cannot be assigned to declared type "Matcher[str]"
"Matcher[Sized]" is incompatible with "Matcher[str]"
TypeVar "T@Matcher" is invariant
"Sized" is incompatible with "str" (reportGeneralTypeIssues)
1 error, 0 warnings, 0 informations
Completed in 0.582sec
Changing line 3 to T = TypeVar('T', contravariant=True)
fixes the issue.
python version: 3.10.8 pyhamcrest version: 2.0.4 pyright version: 1.1.280