Open akaptur opened 4 years ago
Hmm, there have been some typeshed changes aimed at fixing this, eg: https://github.com/python/typeshed/pull/4192 (that haven't made it to the latest mypy release). Note that they've definitely helped when passing key
, but clearly haven't fixed your case:
~/tmp λ cat test19.py
z = [1, None]
reveal_type(z)
z.sort()
~/tmp λ mypy test19.py
test19.py:2: note: Revealed type is 'builtins.list[Union[builtins.int, None]]'
~/tmp λ mypy test19.py --custom-typeshed-dir ~/dev/typeshed
test19.py:2: note: Revealed type is 'builtins.list[Union[builtins.int, None]]'
~/tmp λ vim test19.py
~/tmp λ cat test19.py
z = [1, None]
reveal_type(z)
z.sort(key=lambda x: x)
~/tmp λ mypy test19.py
test19.py:2: note: Revealed type is 'builtins.list[Union[builtins.int, None]]'
~/tmp λ mypy test19.py --custom-typeshed-dir ~/dev/typeshed
test19.py:2: note: Revealed type is 'builtins.list[Union[builtins.int, None]]'
test19.py:3: error: Argument "key" to "sort" of "list" has incompatible type "Callable[[Optional[int]], Optional[int]]"; expected "Callable[[Optional[int]], _SupportsLessThan]"
test19.py:3: error: Incompatible return value type (got "Optional[int]", expected "_SupportsLessThan")
Found 2 errors in 1 file (checked 1 source file)
The typeshed change looks correct to me now and looked correct to me at the time. Maybe mypy doesn't deal with typevar upper bounded by protocols in self types correctly? https://github.com/python/typeshed/blob/028f0d52931fe1f96bb25d066186961159c1f801/stdlib/2and3/builtins.pyi#L961 https://github.com/python/typeshed/blob/028f0d52931fe1f96bb25d066186961159c1f801/stdlib/2and3/builtins.pyi#L84
Oh, interesting - the key
version of this is actually more similar to my original code. For example, neither of these sorts produces a warning:
from typing import Optional
class A:
def __init__(self, thing: Optional[int]) -> None:
self.thing = thing
sorted([A(1), A(None)], key=lambda a: a.thing)
# or without the lambda
def sort_func(a: A) -> Optional[int]:
return a.thing
sorted([A(1), A(None)], key=sort_func)
The next release of mypy will complain about both of those sorts :-) If you point mypy at a copy of typeshed master using --custom-typeshed-dir
you can get those errors today.
It's unfortunate that in the key
-less case, mypy doesn't seem to be able to use the newly more accurate typeshed stubs, so we should still keep this issue open. Seems mypy has some issue with typevars upper bounded by protocols in self types, but that sentence covers a lot of surface area, so would need to do some digging to actually see where things go wrong 🤷♂️
Here's another simple example that came up in our code:
from typing import List, Union
def main() -> None:
values: List[Union[float, str]] = [1, "hi", 2, "zen"]
print(sorted(values))
main()
Will the next release catch this one?
@mortoray That probably won't be caught, since both float
and str
are comparable (they just can't be compared with each other). We could support this via a plugin for sorted
(and sort
) that does some special casing.
The next version of mypy will actually catch:
values: List[Union[float, str]] = [1, "hi", 2, "zen"]
values.sort(lambda x: x)
But not other ways of sorting. I believe this is due to a mypy bug. https://github.com/python/mypy/issues/9122#issuecomment-656918736
I was surprised that some code like this wasn't flagged by mypy:
What is the actual behavior/output? No error.
What is the behavior/output you expect? I would expect a similar warning as I get if I do
1 > None
What are the versions of mypy and Python you are using? mypy 0.782, python 3.8.2
What are the mypy flags you are using? (For example --strict-optional) follow_imports=normal warn_redundant_casts=True warn_unused_ignores=True strict_optional=True strict_equality=True no_implicit_optional=True disallow_untyped_defs=True disallow_any_generics=True