Skip to content

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

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

Closed
cpdean opened this issue Jun 26, 2016 · 9 comments
Closed

Comments

@cpdean
Copy link

cpdean commented Jun 26, 2016

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?

@gvanrossum
Copy link
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?

@JukkaL
Copy link
Collaborator

JukkaL commented Jun 26, 2016

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.

@rwbarton
Copy link
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.

@gvanrossum
Copy link
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.

@cpdean
Copy link
Author

cpdean commented Jun 27, 2016

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?

@gvanrossum
Copy link
Member

gvanrossum commented Jun 27, 2016

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.

@cpdean
Copy link
Author

cpdean commented Jun 27, 2016

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 .

@JukkaL
Copy link
Collaborator

JukkaL commented Jul 15, 2016

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

@ilevkivskyi
Copy link
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
Projects
None yet
Development

No branches or pull requests

5 participants