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

Add @staticmethod overloads #1116

Merged
merged 2 commits into from
Oct 31, 2023
Merged

Conversation

richardm-stripe
Copy link
Contributor

Fixes #1113.

As #1113 reports, the types for our classmethods do not work for MyPy. The problem is our @class_method_variant pattern and the fact that we have methods with the same name that double as both class methods and instance methods.

MyPy doesn't like it when you do not apply @classmethod consistently to all overloads of a method. It complains

Overload does not consistently use the "@classmethod" decorator on all function signatures.  [misc]

I don't mind doing something MyPy doesn't like internally in stripe-python, so long as it gives users types that accurately describe correct usage of the library, but unfortunately in this case MyPy will not generate the overload type that omits self or cls (unlike how Pyright behaves, incidentally). Here's a simplified example:

class Foo:
    @overload
    def boop(self, id: str) -> None:
        pass

    @overload
    @classmethod
    def boop(cls, id: str) -> None:
        pass

    def boop(*args: Any, **kwargs: Any) -> None:
        pass

reveal_type(Foo.boop)
# MYPY: Revealed type is "Overload(def (self: t.Foo, id: builtins.str), def (cls: Type[t.Foo], id: builtins.str))"
# PYRIGHT: Type of "Foo.boop" is "Overload[(self: Foo, id: str) -> None, (id: str) -> None]"

reveal_type(Foo().boop)
# MYPY: Revealed type is "def (id: builtins.str)"
# PYRIGHT: Type of "Foo().boop" is "Overload[(id: str) -> None, (id: str) -> None]"

This PR addresses the problem by adding an additional @staticmethod overload. This isn't very satisfying, as @staticmethod is for methods that do not actually need a reference to cls. On the other hand, because we're only using it on an overload, it doesn't really change the way anything behaves at runtime at all, and it causes MyPy to generate an overload typed the way we want, i.e.:

reveal_type(Foo.boop)
# Revealed type is "Overload(def (self: t.Foo, id: builtins.str), def (cls: Type[t.Foo], id: builtins.str), def (id: builtins.str))"
reveal_type(Foo().boop)
# Revealed type is "def (id: builtins.str)"

@richardm-stripe richardm-stripe merged commit d3f6fc0 into master Oct 31, 2023
11 checks passed
Copy link

@615689347 615689347 left a comment

Choose a reason for hiding this comment

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

Bot platform

@richardm-stripe richardm-stripe deleted the richardm-staticmethod-overloads branch January 26, 2024 16:58
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.

Method signatures not interpreted correctly by mypy
3 participants