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

sorted() does not enforce comparable items in an iterable of tuples #13297

Closed
jcmacdon opened this issue Dec 24, 2024 · 5 comments
Closed

sorted() does not enforce comparable items in an iterable of tuples #13297

jcmacdon opened this issue Dec 24, 2024 · 5 comments
Labels
reason: inexpressable Closed, because this can't be expressed within the current type system stubs: false negative Type checkers do not report an error, but should

Comments

@jcmacdon
Copy link

sorted() does not enforce that every item in the tuple must be comparable:

items: list[tuple[int, object]] = [(1, object()), (1, object())]
sorted(items)

typeshed/stdlib/builtins.pyi

Lines 1762 to 1767 in e5c5318

@overload
def sorted(
iterable: Iterable[SupportsRichComparisonT], /, *, key: None = None, reverse: bool = False
) -> list[SupportsRichComparisonT]: ...
@overload
def sorted(iterable: Iterable[_T], /, *, key: Callable[[_T], SupportsRichComparison], reverse: bool = False) -> list[_T]: ...

@AlexWaygood AlexWaygood added the stubs: false negative Type checkers do not report an error, but should label Dec 24, 2024
@ajaya0
Copy link

ajaya0 commented Dec 25, 2024

Hi @jcmacdon ,
Can you explain the issue in more detail so that I can resolve it?

@jcmacdon
Copy link
Author

In my example items: list[tuple[int, object]] should not be sortable because it is a tuple which contains object which is not comparable.

I think the main issue here is actually not sorted() in particular but the fact that any tuple appears to be compatible with SupportsRichComparison.

This code typechecks ok:

from _typeshed import SupportsRichComparison

tuple1: SupportsRichComparison = (1, object())
tuple2: SupportsRichComparison = (1, object())

items = [tuple1, tuple2]
sorted(items)

but if you run it, you will get a runtime error:

TypeError: '<' not supported between instances of 'object' and 'object'

@ajaya0
Copy link

ajaya0 commented Dec 26, 2024

Hi @jcmacdon,

Thanks for the clarification! I see the issue now. The sorted() function was allowing tuples containing non-comparable types to be sorted, which caused the TypeError at runtime.

@Daverball
Copy link
Contributor

This is a problem with the SupportsRichComparison protocol in general, it's difficult to frame comparability purely as a type, so I don't think it will be possible to get rid of this false negative without type inversion.

You'd need something like this recursive type definition with type intersection and type inversion to handle this case properly

type Comparable = (SupportsRichComparison & Not[tuple[Any, ...]) | tuple[Comparable, ...]

@srittau srittau marked this as a duplicate of #13499 Feb 28, 2025
@srittau srittau added the reason: inexpressable Closed, because this can't be expressed within the current type system label Feb 28, 2025
@srittau
Copy link
Collaborator

srittau commented Feb 28, 2025

I agree that type checkers should complain about the example and the example given by @KotlinIsland in #13499:

sorted(["a", 1]) 

But per @Daverball, I don't think there is anything that we can do to improve the situation without changes to type system. So I'm closing this as inexpressible for now. If you have any ideas that we have overlooked, please send an exploratory PR.

@srittau srittau closed this as not planned Won't fix, can't repro, duplicate, stale Feb 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
reason: inexpressable Closed, because this can't be expressed within the current type system stubs: false negative Type checkers do not report an error, but should
Projects
None yet
Development

No branches or pull requests

5 participants