Skip to content

new protocol, overloads to list.sort, sorted; prep. to fix #4051, #4155

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
wants to merge 9 commits into from
Closed

new protocol, overloads to list.sort, sorted; prep. to fix #4051, #4155

wants to merge 9 commits into from

Conversation

ramalho
Copy link
Contributor

@ramalho ramalho commented Jun 2, 2020

As agreed with @JelleZijlstra, this PR introduces the _SupportsLessThan protocol and a type variable bounded to it to check arguments to list.sort and sorted on Python 3 (on Python 2, these checks do not reflect reality: everything supports __lt__, even None and object).

When this PR is merged, I will send another one using _SupportsLessThan to check arguments to min and max, fixing #4051 with lots of overloads.

@ramalho
Copy link
Contributor Author

ramalho commented Jun 2, 2020

Ok, I am officially stuck. I there is a Python 3.9 stub test that keeps failing. I don't know how to fix that. Apparently @hauntsaninja found something wrong with the Python 3.9 on the CI, but I don't know how he fixed his build right after mine. Thanks for any help.

@hauntsaninja
Copy link
Collaborator

hauntsaninja commented Jun 2, 2020

Sorry about this!
My PR removes Python 3.9 from typeshed CI, since empirically it's not stable enough to be there (it looks like CPython has moved functools.TopologicalSorter and associated, which to me is a surprisingly large post-beta change).
Once its merged, I'll take care of getting CI green on this PR :-)

@ramalho ramalho changed the title Second attempt, hopefully the broken Python 3.9 stub tests won't fail this time new protocol, overloads to list.sort, sorted; prep. to fix #4051, Jun 2, 2020
Comment on lines 950 to 953
@overload
def sort(self: List[_LT], *, key: None = ..., reverse: bool = ...) -> None: ...
@overload
def sort(self, *, key: Callable[[_T], _LT], reverse: bool = ...) -> None: ...
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are only using one instance of _LT in each overload, the type var is redundant. Just using _SupportsLessThan should work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out @srittau , I will change that in my next commit.

def sorted(__iterable: Iterable[_T], *,
key: Optional[Callable[[_T], Any]] = ...,
key: Callable[[_T], _LT],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Copy link
Contributor Author

@ramalho ramalho Jun 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will implement this change as well. Thanks, @srittau !

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @srittau here. A typevar used in a single position doesn't make semantic sense and type checkers could reasonably throw an error for code like this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But here there is no invariance problem, so the _LT can just be _SupportsLessThan.

@hauntsaninja
Copy link
Collaborator

hauntsaninja commented Jun 2, 2020

Hmm, mypy's throwing a lot of Missing named argument "key" for "sort" of "list". It looks like without the typevar, it's not matching the overload with the self type. Seems like a mypy bug, maybe it doesn't support self typing with protocols?

@srittau
Copy link
Collaborator

srittau commented Jun 2, 2020

Ok, my bad. Seems we should go back to the typevar for now. We can still fix this later when it gets fixed in mypy.

@JelleZijlstra
Copy link
Member

Oh, that's probably because List is invariant, so List[_CT] never matches anything unless your list is exactly List[_CT].

@@ -943,7 +947,10 @@ class list(MutableSequence[_T], Generic[_T]):
def remove(self, __value: _T) -> None: ...
def reverse(self) -> None: ...
if sys.version_info >= (3,):
def sort(self, *, key: Optional[Callable[[_T], Any]] = ..., reverse: bool = ...) -> None: ...
@overload
def sort(self: List[_SupportsLessThan], *, key: None = ..., reverse: bool = ...) -> None: ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must actually be List[_LT] to avoid the invariance issue mentioned in my comment.

def sorted(__iterable: Iterable[_T], *,
key: Optional[Callable[[_T], Any]] = ...,
key: Callable[[_T], _LT],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But here there is no invariance problem, so the _LT can just be _SupportsLessThan.

@ramalho
Copy link
Contributor Author

ramalho commented Jun 6, 2020

Hello, @JelleZijlstra, @srittau, and @hauntsaninja. Thanks for your help with this PR. I made a mistake here and I had to start a new PR #4192, which is passing all checks. I am closing this PR.

Please let's continue at #4192. Thanks!

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

Successfully merging this pull request may close these issues.

4 participants