From 5ca2ed5863e84d840d8fe2bf5319d3ad960fbc2d Mon Sep 17 00:00:00 2001 From: Marc Edwards Date: Sun, 3 Nov 2024 07:16:05 +0000 Subject: [PATCH 01/15] Change `cache`/`lru_cache` typing to retain function signatures Define overloads for `cache`/`lru_cache` that are constrained by the signature of the function they're called with. This assumes `self` as a first parameter is a function method, `cls` is a classmethod and everything else are either static methods or functions. Then direct each overload to a descriptor protocol that mirrors the binding behaviour of methods/functions/classmethods. The returned type is then a union with a callable that takes arbitrary arguments that are hashable. This means that the previous hashable requirement is retained (type checkers don't know which type was returned so calls must satisfy both, the union takes any arguments as long as they're hashable while the descriptor protocol mirrors the cached function's behaviour). --- stdlib/functools.pyi | 108 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 10 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 9957fa8f1634..7ed24283d949 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -2,7 +2,7 @@ import sys import types from _typeshed import SupportsAllComparisons, SupportsItems from collections.abc import Callable, Hashable, Iterable, Sequence, Sized -from typing import Any, Generic, Literal, NamedTuple, TypedDict, TypeVar, final, overload +from typing import Any, Generic, Literal, NamedTuple, TypedDict, TypeVar, overload, Protocol, Concatenate from typing_extensions import ParamSpec, Self, TypeAlias if sys.version_info >= (3, 9): @@ -28,12 +28,16 @@ if sys.version_info >= (3, 9): __all__ += ["cache"] _T = TypeVar("_T") +_T_contra = TypeVar("_T_contra", contravariant=True) _T_co = TypeVar("_T_co", covariant=True) _S = TypeVar("_S") _PWrapped = ParamSpec("_PWrapped") _RWrapped = TypeVar("_RWrapped") _PWrapper = ParamSpec("_PWrapper") _RWrapper = TypeVar("_RWrapper") +_R = TypeVar("_R") +_R_co = TypeVar("_R_co", covariant=True) +_P = ParamSpec("_P") @overload def reduce(function: Callable[[_T, _S], _T], sequence: Iterable[_S], initial: _T, /) -> _T: ... @@ -51,22 +55,100 @@ if sys.version_info >= (3, 9): maxsize: int typed: bool -@final -class _lru_cache_wrapper(Generic[_T]): - __wrapped__: Callable[..., _T] - def __call__(self, *args: Hashable, **kwargs: Hashable) -> _T: ... +class _ProtoFunction(Protocol[_P, _R_co]): + def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R_co:... + +class _FunctionDescriptor(Protocol[_P, _R]): + __wrapped__: Callable[_P, _R] + def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R:... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... + if sys.version_info >= (3, 9): + def cache_parameters(self) -> _CacheParameters: ... + + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + +class _FnHashable(Protocol[_P, _R]): + __wrapped__: Callable[_P, _R] + def __call__(self, *args: Hashable, **kwds: Hashable) -> _R:... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... + if sys.version_info >= (3, 9): + def cache_parameters(self) -> _CacheParameters: ... + + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + + +class _ProtoMethod(Protocol[_T_contra, _P, _R_co]): + def __call__(__self, self: _T_contra, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... + +class _MethodDescriptor(Protocol[_T, _P, _R]): + __wrapped__: Callable[Concatenate[_T, _P], _R] + def __call__(__self, self: _T, *args: _P.args, **kwds: _P.kwargs) -> _R: ... + @overload + def __get__(self, instance: None, owner: type[_T]) -> Self:... + @overload + def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]:... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... + if sys.version_info >= (3, 9): + def cache_parameters(self) -> _CacheParameters: ... + + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + +class _ProtoClassmethod(Protocol[_T_contra, _P, _R_co]): + def __call__(__self, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R_co:... + +class _ClassmethodDescriptor(Protocol[_T, _P, _R]): + __wrapped__: Callable[Concatenate[type[_T], _P], _R] + def __call__(self, cls: type[_T], *args: _P.args, **kwds: _P.kwargs) -> _R:... + @overload + def __get__(self, instance: None, owner: type[_T]) -> _FunctionDescriptor[_P, _R]:... + @overload + def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]:... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... + if sys.version_info >= (3, 9): + def cache_parameters(self) -> _CacheParameters: ... + + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + +class _ClsHashable(Protocol[_T, _P, _R]): + __wrapped__: Callable[Concatenate[type[_T], _P], _R] + def __call__(__self, cls: type[_T], *args: Hashable, **kwds: Hashable) -> _R:... + @overload + def __get__(self, instance: None, owner: type[_T]) -> _FnHashable[_P, _R]:... + @overload + def __get__(self, instance: _T, owner: type[_T]) -> _FnHashable[_P, _R]:... + def __get__(self, instance: _T | None, owner: type[_T]) -> _FnHashable[_P, _R]:... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... if sys.version_info >= (3, 9): def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> _lru_cache_wrapper[_T]: ... - def __deepcopy__(self, memo: Any, /) -> _lru_cache_wrapper[_T]: ... + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + +class _LRUInner(Protocol): + @overload + def __call__(self, fn: _ProtoMethod[_T, _P, _R]) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]:... + @overload + def __call__(self, fn: _ProtoClassmethod[_T, _P, _R]) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]:... + @overload + def __call__(self, fn: _ProtoFunction[_P, _R]) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]:... @overload -def lru_cache(maxsize: int | None = 128, typed: bool = False) -> Callable[[Callable[..., _T]], _lru_cache_wrapper[_T]]: ... +def lru_cache(maxsize: int | None = 128, typed: bool = False) -> _LRUInner: ... +@overload +def lru_cache(maxsize: _ProtoMethod[_T, _P, _R], typed: bool = False) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]:... @overload -def lru_cache(maxsize: Callable[..., _T], typed: bool = False) -> _lru_cache_wrapper[_T]: ... +def lru_cache(maxsize: _ProtoClassmethod[_T, _P, _R], typed: bool = False) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]:... +@overload +def lru_cache(maxsize: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]:... if sys.version_info >= (3, 12): WRAPPER_ASSIGNMENTS: tuple[ @@ -199,7 +281,13 @@ class cached_property(Generic[_T_co]): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... if sys.version_info >= (3, 9): - def cache(user_function: Callable[..., _T], /) -> _lru_cache_wrapper[_T]: ... + @overload + def cache(user_function: _ProtoMethod[_T, _P, _R], typed: bool = False) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]:... + @overload + def cache(user_function: _ProtoClassmethod[_T, _P, _R], typed: bool = False) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]:... + @overload + def cache(user_function: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]:... + def _make_key( args: tuple[Hashable, ...], From c16b3518810021a6dd2e85013eb335f7ef86bce9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 07:27:17 +0000 Subject: [PATCH 02/15] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/functools.pyi | 58 +++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 7ed24283d949..f34ffca6029b 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -2,7 +2,7 @@ import sys import types from _typeshed import SupportsAllComparisons, SupportsItems from collections.abc import Callable, Hashable, Iterable, Sequence, Sized -from typing import Any, Generic, Literal, NamedTuple, TypedDict, TypeVar, overload, Protocol, Concatenate +from typing import Any, Concatenate, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload from typing_extensions import ParamSpec, Self, TypeAlias if sys.version_info >= (3, 9): @@ -56,11 +56,11 @@ if sys.version_info >= (3, 9): typed: bool class _ProtoFunction(Protocol[_P, _R_co]): - def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R_co:... + def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... class _FunctionDescriptor(Protocol[_P, _R]): __wrapped__: Callable[_P, _R] - def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R:... + def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... if sys.version_info >= (3, 9): @@ -71,7 +71,7 @@ class _FunctionDescriptor(Protocol[_P, _R]): class _FnHashable(Protocol[_P, _R]): __wrapped__: Callable[_P, _R] - def __call__(self, *args: Hashable, **kwds: Hashable) -> _R:... + def __call__(self, *args: Hashable, **kwds: Hashable) -> _R: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... if sys.version_info >= (3, 9): @@ -80,7 +80,6 @@ class _FnHashable(Protocol[_P, _R]): def __copy__(self) -> Self: ... def __deepcopy__(self, memo: Any, /) -> Self: ... - class _ProtoMethod(Protocol[_T_contra, _P, _R_co]): def __call__(__self, self: _T_contra, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... @@ -88,9 +87,9 @@ class _MethodDescriptor(Protocol[_T, _P, _R]): __wrapped__: Callable[Concatenate[_T, _P], _R] def __call__(__self, self: _T, *args: _P.args, **kwds: _P.kwargs) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T]) -> Self:... + def __get__(self, instance: None, owner: type[_T]) -> Self: ... @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]:... + def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... if sys.version_info >= (3, 9): @@ -100,15 +99,15 @@ class _MethodDescriptor(Protocol[_T, _P, _R]): def __deepcopy__(self, memo: Any, /) -> Self: ... class _ProtoClassmethod(Protocol[_T_contra, _P, _R_co]): - def __call__(__self, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R_co:... + def __call__(__self, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... class _ClassmethodDescriptor(Protocol[_T, _P, _R]): __wrapped__: Callable[Concatenate[type[_T], _P], _R] - def __call__(self, cls: type[_T], *args: _P.args, **kwds: _P.kwargs) -> _R:... + def __call__(self, cls: type[_T], *args: _P.args, **kwds: _P.kwargs) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T]) -> _FunctionDescriptor[_P, _R]:... + def __get__(self, instance: None, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]:... + def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... if sys.version_info >= (3, 9): @@ -119,12 +118,12 @@ class _ClassmethodDescriptor(Protocol[_T, _P, _R]): class _ClsHashable(Protocol[_T, _P, _R]): __wrapped__: Callable[Concatenate[type[_T], _P], _R] - def __call__(__self, cls: type[_T], *args: Hashable, **kwds: Hashable) -> _R:... + def __call__(__self, cls: type[_T], *args: Hashable, **kwds: Hashable) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T]) -> _FnHashable[_P, _R]:... + def __get__(self, instance: None, owner: type[_T]) -> _FnHashable[_P, _R]: ... @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FnHashable[_P, _R]:... - def __get__(self, instance: _T | None, owner: type[_T]) -> _FnHashable[_P, _R]:... + def __get__(self, instance: _T, owner: type[_T]) -> _FnHashable[_P, _R]: ... + def __get__(self, instance: _T | None, owner: type[_T]) -> _FnHashable[_P, _R]: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... if sys.version_info >= (3, 9): @@ -135,20 +134,24 @@ class _ClsHashable(Protocol[_T, _P, _R]): class _LRUInner(Protocol): @overload - def __call__(self, fn: _ProtoMethod[_T, _P, _R]) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]:... + def __call__(self, fn: _ProtoMethod[_T, _P, _R]) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... @overload - def __call__(self, fn: _ProtoClassmethod[_T, _P, _R]) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]:... + def __call__(self, fn: _ProtoClassmethod[_T, _P, _R]) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... @overload - def __call__(self, fn: _ProtoFunction[_P, _R]) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]:... + def __call__(self, fn: _ProtoFunction[_P, _R]) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... @overload def lru_cache(maxsize: int | None = 128, typed: bool = False) -> _LRUInner: ... @overload -def lru_cache(maxsize: _ProtoMethod[_T, _P, _R], typed: bool = False) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]:... +def lru_cache( + maxsize: _ProtoMethod[_T, _P, _R], typed: bool = False +) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... @overload -def lru_cache(maxsize: _ProtoClassmethod[_T, _P, _R], typed: bool = False) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]:... +def lru_cache( + maxsize: _ProtoClassmethod[_T, _P, _R], typed: bool = False +) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... @overload -def lru_cache(maxsize: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]:... +def lru_cache(maxsize: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... if sys.version_info >= (3, 12): WRAPPER_ASSIGNMENTS: tuple[ @@ -282,12 +285,17 @@ class cached_property(Generic[_T_co]): if sys.version_info >= (3, 9): @overload - def cache(user_function: _ProtoMethod[_T, _P, _R], typed: bool = False) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]:... + def cache( + user_function: _ProtoMethod[_T, _P, _R], typed: bool = False + ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... @overload - def cache(user_function: _ProtoClassmethod[_T, _P, _R], typed: bool = False) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]:... + def cache( + user_function: _ProtoClassmethod[_T, _P, _R], typed: bool = False + ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... @overload - def cache(user_function: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]:... - + def cache( + user_function: _ProtoFunction[_P, _R], typed: bool = False + ) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... def _make_key( args: tuple[Hashable, ...], From 833e40efc045c4ec278d5640d3c7d175695dd753 Mon Sep 17 00:00:00 2001 From: Marc Edwards Date: Sun, 3 Nov 2024 07:33:50 +0000 Subject: [PATCH 03/15] Fix remove overload implementation --- stdlib/functools.pyi | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index f34ffca6029b..581e10dd365f 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -123,7 +123,6 @@ class _ClsHashable(Protocol[_T, _P, _R]): def __get__(self, instance: None, owner: type[_T]) -> _FnHashable[_P, _R]: ... @overload def __get__(self, instance: _T, owner: type[_T]) -> _FnHashable[_P, _R]: ... - def __get__(self, instance: _T | None, owner: type[_T]) -> _FnHashable[_P, _R]: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... if sys.version_info >= (3, 9): From 6e22af965672bee00695ed4a45c8395bc4105258 Mon Sep 17 00:00:00 2001 From: Marc Edwards Date: Sun, 3 Nov 2024 07:47:35 +0000 Subject: [PATCH 04/15] Fix add version gate for `typing.Concatenate` --- stdlib/functools.pyi | 198 ++++++++++++++++++++++++------------------- 1 file changed, 109 insertions(+), 89 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 581e10dd365f..2e84bbc06c64 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -2,12 +2,15 @@ import sys import types from _typeshed import SupportsAllComparisons, SupportsItems from collections.abc import Callable, Hashable, Iterable, Sequence, Sized -from typing import Any, Concatenate, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload +from typing import Any, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload from typing_extensions import ParamSpec, Self, TypeAlias if sys.version_info >= (3, 9): from types import GenericAlias +if sys.version_info >= (3, 10): + from typing import Concatenate + __all__ = [ "update_wrapper", "wraps", @@ -55,102 +58,133 @@ if sys.version_info >= (3, 9): maxsize: int typed: bool -class _ProtoFunction(Protocol[_P, _R_co]): - def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... +if sys.version_info >= (3, 10): -class _FunctionDescriptor(Protocol[_P, _R]): - __wrapped__: Callable[_P, _R] - def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... - if sys.version_info >= (3, 9): + class _ProtoFunction(Protocol[_P, _R_co]): + def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... + + class _FunctionDescriptor(Protocol[_P, _R]): + __wrapped__: Callable[_P, _R] + def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R: ... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... -class _FnHashable(Protocol[_P, _R]): - __wrapped__: Callable[_P, _R] - def __call__(self, *args: Hashable, **kwds: Hashable) -> _R: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... - if sys.version_info >= (3, 9): + class _FnHashable(Protocol[_P, _R]): + __wrapped__: Callable[_P, _R] + def __call__(self, *args: Hashable, **kwds: Hashable) -> _R: ... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + + class _ProtoMethod(Protocol[_T_contra, _P, _R_co]): + def __call__(__self, self: _T_contra, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... + + class _MethodDescriptor(Protocol[_T, _P, _R]): + __wrapped__: Callable[Concatenate[_T, _P], _R] + def __call__(__self, self: _T, *args: _P.args, **kwds: _P.kwargs) -> _R: ... + @overload + def __get__(self, instance: None, owner: type[_T]) -> Self: ... + @overload + def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... + def cache_parameters(self) -> _CacheParameters: ... -class _ProtoMethod(Protocol[_T_contra, _P, _R_co]): - def __call__(__self, self: _T_contra, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + + class _ProtoClassmethod(Protocol[_T_contra, _P, _R_co]): + def __call__(__self, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... + + class _ClassmethodDescriptor(Protocol[_T, _P, _R]): + __wrapped__: Callable[Concatenate[type[_T], _P], _R] + def __call__(self, cls: type[_T], *args: _P.args, **kwds: _P.kwargs) -> _R: ... + @overload + def __get__(self, instance: None, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... + @overload + def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... + def cache_parameters(self) -> _CacheParameters: ... -class _MethodDescriptor(Protocol[_T, _P, _R]): - __wrapped__: Callable[Concatenate[_T, _P], _R] - def __call__(__self, self: _T, *args: _P.args, **kwds: _P.kwargs) -> _R: ... - @overload - def __get__(self, instance: None, owner: type[_T]) -> Self: ... - @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... - if sys.version_info >= (3, 9): + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + + class _ClsHashable(Protocol[_T, _P, _R]): + __wrapped__: Callable[Concatenate[type[_T], _P], _R] + def __call__(__self, cls: type[_T], *args: Hashable, **kwds: Hashable) -> _R: ... + @overload + def __get__(self, instance: None, owner: type[_T]) -> _FnHashable[_P, _R]: ... + @overload + def __get__(self, instance: _T, owner: type[_T]) -> _FnHashable[_P, _R]: ... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... -class _ProtoClassmethod(Protocol[_T_contra, _P, _R_co]): - def __call__(__self, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... + class _LRUInner(Protocol): + @overload + def __call__(self, fn: _ProtoMethod[_T, _P, _R]) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... + @overload + def __call__(self, fn: _ProtoClassmethod[_T, _P, _R]) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... + @overload + def __call__(self, fn: _ProtoFunction[_P, _R]) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... -class _ClassmethodDescriptor(Protocol[_T, _P, _R]): - __wrapped__: Callable[Concatenate[type[_T], _P], _R] - def __call__(self, cls: type[_T], *args: _P.args, **kwds: _P.kwargs) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... + def lru_cache(maxsize: int | None = 128, typed: bool = False) -> _LRUInner: ... @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... - if sys.version_info >= (3, 9): - def cache_parameters(self) -> _CacheParameters: ... - - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... + def lru_cache( + maxsize: _ProtoMethod[_T, _P, _R], typed: bool = False + ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... + @overload + def lru_cache( + maxsize: _ProtoClassmethod[_T, _P, _R], typed: bool = False + ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... + @overload + def lru_cache(maxsize: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... -class _ClsHashable(Protocol[_T, _P, _R]): - __wrapped__: Callable[Concatenate[type[_T], _P], _R] - def __call__(__self, cls: type[_T], *args: Hashable, **kwds: Hashable) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T]) -> _FnHashable[_P, _R]: ... + def cache( + user_function: _ProtoMethod[_T, _P, _R], typed: bool = False + ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... + @overload + def cache( + user_function: _ProtoClassmethod[_T, _P, _R], typed: bool = False + ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FnHashable[_P, _R]: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... - if sys.version_info >= (3, 9): - def cache_parameters(self) -> _CacheParameters: ... + def cache( + user_function: _ProtoFunction[_P, _R], typed: bool = False + ) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... +else: + @final + class _lru_cache_wrapper(Generic[_T]): + __wrapped__: Callable[..., _T] + def __call__(self, *args: Hashable, **kwargs: Hashable) -> _T: ... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... + if sys.version_info >= (3, 9): + def cache_parameters(self) -> _CacheParameters: ... + + def __copy__(self) -> _lru_cache_wrapper[_T]: ... + def __deepcopy__(self, memo: Any, /) -> _lru_cache_wrapper[_T]: ... -class _LRUInner(Protocol): - @overload - def __call__(self, fn: _ProtoMethod[_T, _P, _R]) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... @overload - def __call__(self, fn: _ProtoClassmethod[_T, _P, _R]) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... + def lru_cache(maxsize: int | None = 128, typed: bool = False) -> Callable[[Callable[..., _T]], _lru_cache_wrapper[_T]]: ... @overload - def __call__(self, fn: _ProtoFunction[_P, _R]) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... + def lru_cache(maxsize: Callable[..., _T], typed: bool = False) -> _lru_cache_wrapper[_T]: ... -@overload -def lru_cache(maxsize: int | None = 128, typed: bool = False) -> _LRUInner: ... -@overload -def lru_cache( - maxsize: _ProtoMethod[_T, _P, _R], typed: bool = False -) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... -@overload -def lru_cache( - maxsize: _ProtoClassmethod[_T, _P, _R], typed: bool = False -) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... -@overload -def lru_cache(maxsize: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... + if sys.version_info >= (3, 9): + def cache(user_function: Callable[..., _T], /) -> _lru_cache_wrapper[_T]: ... if sys.version_info >= (3, 12): WRAPPER_ASSIGNMENTS: tuple[ @@ -282,20 +316,6 @@ class cached_property(Generic[_T_co]): if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... -if sys.version_info >= (3, 9): - @overload - def cache( - user_function: _ProtoMethod[_T, _P, _R], typed: bool = False - ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... - @overload - def cache( - user_function: _ProtoClassmethod[_T, _P, _R], typed: bool = False - ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... - @overload - def cache( - user_function: _ProtoFunction[_P, _R], typed: bool = False - ) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... - def _make_key( args: tuple[Hashable, ...], kwds: SupportsItems[Any, Any], From ab29e6d28130f5b35624c222a13a3e67567c12fe Mon Sep 17 00:00:00 2001 From: Marc Edwards Date: Sun, 3 Nov 2024 07:53:41 +0000 Subject: [PATCH 05/15] Fix match mypy's expected type invariance --- stdlib/functools.pyi | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 2e84bbc06c64..f4a63aef8199 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -86,13 +86,13 @@ if sys.version_info >= (3, 10): class _ProtoMethod(Protocol[_T_contra, _P, _R_co]): def __call__(__self, self: _T_contra, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... - class _MethodDescriptor(Protocol[_T, _P, _R]): - __wrapped__: Callable[Concatenate[_T, _P], _R] - def __call__(__self, self: _T, *args: _P.args, **kwds: _P.kwargs) -> _R: ... + class _MethodDescriptor(Protocol[_T_contra, _P, _R]): + __wrapped__: Callable[Concatenate[_T_contra, _P], _R] + def __call__(__self, self: _T_contra, *args: _P.args, **kwds: _P.kwargs) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T]) -> Self: ... + def __get__(self, instance: None, owner: type[_T_contra]) -> Self: ... @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... + def __get__(self, instance: _T_contra, owner: type[_T_contra]) -> _FunctionDescriptor[_P, _R]: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... @@ -103,13 +103,13 @@ if sys.version_info >= (3, 10): class _ProtoClassmethod(Protocol[_T_contra, _P, _R_co]): def __call__(__self, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... - class _ClassmethodDescriptor(Protocol[_T, _P, _R]): - __wrapped__: Callable[Concatenate[type[_T], _P], _R] - def __call__(self, cls: type[_T], *args: _P.args, **kwds: _P.kwargs) -> _R: ... + class _ClassmethodDescriptor(Protocol[_T_contra, _P, _R]): + __wrapped__: Callable[Concatenate[type[_T_contra], _P], _R] + def __call__(self, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... + def __get__(self, instance: None, owner: type[_T_contra]) -> _FunctionDescriptor[_P, _R]: ... @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... + def __get__(self, instance: _T_contra, owner: type[_T_contra]) -> _FunctionDescriptor[_P, _R]: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... @@ -117,13 +117,13 @@ if sys.version_info >= (3, 10): def __copy__(self) -> Self: ... def __deepcopy__(self, memo: Any, /) -> Self: ... - class _ClsHashable(Protocol[_T, _P, _R]): - __wrapped__: Callable[Concatenate[type[_T], _P], _R] - def __call__(__self, cls: type[_T], *args: Hashable, **kwds: Hashable) -> _R: ... + class _ClsHashable(Protocol[_T_contra, _P, _R]): + __wrapped__: Callable[Concatenate[type[_T_contra], _P], _R] + def __call__(__self, cls: type[_T_contra], *args: Hashable, **kwds: Hashable) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T]) -> _FnHashable[_P, _R]: ... + def __get__(self, instance: None, owner: type[_T_contra]) -> _FnHashable[_P, _R]: ... @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FnHashable[_P, _R]: ... + def __get__(self, instance: _T_contra, owner: type[_T_contra]) -> _FnHashable[_P, _R]: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... From 3cbb7141f430843a86ce088866130e1e7e815b10 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 07:55:23 +0000 Subject: [PATCH 06/15] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/functools.pyi | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index f4a63aef8199..e34d982775aa 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -59,7 +59,6 @@ if sys.version_info >= (3, 9): typed: bool if sys.version_info >= (3, 10): - class _ProtoFunction(Protocol[_P, _R_co]): def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... @@ -69,7 +68,6 @@ if sys.version_info >= (3, 10): def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... def __deepcopy__(self, memo: Any, /) -> Self: ... @@ -79,7 +77,6 @@ if sys.version_info >= (3, 10): def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... def __deepcopy__(self, memo: Any, /) -> Self: ... @@ -96,7 +93,6 @@ if sys.version_info >= (3, 10): def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... def __deepcopy__(self, memo: Any, /) -> Self: ... @@ -113,7 +109,6 @@ if sys.version_info >= (3, 10): def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... def __deepcopy__(self, memo: Any, /) -> Self: ... @@ -127,15 +122,18 @@ if sys.version_info >= (3, 10): def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... def __deepcopy__(self, memo: Any, /) -> Self: ... class _LRUInner(Protocol): @overload - def __call__(self, fn: _ProtoMethod[_T, _P, _R]) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... + def __call__( + self, fn: _ProtoMethod[_T, _P, _R] + ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... @overload - def __call__(self, fn: _ProtoClassmethod[_T, _P, _R]) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... + def __call__( + self, fn: _ProtoClassmethod[_T, _P, _R] + ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... @overload def __call__(self, fn: _ProtoFunction[_P, _R]) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... @@ -151,7 +149,6 @@ if sys.version_info >= (3, 10): ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... @overload def lru_cache(maxsize: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... - @overload def cache( user_function: _ProtoMethod[_T, _P, _R], typed: bool = False From 91f43a29151cf46a90e7f9d444de3ca27ac5f259 Mon Sep 17 00:00:00 2001 From: Marc Edwards Date: Sun, 3 Nov 2024 08:28:11 +0000 Subject: [PATCH 07/15] Fix copy/paste mistake --- stdlib/functools.pyi | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index e34d982775aa..8c20c17388c2 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -150,17 +150,11 @@ if sys.version_info >= (3, 10): @overload def lru_cache(maxsize: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... @overload - def cache( - user_function: _ProtoMethod[_T, _P, _R], typed: bool = False - ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... + def cache(user_function: _ProtoMethod[_T, _P, _R]) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... @overload - def cache( - user_function: _ProtoClassmethod[_T, _P, _R], typed: bool = False - ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... + def cache(user_function: _ProtoClassmethod[_T, _P, _R]) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... @overload - def cache( - user_function: _ProtoFunction[_P, _R], typed: bool = False - ) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... + def cache(user_function: _ProtoFunction[_P, _R]) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... else: @final From 54e4fe01fca651d5a700472fa00b5b1163a7a57c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 08:29:48 +0000 Subject: [PATCH 08/15] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/functools.pyi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 8c20c17388c2..40ec312e385f 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -150,7 +150,9 @@ if sys.version_info >= (3, 10): @overload def lru_cache(maxsize: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... @overload - def cache(user_function: _ProtoMethod[_T, _P, _R]) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... + def cache( + user_function: _ProtoMethod[_T, _P, _R] + ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... @overload def cache(user_function: _ProtoClassmethod[_T, _P, _R]) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... @overload From fd0d180e957347fd7280a7e9fa70bbb8ef86c3c2 Mon Sep 17 00:00:00 2001 From: Marc Edwards Date: Sun, 3 Nov 2024 08:34:34 +0000 Subject: [PATCH 09/15] Fix cache should be positional-only --- stdlib/functools.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 40ec312e385f..df050c5a991f 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -151,12 +151,12 @@ if sys.version_info >= (3, 10): def lru_cache(maxsize: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... @overload def cache( - user_function: _ProtoMethod[_T, _P, _R] + user_function: _ProtoMethod[_T, _P, _R], / ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... @overload - def cache(user_function: _ProtoClassmethod[_T, _P, _R]) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... + def cache(user_function: _ProtoClassmethod[_T, _P, _R], /) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... @overload - def cache(user_function: _ProtoFunction[_P, _R]) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... + def cache(user_function: _ProtoFunction[_P, _R], /) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... else: @final From 3aaf0ff16186ac7bf8542de8102eb81f122a2c60 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 08:36:11 +0000 Subject: [PATCH 10/15] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/functools.pyi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index df050c5a991f..ff826655d27c 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -154,7 +154,9 @@ if sys.version_info >= (3, 10): user_function: _ProtoMethod[_T, _P, _R], / ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... @overload - def cache(user_function: _ProtoClassmethod[_T, _P, _R], /) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... + def cache( + user_function: _ProtoClassmethod[_T, _P, _R], / + ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... @overload def cache(user_function: _ProtoFunction[_P, _R], /) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... From 8c5c4698376838954c94ddb710c821713a5ec570 Mon Sep 17 00:00:00 2001 From: Marc Edwards Date: Sun, 3 Nov 2024 08:44:23 +0000 Subject: [PATCH 11/15] Remove what I think are nolonger needed ignores --- stdlib/@tests/stubtest_allowlists/py310.txt | 1 - stdlib/@tests/stubtest_allowlists/py311.txt | 1 - stdlib/@tests/stubtest_allowlists/py312.txt | 1 - stdlib/@tests/stubtest_allowlists/py313.txt | 1 - 4 files changed, 4 deletions(-) diff --git a/stdlib/@tests/stubtest_allowlists/py310.txt b/stdlib/@tests/stubtest_allowlists/py310.txt index 8d0631cdd291..13ea9d671e8c 100644 --- a/stdlib/@tests/stubtest_allowlists/py310.txt +++ b/stdlib/@tests/stubtest_allowlists/py310.txt @@ -10,7 +10,6 @@ contextlib.AbstractAsyncContextManager.__class_getitem__ contextlib.AbstractContextManager.__class_getitem__ email.contentmanager.typ enum.Enum._generate_next_value_ -functools._lru_cache_wrapper.cache_parameters # Cannot be detected statically gettext.install gettext.translation importlib._abc.Loader.exec_module # See Lib/importlib/_abc.py. Might be defined for backwards compatibility diff --git a/stdlib/@tests/stubtest_allowlists/py311.txt b/stdlib/@tests/stubtest_allowlists/py311.txt index 308855f8f00b..05b8513bbc0a 100644 --- a/stdlib/@tests/stubtest_allowlists/py311.txt +++ b/stdlib/@tests/stubtest_allowlists/py311.txt @@ -129,7 +129,6 @@ builtins.property.__set_name__ # Doesn't actually exist dataclasses.KW_ONLY # white lies around defaults enum.auto.__init__ # The stub for enum.auto is nothing like the implementation enum.auto.value # The stub for enum.auto is nothing like the implementation -functools._lru_cache_wrapper.cache_parameters # Cannot be detected statically http.HTTPMethod.description # mutable instance attribute at runtime but we pretend it's a property inspect._ParameterKind.description # Still exists, but stubtest can't see it os.PathLike.__class_getitem__ # PathLike is a protocol; we don't expect all PathLike classes to implement class_getitem diff --git a/stdlib/@tests/stubtest_allowlists/py312.txt b/stdlib/@tests/stubtest_allowlists/py312.txt index 14500a678fdf..446bdc7cae28 100644 --- a/stdlib/@tests/stubtest_allowlists/py312.txt +++ b/stdlib/@tests/stubtest_allowlists/py312.txt @@ -131,7 +131,6 @@ collections\.UserList\.index # ignoring pos-or-keyword parameter dataclasses.KW_ONLY # white lies around defaults enum.auto.__init__ # The stub for enum.auto is nothing like the implementation enum.auto.value # The stub for enum.auto is nothing like the implementation -functools._lru_cache_wrapper.cache_parameters # Cannot be detected statically http.HTTPMethod.description # mutable instance attribute at runtime but we pretend it's a property inspect._ParameterKind.description # Still exists, but stubtest can't see it os.PathLike.__class_getitem__ # PathLike is a protocol; we don't expect all PathLike classes to implement class_getitem diff --git a/stdlib/@tests/stubtest_allowlists/py313.txt b/stdlib/@tests/stubtest_allowlists/py313.txt index f1dd2471203e..92d19c867e35 100644 --- a/stdlib/@tests/stubtest_allowlists/py313.txt +++ b/stdlib/@tests/stubtest_allowlists/py313.txt @@ -108,7 +108,6 @@ doctest.TestResults.__match_args__ # Stubtest doesn't pick up override doctest.TestResults._fields # Stubtest doesn't pick up override enum.auto.__init__ # The stub for enum.auto is nothing like the implementation enum.auto.value # The stub for enum.auto is nothing like the implementation -functools._lru_cache_wrapper.cache_parameters # Cannot be detected statically http.HTTPMethod.description # mutable instance attribute at runtime but we pretend it's a property inspect._ParameterKind.description # Still exists, but stubtest can't see it os.PathLike.__class_getitem__ # PathLike is a protocol; we don't expect all PathLike classes to implement class_getitem From 28e87fc73f0f6f5a7b255fde91a51de67ff4e710 Mon Sep 17 00:00:00 2001 From: Marc Edwards Date: Sun, 3 Nov 2024 08:46:00 +0000 Subject: [PATCH 12/15] Fix final shouldn't have been removed --- stdlib/functools.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index ff826655d27c..5247a62ceebc 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -2,7 +2,7 @@ import sys import types from _typeshed import SupportsAllComparisons, SupportsItems from collections.abc import Callable, Hashable, Iterable, Sequence, Sized -from typing import Any, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload +from typing import Any, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload, final from typing_extensions import ParamSpec, Self, TypeAlias if sys.version_info >= (3, 9): From 1d1c46a9e3fb2481c95cae5c84b661eaf7edea59 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 08:47:42 +0000 Subject: [PATCH 13/15] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/functools.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 5247a62ceebc..d72ce5563ce5 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -2,7 +2,7 @@ import sys import types from _typeshed import SupportsAllComparisons, SupportsItems from collections.abc import Callable, Hashable, Iterable, Sequence, Sized -from typing import Any, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload, final +from typing import Any, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, final, overload from typing_extensions import ParamSpec, Self, TypeAlias if sys.version_info >= (3, 9): From d705819fbbc74a7b700faf49812a7d5f462a8f2a Mon Sep 17 00:00:00 2001 From: Marc Edwards Date: Sun, 3 Nov 2024 10:14:09 +0000 Subject: [PATCH 14/15] Use type invariance recommended by pyright (which I think is correct) --- stdlib/functools.pyi | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index d72ce5563ce5..bbe141f80600 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -83,13 +83,13 @@ if sys.version_info >= (3, 10): class _ProtoMethod(Protocol[_T_contra, _P, _R_co]): def __call__(__self, self: _T_contra, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... - class _MethodDescriptor(Protocol[_T_contra, _P, _R]): - __wrapped__: Callable[Concatenate[_T_contra, _P], _R] - def __call__(__self, self: _T_contra, *args: _P.args, **kwds: _P.kwargs) -> _R: ... + class _MethodDescriptor(Protocol[_T, _P, _R]): + __wrapped__: Callable[Concatenate[_T, _P], _R] + def __call__(__self, self: _T, *args: _P.args, **kwds: _P.kwargs) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T_contra]) -> Self: ... + def __get__(self, instance: None, owner: type[_T]) -> Self: ... @overload - def __get__(self, instance: _T_contra, owner: type[_T_contra]) -> _FunctionDescriptor[_P, _R]: ... + def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... @@ -99,26 +99,26 @@ if sys.version_info >= (3, 10): class _ProtoClassmethod(Protocol[_T_contra, _P, _R_co]): def __call__(__self, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... - class _ClassmethodDescriptor(Protocol[_T_contra, _P, _R]): - __wrapped__: Callable[Concatenate[type[_T_contra], _P], _R] - def __call__(self, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R: ... + class _ClassmethodDescriptor(Protocol[_T, _P, _R]): + __wrapped__: Callable[Concatenate[type[_T], _P], _R] + def __call__(self, cls: type[_T], *args: _P.args, **kwds: _P.kwargs) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T_contra]) -> _FunctionDescriptor[_P, _R]: ... + def __get__(self, instance: None, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... @overload - def __get__(self, instance: _T_contra, owner: type[_T_contra]) -> _FunctionDescriptor[_P, _R]: ... + def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... def __copy__(self) -> Self: ... def __deepcopy__(self, memo: Any, /) -> Self: ... - class _ClsHashable(Protocol[_T_contra, _P, _R]): - __wrapped__: Callable[Concatenate[type[_T_contra], _P], _R] - def __call__(__self, cls: type[_T_contra], *args: Hashable, **kwds: Hashable) -> _R: ... + class _ClsHashable(Protocol[_T, _P, _R]): + __wrapped__: Callable[Concatenate[type[_T], _P], _R] + def __call__(__self, cls: type[_T], *args: Hashable, **kwds: Hashable) -> _R: ... @overload - def __get__(self, instance: None, owner: type[_T_contra]) -> _FnHashable[_P, _R]: ... + def __get__(self, instance: None, owner: type[_T]) -> _FnHashable[_P, _R]: ... @overload - def __get__(self, instance: _T_contra, owner: type[_T_contra]) -> _FnHashable[_P, _R]: ... + def __get__(self, instance: _T, owner: type[_T]) -> _FnHashable[_P, _R]: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... From 6af921487147f7bee12da2a2b05195db26014cb1 Mon Sep 17 00:00:00 2001 From: Marc Edwards Date: Sun, 3 Nov 2024 18:28:17 +0000 Subject: [PATCH 15/15] Various improvements Simplified implementation now I've got a better understanding of the code --- stdlib/@tests/stubtest_allowlists/py310.txt | 1 + stdlib/@tests/stubtest_allowlists/py311.txt | 1 + stdlib/@tests/stubtest_allowlists/py312.txt | 1 + stdlib/@tests/stubtest_allowlists/py313.txt | 1 + stdlib/functools.pyi | 211 +++++++++----------- 5 files changed, 101 insertions(+), 114 deletions(-) diff --git a/stdlib/@tests/stubtest_allowlists/py310.txt b/stdlib/@tests/stubtest_allowlists/py310.txt index 13ea9d671e8c..8d0631cdd291 100644 --- a/stdlib/@tests/stubtest_allowlists/py310.txt +++ b/stdlib/@tests/stubtest_allowlists/py310.txt @@ -10,6 +10,7 @@ contextlib.AbstractAsyncContextManager.__class_getitem__ contextlib.AbstractContextManager.__class_getitem__ email.contentmanager.typ enum.Enum._generate_next_value_ +functools._lru_cache_wrapper.cache_parameters # Cannot be detected statically gettext.install gettext.translation importlib._abc.Loader.exec_module # See Lib/importlib/_abc.py. Might be defined for backwards compatibility diff --git a/stdlib/@tests/stubtest_allowlists/py311.txt b/stdlib/@tests/stubtest_allowlists/py311.txt index 05b8513bbc0a..308855f8f00b 100644 --- a/stdlib/@tests/stubtest_allowlists/py311.txt +++ b/stdlib/@tests/stubtest_allowlists/py311.txt @@ -129,6 +129,7 @@ builtins.property.__set_name__ # Doesn't actually exist dataclasses.KW_ONLY # white lies around defaults enum.auto.__init__ # The stub for enum.auto is nothing like the implementation enum.auto.value # The stub for enum.auto is nothing like the implementation +functools._lru_cache_wrapper.cache_parameters # Cannot be detected statically http.HTTPMethod.description # mutable instance attribute at runtime but we pretend it's a property inspect._ParameterKind.description # Still exists, but stubtest can't see it os.PathLike.__class_getitem__ # PathLike is a protocol; we don't expect all PathLike classes to implement class_getitem diff --git a/stdlib/@tests/stubtest_allowlists/py312.txt b/stdlib/@tests/stubtest_allowlists/py312.txt index 446bdc7cae28..14500a678fdf 100644 --- a/stdlib/@tests/stubtest_allowlists/py312.txt +++ b/stdlib/@tests/stubtest_allowlists/py312.txt @@ -131,6 +131,7 @@ collections\.UserList\.index # ignoring pos-or-keyword parameter dataclasses.KW_ONLY # white lies around defaults enum.auto.__init__ # The stub for enum.auto is nothing like the implementation enum.auto.value # The stub for enum.auto is nothing like the implementation +functools._lru_cache_wrapper.cache_parameters # Cannot be detected statically http.HTTPMethod.description # mutable instance attribute at runtime but we pretend it's a property inspect._ParameterKind.description # Still exists, but stubtest can't see it os.PathLike.__class_getitem__ # PathLike is a protocol; we don't expect all PathLike classes to implement class_getitem diff --git a/stdlib/@tests/stubtest_allowlists/py313.txt b/stdlib/@tests/stubtest_allowlists/py313.txt index 92d19c867e35..f1dd2471203e 100644 --- a/stdlib/@tests/stubtest_allowlists/py313.txt +++ b/stdlib/@tests/stubtest_allowlists/py313.txt @@ -108,6 +108,7 @@ doctest.TestResults.__match_args__ # Stubtest doesn't pick up override doctest.TestResults._fields # Stubtest doesn't pick up override enum.auto.__init__ # The stub for enum.auto is nothing like the implementation enum.auto.value # The stub for enum.auto is nothing like the implementation +functools._lru_cache_wrapper.cache_parameters # Cannot be detected statically http.HTTPMethod.description # mutable instance attribute at runtime but we pretend it's a property inspect._ParameterKind.description # Still exists, but stubtest can't see it os.PathLike.__class_getitem__ # PathLike is a protocol; we don't expect all PathLike classes to implement class_getitem diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index bbe141f80600..b3a009ac4699 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -2,15 +2,12 @@ import sys import types from _typeshed import SupportsAllComparisons, SupportsItems from collections.abc import Callable, Hashable, Iterable, Sequence, Sized -from typing import Any, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, final, overload -from typing_extensions import ParamSpec, Self, TypeAlias +from typing import Any, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload, type_check_only +from typing_extensions import Concatenate, ParamSpec, Self, TypeAlias if sys.version_info >= (3, 9): from types import GenericAlias -if sys.version_info >= (3, 10): - from typing import Concatenate - __all__ = [ "update_wrapper", "wraps", @@ -58,128 +55,102 @@ if sys.version_info >= (3, 9): maxsize: int typed: bool -if sys.version_info >= (3, 10): - class _ProtoFunction(Protocol[_P, _R_co]): - def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... +class _Method(Protocol[_T_contra, _P, _R_co]): + def __call__(__self, /, self: _T_contra, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... - class _FunctionDescriptor(Protocol[_P, _R]): - __wrapped__: Callable[_P, _R] - def __call__(__self, *args: _P.args, **kwds: _P.kwargs) -> _R: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... - def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... - - class _FnHashable(Protocol[_P, _R]): - __wrapped__: Callable[_P, _R] - def __call__(self, *args: Hashable, **kwds: Hashable) -> _R: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... - def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... - - class _ProtoMethod(Protocol[_T_contra, _P, _R_co]): - def __call__(__self, self: _T_contra, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... - - class _MethodDescriptor(Protocol[_T, _P, _R]): - __wrapped__: Callable[Concatenate[_T, _P], _R] - def __call__(__self, self: _T, *args: _P.args, **kwds: _P.kwargs) -> _R: ... - @overload - def __get__(self, instance: None, owner: type[_T]) -> Self: ... - @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... - def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... - - class _ProtoClassmethod(Protocol[_T_contra, _P, _R_co]): - def __call__(__self, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... - - class _ClassmethodDescriptor(Protocol[_T, _P, _R]): - __wrapped__: Callable[Concatenate[type[_T], _P], _R] - def __call__(self, cls: type[_T], *args: _P.args, **kwds: _P.kwargs) -> _R: ... - @overload - def __get__(self, instance: None, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... - @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... - def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... - - class _ClsHashable(Protocol[_T, _P, _R]): - __wrapped__: Callable[Concatenate[type[_T], _P], _R] - def __call__(__self, cls: type[_T], *args: Hashable, **kwds: Hashable) -> _R: ... - @overload - def __get__(self, instance: None, owner: type[_T]) -> _FnHashable[_P, _R]: ... - @overload - def __get__(self, instance: _T, owner: type[_T]) -> _FnHashable[_P, _R]: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... +class _Classmethod(Protocol[_T_contra, _P, _R_co]): + def __call__(__self, /, cls: type[_T_contra], *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... + +class _Function(Protocol[_P, _R_co]): + def __call__(__self, /, *args: _P.args, **kwds: _P.kwargs) -> _R_co: ... + +class _lru_cache_wrapper(Generic[_P, _R]): + __wrapped__: Callable[_P, _R] + # def __call__(self, *args: Hashable, **kwargs: Hashable) -> _T: ... + def cache_info(self) -> _CacheInfo: ... + def cache_clear(self) -> None: ... + if sys.version_info >= (3, 9): def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... - - class _LRUInner(Protocol): - @overload - def __call__( - self, fn: _ProtoMethod[_T, _P, _R] - ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... - @overload - def __call__( - self, fn: _ProtoClassmethod[_T, _P, _R] - ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... - @overload - def __call__(self, fn: _ProtoFunction[_P, _R]) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + +# Below types are type_check_only. Type +# checkers assume that cache functions +# are descriptors because the cache +# decorators aren't simple pass through +# decorators. At run time the normal method +# binding behavior is applied but type +# checkers don't know, so the below +# descriptor types mirror the normal +# binding behavior but aren't present at runtime. +# Returned objects are still +# _lru_cache_wrapper at runtime. + +# function, staticmethod and bound +# class/instance method descriptor. +@type_check_only +class _FunctionDescriptor(_lru_cache_wrapper[_P, _R]): + def __call__(__self, /, *args: _P.args, **kwds: _P.kwargs) -> _R: ... + +@type_check_only +class _MethodDescriptor(_lru_cache_wrapper[Concatenate[_T, _P], _R], Generic[_T, _P, _R]): + def __call__(__self, /, self: _T, *args: _P.args, **kwds: _P.kwargs) -> _R: ... @overload - def lru_cache(maxsize: int | None = 128, typed: bool = False) -> _LRUInner: ... + def __get__(self, instance: None, owner: type[_T]) -> Self: ... @overload - def lru_cache( - maxsize: _ProtoMethod[_T, _P, _R], typed: bool = False - ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... + def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... + +@type_check_only +class _ClassmethodDescriptor(_lru_cache_wrapper[Concatenate[type[_T], _P], _R], Generic[_T, _P, _R]): + def __call__(self, cls: type[_T], *args: _P.args, **kwds: _P.kwargs) -> _R: ... @overload - def lru_cache( - maxsize: _ProtoClassmethod[_T, _P, _R], typed: bool = False - ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... + def __get__(self, instance: None, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... @overload - def lru_cache(maxsize: _ProtoFunction[_P, _R], typed: bool = False) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... + def __get__(self, instance: _T, owner: type[_T]) -> _FunctionDescriptor[_P, _R]: ... + +# All functions except unbound classmethods +# because @classmethod is typed to expect a function +# with first parameter of type `type[T]` and has +# different binding behavior to __call__. +@type_check_only +class _FunctionHasHashableArgs(_lru_cache_wrapper[_P, _R]): + def __call__(__self, /, *args: Hashable, **kwds: Hashable) -> _R: ... + +@type_check_only +class _ClassmethodHasHashableArgs(_lru_cache_wrapper[Concatenate[type[_T], _P], _R], Generic[_T, _P, _R]): + def __call__(__self, /, cls: type[_T], *args: Hashable, **kwds: Hashable) -> _R: ... @overload - def cache( - user_function: _ProtoMethod[_T, _P, _R], / - ) -> _MethodDescriptor[_T, _P, _R] | _FnHashable[Concatenate[_T, _P], _R]: ... + def __get__(__self, /, instance: None, owner: type[_T]) -> _FunctionHasHashableArgs[_P, _R]: ... @overload - def cache( - user_function: _ProtoClassmethod[_T, _P, _R], / - ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClsHashable[_T, _P, _R]: ... - @overload - def cache(user_function: _ProtoFunction[_P, _R], /) -> _FunctionDescriptor[_P, _R] | _FnHashable[_P, _R]: ... - -else: - @final - class _lru_cache_wrapper(Generic[_T]): - __wrapped__: Callable[..., _T] - def __call__(self, *args: Hashable, **kwargs: Hashable) -> _T: ... - def cache_info(self) -> _CacheInfo: ... - def cache_clear(self) -> None: ... - if sys.version_info >= (3, 9): - def cache_parameters(self) -> _CacheParameters: ... - - def __copy__(self) -> _lru_cache_wrapper[_T]: ... - def __deepcopy__(self, memo: Any, /) -> _lru_cache_wrapper[_T]: ... + def __get__(__self, /, instance: _T, owner: type[_T]) -> _FunctionHasHashableArgs[_P, _R]: ... +class _LruInnerFunction(Protocol): @overload - def lru_cache(maxsize: int | None = 128, typed: bool = False) -> Callable[[Callable[..., _T]], _lru_cache_wrapper[_T]]: ... + def __call__( + self, fn: _Method[_T, _P, _R] + ) -> _MethodDescriptor[_T, _P, _R] | _FunctionHasHashableArgs[Concatenate[_T, _P], _R]: ... @overload - def lru_cache(maxsize: Callable[..., _T], typed: bool = False) -> _lru_cache_wrapper[_T]: ... + def __call__( + self, fn: _Classmethod[_T, _P, _R] + ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClassmethodHasHashableArgs[_T, _P, _R]: ... + @overload + def __call__(self, fn: _Function[_P, _R]) -> _FunctionDescriptor[_P, _R] | _FunctionHasHashableArgs[_P, _R]: ... - if sys.version_info >= (3, 9): - def cache(user_function: Callable[..., _T], /) -> _lru_cache_wrapper[_T]: ... +@overload +def lru_cache(maxsize: int | None = 128, typed: bool = False) -> _LruInnerFunction: ... +@overload +def lru_cache( + maxsize: _Method[_T, _P, _R], typed: bool = False +) -> _MethodDescriptor[_T, _P, _R] | _FunctionHasHashableArgs[Concatenate[_T, _P], _R]: ... +@overload +def lru_cache( + maxsize: _Classmethod[_T, _P, _R], typed: bool = False +) -> _ClassmethodDescriptor[_T, _P, _R] | _ClassmethodHasHashableArgs[_T, _P, _R]: ... +@overload +def lru_cache( + maxsize: _Function[_P, _R], typed: bool = False +) -> _FunctionDescriptor[_P, _R] | _FunctionHasHashableArgs[_P, _R]: ... if sys.version_info >= (3, 12): WRAPPER_ASSIGNMENTS: tuple[ @@ -311,6 +282,18 @@ class cached_property(Generic[_T_co]): if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... +if sys.version_info >= (3, 9): + @overload + def cache( + user_function: _Method[_T, _P, _R], / + ) -> _MethodDescriptor[_T, _P, _R] | _FunctionHasHashableArgs[Concatenate[_T, _P], _R]: ... + @overload + def cache( + user_function: _Classmethod[_T, _P, _R], / + ) -> _ClassmethodDescriptor[_T, _P, _R] | _ClassmethodHasHashableArgs[_T, _P, _R]: ... + @overload + def cache(user_function: _Function[_P, _R], /) -> _FunctionDescriptor[_P, _R] | _FunctionHasHashableArgs[_P, _R]: ... + def _make_key( args: tuple[Hashable, ...], kwds: SupportsItems[Any, Any],