Skip to content

Review SupportsInt and SupportsFloat usages in 3rd-party stubs #11003

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

Merged

Conversation

Avasam
Copy link
Collaborator

@Avasam Avasam commented Nov 9, 2023

Mypy 1.7 has been released since #10707 .
I have reviewed all usages of SupportsInt and SupportsFloat that didn't use the full Union.
Direct replacements have been extracted to #11022

Which also makes me realize two things:

  1. A bunch of Supports* in stdlib could also use ConvertibleTo* instead.
  2. SupportsInt isn't used anywhere in 3rd-party stubs anymore. But CONTIBUTING.md's guide section about Protocols providing callable methods explicitly mentions it. Maybe it'd be a good idea to mention the Convertible aliases also/instead ?

@AlexWaygood
Copy link
Member

Mypy 1.6 (and 1.6.1) has been released since #10707 .

We still can't go ahead with this just yet, unfortunately. If you look at mypy's vendored stubs in mypy/typeshed/stdlib/_typeshed/__init__.py, it doesn't include these aliases in the 1.6.1 tag (which is the latest release). We'll need to wait for mypy 1.7, which should include these aliases in mypy's vendored version of typeshed.

@AlexWaygood AlexWaygood marked this pull request as draft November 9, 2023 18:06
@Avasam
Copy link
Collaborator Author

Avasam commented Nov 9, 2023

Mypy 1.6 (and 1.6.1) has been released since #10707 .

We still can't go ahead with this just yet, unfortunately. If you look at mypy's vendored stubs in mypy/typeshed/stdlib/_typeshed/__init__.py, it doesn't include these aliases in the 1.6.1 tag (which is the latest release). We'll need to wait for mypy 1.7, which should include these aliases in mypy's vendored version of typeshed.

Oh my bad, I thought the stubs were updated as well. draft + DO NOT MERGE it is in the mean time. It'll probably accumulate a couple merge conflicts but that's fine they'll be easy to fix.

This comment has been minimized.

@Akuli
Copy link
Collaborator

Akuli commented Nov 10, 2023

I don't think we should apply ConvertibleToInt blindly to anything that converts things to int. Because ConvertibleToInt includes str, using it means that users won't get an error if they accidentally pass a string instead of a number.

@AlexWaygood
Copy link
Member

Mypy 1.7 is out now, but I'd still like to wait another week or so before we consider this, to give people time to upgrade to the latest mypy -- being overly hasty with things like this has caused issues in the past. Agree with @Akuli that it might also be good to be opinionated in some places, and continue using SupportsInt -- we should think about this carefully

@Avasam
Copy link
Collaborator Author

Avasam commented Nov 10, 2023

There's a couple places where it's a simple existing union replacement. Splitting it up might make it easier to review intent of other SupportsInt changes?

@AlexWaygood
Copy link
Member

There's a couple places where it's a simple existing union replacement. Splitting it up might make it easier to review intent of other SupportsInt changes?

that'd be great, yeah :)

@Avasam Avasam changed the title Use ConvertibleToInt and ConvertibleToFloat in 3rd-party stubs Review SupportsInt and SupportsFloat usages in 3rd-party stubs Nov 12, 2023
@Avasam Avasam marked this pull request as ready for review November 12, 2023 17:55
@Avasam Avasam requested a review from AlexWaygood November 12, 2023 17:55

This comment has been minimized.

@@ -70,10 +74,10 @@ def size() -> Size: ...

resolution = size

def onScreen(x: _NormalizeableXArg | None, y: SupportsInt | None = None) -> bool: ...
def onScreen(x: _NormalizeableXArg | None, y: ConvertibleToInt | None = None) -> bool: ...
Copy link
Member

Choose a reason for hiding this comment

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

Are there any examples in the documentation where y is called with a str argument? Or, is there any particular reason that you know of to pass a str to the y parameter?

It's true that the function at runtime calls int() on the argument passed to y before doing anything with it, so if you pass "10" to the y parameter, it will work. But what's the reason for doing so? SupportsInt isn't a perfect type hint here, but it ensures that the type checker will still emit an error if a user accidentally tries to pass "foo" to the y parameter -- and with this change, it wouldn't.

In general, typeshed tries to put more weight on avoiding false positives than on avoiding false negatives. But in a situation like this, where (as far as I can see) there's no real use case for passing a str, I think we can and should be more opinionated than the function at runtime.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think so. I'll revert here. How about the normalizable X arg (see _NormalizeableXArg aslias)? It can be a str, but str there means "filename on screen"

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I'm fine with that one!

@@ -40,7 +41,7 @@ class EUI(BaseIdentifier):
@property
def value(self) -> int: ...
@value.setter
def value(self, value: str | SupportsInt | SupportsIndex) -> None: ...
def value(self, value: ConvertibleToInt) -> 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 seems like a good change, since the .value property is explicitly there in order to transform str, bytes objects etc. into int before they're stored on the EUI instance

@@ -148,14 +148,14 @@ class IPRange(BaseIP, IPListMixin):
def cidrs(self) -> list[IPNetwork]: ...

def iter_unique_ips(*args: IPRange | _IPNetworkAddr) -> Iterator[IPAddress]: ...
def cidr_abbrev_to_verbose(abbrev_cidr: str | SupportsInt | SupportsIndex) -> str: ...
def cidr_abbrev_to_verbose(abbrev_cidr: ConvertibleToInt) -> str: ...
Copy link
Member

Choose a reason for hiding this comment

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

This change seems reasonable to me; the function at runtime is deliberately very permissive in what it accepts

@Avasam Avasam requested a review from AlexWaygood December 14, 2023 22:51
Copy link
Contributor

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Thanks!

@srittau srittau merged commit 91b35bb into python:main Dec 18, 2023
@Avasam Avasam deleted the ConvertibleToInt-ConvertibleToFloat-3rd-party branch December 18, 2023 15:15
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