typeshed icon indicating copy to clipboard operation
typeshed copied to clipboard

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

Open NeilGirdhar opened this issue 2 years ago • 5 comments

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]

NeilGirdhar avatar Apr 26 '22 03:04 NeilGirdhar

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

AlexWaygood avatar Apr 26 '22 03:04 AlexWaygood

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

JelleZijlstra avatar Apr 26 '22 03:04 JelleZijlstra

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]: ...

AlexWaygood avatar Apr 26 '22 03:04 AlexWaygood

@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].

NeilGirdhar avatar Apr 26 '22 03:04 NeilGirdhar

Mypy 0.950 is now out, but sadly we still cannot use ParamSpec in classmethod or staticmethod due to https://github.com/python/mypy/issues/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 avatar Apr 28 '22 04:04 AlexWaygood