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

List[Union[...]] is not always satisfied by valid inputs. #3351

Closed
tomchristie opened this issue May 10, 2017 · 7 comments
Closed

List[Union[...]] is not always satisfied by valid inputs. #3351

tomchristie opened this issue May 10, 2017 · 7 comments

Comments

@tomchristie
Copy link

When a list of unions is used, mypy will incorrectly error when a subset of the possible union types is used...

example.py:

from typing import List, Union

def mean(numbers: List[Union[int, float]]) -> float:
    return sum(numbers) / len(numbers)

some_numbers = [1, 2, 3, 4]
mean(some_numbers)

console:

$ mypy --version
mypy 0.470
$ mypy example.py 
example.py:7: error: Argument 1 to "mean" has incompatible type List[int]; expected List[Union[int, float]]

Presumably the inferred List[int] ought to be able to satisfy List[Union[int, float]], right?

@ilevkivskyi
Copy link
Member

ilevkivskyi commented May 10, 2017

Presumably the inferred List[int] ought to be able to satisfy List[Union[int, float]], right?

No, List is invariant, and therefore List[int] is not a subtype (not compatible with) List[Union[int, float]] (the latter actually is just List[float], see PEP 484). The reason is that lists are mutable and therefore it is not safe to pass something of type List[int], where List[float] (or List[Union[int, float]]) is expected.

See the docs for such situations. In your case I would recommend annotating your function as:

def mean(numbers: Sequence[float]) -> float:

(since you don't mutate numbers.)

@tomchristie
Copy link
Author

Thanks for the clarification. 😄
(& apologies for the noise!)

@gvanrossum
Copy link
Member

This should also be called out much earlier in the mypy docs. It's a very common "bug" report.

@ilevkivskyi
Copy link
Member

I think what Jukka proposed in #3352 (including link to docs in error messages) will solve the problem.

@ierezell
Copy link

ierezell commented Sep 30, 2020

Sorry for the necroBump but I'm not able to have a list from Literals (as the exemple here) and I guess it's the same topic.

I Feel that something is possible but I cannot make the typing system satisfied with that

For exemple :

MyListType = Literal['dogs', 'cats', 'crocodiles', 'ducks', 'bird', 'pony', 'fish'] # Tried with Union[Literal,Literal...] as well
my_list : List[MyListType] = ['cats', 'crocodiles', 'ducks'] # Tried with Sequence as well and putting all elements in the MyListType

I guess it's comming from Type "str" cannot be assigned to type "MyListType" which should...

@gvanrossum
Copy link
Member

@ierezell I don't get an error for that input. Please see Gitter for more help.

davidszotten added a commit to davidszotten/django-stubs that referenced this issue Jul 3, 2021
Unlike `List`, which is invariant, `Sequence` is covariant, which lets
`path` accept lists of subsets of the `Union` as well.

I believe this is safe, as django doesn't mutate this input. I found
[this
comment](python/mypy#3351 (comment))
helpful
sobolevn pushed a commit to typeddjango/django-stubs that referenced this issue Jul 3, 2021
Unlike `List`, which is invariant, `Sequence` is covariant, which lets
`path` accept lists of subsets of the `Union` as well.

I believe this is safe, as django doesn't mutate this input. I found
[this
comment](python/mypy#3351 (comment))
helpful
@Godsmith
Copy link

Godsmith commented Nov 3, 2021

Presumably the inferred List[int] ought to be able to satisfy List[Union[int, float]], right?

No, List is invariant, and therefore List[int] is not a subtype (not compatible with) List[Union[int, float]] (the latter actually is just List[float], see PEP 484). The reason is that lists are mutable and therefore it is not safe to pass something of type List[int], where List[float] (or List[Union[int, float]]) is expected.

To explain why this is unsafe, to help people like me who have never heard the term invariant before, say that you have the following code:

def add_float(numbers: List[Union[int, float]]):
    numbers.append(4.5)

ints = [1, 2, 3]  # type: List[int]

If you then do

add_float(ints)

you will end up with ints containing [1, 2, 3, 4.5] even though in the type definition it says that ints should only contain integers! And that is what they meant when they said passing the list into the method was "unsafe".

hunterhector added a commit to qinzzz/forte that referenced this issue Feb 20, 2022
List is invariant so we have to update the function return type annotation a bit: python/mypy#3351
hunterhector added a commit to asyml/forte that referenced this issue Feb 20, 2022
* change tyoe_id to type_name in DataStore for compatablility

* fix mypy error

* Update batch_processor.py

* Update bert_based_query_creator.py

* Update converter.py

* Update converter.py

List is invariant so we have to update the function return type annotation a bit: python/mypy#3351

* Update converter.py

* Update converter.py

* Update converter.py

* Update converter.py

* Update converter.py

* Update converter.py

* Update converter.py

* Update forte/data/data_store.py

* Update converter.py

Co-authored-by: qinzzz <[email protected]>
Co-authored-by: Hector <[email protected]>
kodiakhq bot pushed a commit to sbdchd/djangorestframework-types that referenced this issue Apr 12, 2022
Use `Sequence` instead of `List` in `apply_suffix_patterns` and `format_suffix_patterns`. This thread, python/mypy#3351 (comment), explains why `List`, which is invariant, isn't suitable here
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants