Skip to content

mypy doesn't type-check membership equality, for example: 'foo' in bar_list  #1749

Closed

Description

@cpdean

I'm not sure if this is a bug or a feature request, but given mypy will enforce types on the append operator, it feels incomplete it doesn't also support checking if an element is present in a list of a different type.

For example:

from typing import List


def is_it_in(things):
    # type: (List[int]) -> bool
    if "foo" in things:   # this will not fail, but it should
        return True
    else:
        return False


def add_a_thing(things):
    # type: (List[int]) -> None
    things.append("foo")  # this will fail expectedly

t = [1, 2, 3]
add_a_thing(t)
assert is_it_in(t)

Running it gives the following on master, mypy-lang-0.4.3.dev0:

mypy --py2 test.py
test.py: note: In function "add_a_thing":
test.py:14: error: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"

I know that there isn't anything wrong with going "foo" in things since the list could have anything in it, but mypy yells at append("foo"), so if adding things to a list are checked, maybe inspecting that list could be type-checked too?

Activity

  1. gvanrossum commented on Jun 26, 2016

    @gvanrossum
    Member

    It's not symmetric though. You could have a value whose type is a supertype of the list item type (or a union that includes the list item type), and while it's a definite violation to append that to the list, it's not necessarily wrong to check whether that's in the list. But if mypy believes that the membership test will always return False it would be okay to report that IMO.

    I think we may already have an issue about this?

  2. JukkaL commented on Jun 26, 2016

    @JukkaL
    Collaborator

    Yeah, something similar was discussed a while ago. Note that there's no syntax in PEP 484 that lets us specify the desired behavior for __contains__ in a stub file. Mypy could special case a few of the more common operations like this, and this would likely give pretty good coverage.

  3. rwbarton commented on Jun 26, 2016

    @rwbarton
    Contributor

    Yep, it was discussed in #1472, though that discussion went in other directions as well.

    I've had two confusing debugging experiences while working on mypy itself which would have been caught immediately by such a check, so I'm personally quite in favor of seeing something done here.

  4. gvanrossum commented on Jun 27, 2016

    @gvanrossum
    Member

    I guess what I'm saying is that I don't like the idea of requiring is_subtype(X, Y) when checking X in Container[Y]. I do agree that we could require that the intersection of X and Y is not object, but I'm not sure how to express that.

  5. cpdean commented on Jun 27, 2016

    @cpdean
    Author

    I can see how the membership check doesn't necessarily violate the List[int] annotation, since you can still ask if anything is in a list, but how strict or non strict do we want to be here? I can see the value in enforcing it on the append method but I'm struggling to come up with a use case when we wouldn't want to enforce it for checking for an element in a list. if a list sometimes could have a different type then they could just annotate it with a Union, right?

  6. gvanrossum commented on Jun 27, 2016

    @gvanrossum
    Member

    So if I have y: List[int] then '' in y should be an error.

    But here's a case using an overlap:

    class B: ...
    class C(B): ...
    y = []  # type: List[C]
    def foo(x: B):
        if x in y: ...  # HERE
        else: ...
    

    I don't think the check in foo() should trigger an error; having to make it "type-safe" by writing

        if isinstance(x, C) and x in y: ...
    

    doesn't help anybody.

  7. cpdean commented on Jun 27, 2016

    @cpdean
    Author

    That's a good point, I agree with you. But what about the case where they're totally different types?

    Sorry, went right for the code example and skipped over what you had said @gvanrossum .

  8. JukkaL commented on Jul 15, 2016

    @JukkaL
    Collaborator

    There's a similar issue with equality. Maybe mypy should warn about 2 == 'x', for example. (This was asked by Stefan Kraus).

  9. ilevkivskyi commented on Aug 9, 2019

    @ilevkivskyi
    Member

    We now have a flag --strict-equality to opt-in to strict equality and membership checks, so I think this can now be closed.

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions