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

Problem with sorted() and _LT #9582

Closed
jolaf opened this issue Oct 12, 2020 · 5 comments
Closed

Problem with sorted() and _LT #9582

jolaf opened this issue Oct 12, 2020 · 5 comments
Labels
bug mypy got something wrong

Comments

@jolaf
Copy link
Contributor

jolaf commented Oct 12, 2020

The following code:

from typing import Sequence
class A:
    pass
d: Sequence[A] = ()
s = sorted(d)
print("OK")

produces the following output:

$ python3 Test.py
OK
$ mypy Test.py
Test.py:8:5: error: Value of type variable "_LT" of "sorted" cannot be "A"  [type-var]
    s = sorted(d)
$ python3 --version
Python 3.8.5
$ mypy --version
mypy 0.790

The code seems perfectly valid, so mypy reaction looks a false positive.

@jolaf jolaf added the bug mypy got something wrong label Oct 12, 2020
@srittau
Copy link
Contributor

srittau commented Oct 12, 2020

Actually adding items fails at runtime:

from typing import Sequence
class A:
    pass
d: Sequence[A] = (A(), A())
s = sorted(d)
print("OK")
Traceback (most recent call last):
  File "foo.py", line 5, in <module>
    s = sorted(d)
TypeError: '<' not supported between instances of 'A' and 'A'

@pmantica1
Copy link

I saw the same Value of type variable "_LT" of "sorted" ... issue pop up when I bumped the mypy version number from 0.782 to 0.790.

@hauntsaninja
Copy link
Collaborator

This is a new trick mypy has learned. The error message is a little inscrutable, but has already been improved on master (python/typeshed#4579). As Sebastian mentions, in this case the error is valid, so I'm closing.
If others are running into the same error, but in a case where they believe it's a false positive, feel free to file another issue

@JarnoRFB
Copy link

JarnoRFB commented Oct 16, 2020

When using generics, you can get around this by bounding your A on a comparable type. That does not ship with python so you have to define it yourself at the moment:

C = TypeVar("C", bound="Comparable")


class Comparable(Protocol):
    @abstractmethod
    def __eq__(self, other: Any) -> bool:
        ...

    @abstractmethod
    def __lt__(self: C, other: C) -> bool:
        ...

    def __gt__(self: C, other: C) -> bool:
        return (not self < other) and self != other

    def __le__(self: C, other: C) -> bool:
        return self < other or self == other

    def __ge__(self: C, other: C) -> bool:
        return not (self < other)

This idea comes from another mypy issue.
In this case just defining __lt__ should even be enough.

@hauntsaninja
Copy link
Collaborator

Yup. The ingredients you need for many fixes are:

from typing import Protocol
class _SupportsLessThan(Protocol):
    def __lt__(self, __other: Any) -> bool: ...
_SupportsLessThanT = TypeVar("_SupportsLessThanT", bound=_SupportsLessThan)

and as mentioned^, you can use _SupportsLessThanT instead of a plain typevar for generic situations.

Note the error message on master is also improved: Value of type variable "_SupportsLessThan" of "sorted" cannot be "A", which is hopefully clearer.

Finally, the issue for adding this protocol to typing / typing_extensions is here: python/typing_extensions#9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

5 participants