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

Stubtest: add a hint when arguments in the stub need to be keyword-only #16210

Merged
merged 1 commit into from
Oct 1, 2023

Conversation

AlexWaygood
Copy link
Member

@AlexWaygood AlexWaygood commented Oct 1, 2023

Something I've seen come up several times in typeshed is that a runtime library will have a class similar to this (which is contrived, but you hopefully see the point):

class Foo:
    def __init__(self, **kwargs):
        self.a = kwargs.pop('a')
        self.b = kwargs.pop('b')
        self.c = kwargs.pop('c')
        if kwargs:
            raise Exception("no")

Somebody will then come along and try to write stubs for this class like this, which is nearly correct, except that all the arguments need to be keyword-only:

class Foo:
    def __init__(self, a: int = ..., b: int = ..., c: int = ...) -> None: ...

Stubtest then (correctly!) gets very angry and reports three errors for this function. However, none of the error messages tells the author of the stub that the arguments all need to be made keyword-only:

error: pkg.Foo.__init__ is inconsistent, runtime does not have argument "a"
Stub: in file pkg.pyi
def (self: pkg.Foo, a: int =, b: int =, c: int =)
Runtime: in file pkg.py:
def (self, **kwargs)

error: pkg.Foo.__init__ is inconsistent, runtime does not have argument "b"
Stub: in file pkg.pyi
def (self: pkg.Foo, a: int =, b: int =, c: int =)
Runtime: in file pkg.py:
def (self, **kwargs)

error: pkg.Foo.__init__ is inconsistent, runtime does not have argument "c"
Stub: in file pkg.pyi
def (self: pkg.Foo, a: int =, b: int =, c: int =)
Runtime: in file pkg.py:
def (self, **kwargs)

With this PR, stubtest instead emits the following error messages if the runtime has a **kwargs variadic keyword argument:

error: pkg.Foo.__init__ is inconsistent, runtime does not have argument "a". Maybe you forgot to make it keyword-only in the stub?
Stub: in file pkg.pyi
def (self: pkg.Foo, a: int =, b: int =, c: int =)
Runtime: in file pkg.py:
def (self, **kwargs)

error: pkg.Foo.__init__ is inconsistent, runtime does not have argument "b". Maybe you forgot to make it keyword-only in the stub?
Stub: in file pkg.pyi
def (self: pkg.Foo, a: int =, b: int =, c: int =)
Runtime: in file pkg.py:
def (self, **kwargs)

error: pkg.Foo.__init__ is inconsistent, runtime does not have argument "c". Maybe you forgot to make it keyword-only in the stub?
Stub: in file pkg.pyi
def (self: pkg.Foo, a: int =, b: int =, c: int =)
Runtime: in file pkg.py:
def (self, **kwargs)

Copy link
Member

@JelleZijlstra JelleZijlstra left a comment

Choose a reason for hiding this comment

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

Your example doesn't seem all that contrived, this is a good addition.

@AlexWaygood
Copy link
Member Author

(The real-life example is python/typeshed#10815. The stubtest errors on the first commit in that PR were these -- 42 errors due to two missing *s! The PR author did this in response, when they should have done this instead.)

@hauntsaninja hauntsaninja merged commit bcd4ff2 into python:master Oct 1, 2023
12 checks passed
@AlexWaygood AlexWaygood deleted the stubtest-hint branch October 1, 2023 22:48
@hauntsaninja
Copy link
Collaborator

Nice, thank you!

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.

3 participants