Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected type warnings when using assert_that with sequence matchers #234

Open
borislubimov opened this issue Jul 14, 2023 · 3 comments
Open

Comments

@borislubimov
Copy link

Currently, PyCharm highlights all usages of assert_that with sequence matchers due to unexpected type warnings.
Is it possible to include an overloaded version of assert_that specifically designed for such cases?
Would something like in the example below work?

# Python 3.10.0
# pyhamcrest 2.0.4
def test_assert():
    from hamcrest import assert_that, contains_exactly
    from typing import Sequence
    from typing import TypeVar
    from hamcrest.core.matcher import Matcher
    T = TypeVar("T")

    li = [1, 2, 3]
    ls = ['1', '2', '3']
    s = '123'

    # Native hamcrest asserts

    #  Unexpected type(s): (list[int], Matcher[Sequence]) Possible type(s): (bool, str) (list[int], Matcher[list[int]])
    assert_that(li, contains_exactly(*li))
    # Unexpected type(s): (list[str], Matcher[Sequence]) Possible type(s): (bool, str) (list[str], Matcher[list[str]])
    assert_that(ls, contains_exactly(*ls))
    assert_that(ls, contains_exactly(*s))
    # Unexpected type(s): (str, Matcher[Sequence]) Possible type(s): (bool, str) (str, Matcher[str])
    assert_that(s, contains_exactly(*s))
    assert_that(s, contains_exactly(*ls))

    # Overloaded assert_that

    def my_assert_that(actual_or_assertion: Sequence[T], matcher: Matcher[Sequence[T]], reason: str = "") -> None:
        assert_that(actual_or_assertion, matcher)

    # No Warnings
    my_assert_that(li, contains_exactly(*li))
    my_assert_that(ls, contains_exactly(*ls))
    my_assert_that(s, contains_exactly(*s))
    my_assert_that(ls, contains_exactly(*s))
    my_assert_that(s, contains_exactly(*ls))

How it looks in PyCharm:

assert_that
@brunns
Copy link
Member

brunns commented Jul 17, 2023

Is this the same issue as #222?

@borislubimov
Copy link
Author

It's definitely related, at least changing type in either first or second argument of assert_that, fixes the issue. While changing types in both - returns the issue:

def test_assert_contravariant():
    from hamcrest import assert_that, contains_exactly
    from typing import TypeVar
    from hamcrest.core.matcher import Matcher

    li = [1, 2, 3]

    T = TypeVar("T")
    T_contravariant = TypeVar("T_contravariant", contravariant=True)

    # 1 case
    def my_assert_that_1(actual_or_assertion: T_contravariant, matcher: Matcher[T], reason: str = "") -> None:
        assert_that(actual_or_assertion, matcher, reason)

    my_assert_that_1(li, contains_exactly(*li))  # No Warnings

    # 2 case
    def my_assert_that_2(actual_or_assertion: T, matcher: Matcher[T_contravariant], reason: str = "") -> None:
        assert_that(actual_or_assertion, matcher, reason)

    my_assert_that_2(li, contains_exactly(*li))  # No Warnings

    # 3 case
    def my_assert_that_contr3(actual_or_assertion: T_contravariant, matcher: Matcher[T_contravariant],
                              reason: str = "") -> None:
        assert_that(actual_or_assertion, matcher, reason)

    # Expected type 'Matcher[list[int]]' (matched generic type 'Matcher[T_contravariant]'), got 'Matcher[Sequence]' instead
    my_assert_that_contr3(li, contains_exactly(*li))

@brunns
Copy link
Member

brunns commented Jul 18, 2023

As I said on #222, I wasn't able to get this working on the real codebase. I'd very much appreciate a PR if anyone else can!

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

No branches or pull requests

2 participants