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

Would it be possible to broaden classmethod to accept ParamSpec when MyPy's support is better? #7689

Closed
NeilGirdhar opened this issue Apr 26, 2022 · 5 comments · Fixed by #9771

Comments

@NeilGirdhar
Copy link
Contributor

NeilGirdhar commented Apr 26, 2022

It could be something like:

P = ParamSpec('P')
class classmethod(Generic[P, _R_co]):
    @property
    def __func__(self) -> Callable[P, _R_co]: ...
    @property
    def __isabstractmethod__(self) -> bool: ...
    def __init__(self: classmethod[_R_co], __f: Callable[P, _R_co]) -> None: ...
    def __get__(self, __obj: _T, __type: type[_T] | None = ...) -> Callable[P, _R_co]: ...
    if sys.version_info >= (3, 10):
        __name__: str
        __qualname__: str
        __wrapped__: Callable[P, _R_co]
@AlexWaygood
Copy link
Member

AlexWaygood commented Apr 26, 2022

This is on my to-do list for as soon as mypy 0.950 is released 🙂

@JelleZijlstra
Copy link
Member

Though I'm not sure how much of a difference this will make, considering how thoroughly type checkers special case classmethod (and staticmethod).

@AlexWaygood
Copy link
Member

AlexWaygood commented Apr 26, 2022

Also, staticmethod is quite a lot easier than classmethod. staticmethod doesn't change the signature of the function it wraps, but classmethod does -- it requires Concatenate. It would be something like this:

import sys
from typing import TypeVar, Callable, Generic
from typing_extensions import ParamSpec, Concatenate

_P = ParamSpec("_P")
_R_co = TypeVar("_R_co", covariant=True)
_T = TypeVar("_T")

class classmethod(Generic[_P, _R_co, _T]):
    @property
    def __func__(self) -> Callable[Concatenate[_T, _P], _R_co]: ...
    @property
    def __isabstractmethod__(self) -> bool: ...
    def __init__(self: classmethod[_P, _R_co, _T], __f: Callable[Concatenate[_T, _P], _R_co]) -> None: ...
    def __get__(self, __obj: _T | None, __type: type[_T] | None = ...) -> Callable[_P, _R_co]: ...
    if sys.version_info >= (3, 10):
        __name__: str
        __qualname__: str
        @property
        def __wrapped__(self) -> Callable[Concatenate[_T, _P], _R_co]: ...

@NeilGirdhar
Copy link
Contributor Author

NeilGirdhar commented Apr 26, 2022

@JelleZijlstra Yup, I just learned about that here. It's not too big a deal since it's very rare that you decorate class methods, but maybe after classmethod is broadened they might consider producing a classmethod[P, R, T] instead of a Callable[Concatenate[type[T], P], R].

@AlexWaygood
Copy link
Member

AlexWaygood commented Apr 28, 2022

Mypy 0.950 is now out, but sadly we still cannot use ParamSpec in classmethod or staticmethod due to python/mypy#12011. (abc.abstractclassmethod and abc.abstractstaticmethod inherit from classmethod and staticmethod respectively, so while that mypy issue is outstanding, we cannot make builtins.staticmethod or builtins.classmethod generic over a parameter specification without breaking those two classes.)

@AlexWaygood AlexWaygood added the status: deferred Issue or PR deferred until some precondition is fixed label Jun 12, 2022
@AlexWaygood AlexWaygood removed the status: deferred Issue or PR deferred until some precondition is fixed label Feb 20, 2023
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 a pull request may close this issue.

3 participants