Skip to content

Matchers should be contravariant #222

Description

@mezuzza

Currently, the Matcher class has a type arg T as it should, but Matchers 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions