diff --git a/stdlib/@tests/test_cases/check_functools.py b/stdlib/@tests/test_cases/check_functools.py index e3b90ab5743f..d3aaf5ca1c4d 100644 --- a/stdlib/@tests/test_cases/check_functools.py +++ b/stdlib/@tests/test_cases/check_functools.py @@ -122,6 +122,17 @@ def check_lru_cache_with_maxsize(x: int) -> int: assert_type(check_lru_cache_with_maxsize.cache_info().misses, int) +def check_cache_keys() -> None: + def size(*, self: list[int]) -> int: + return len(self) + + disabled = lru_cache(maxsize=0)(size) + assert_type(disabled(self=[]), int) + assert_type(lru_cache(False, typed=True)(size)(self=[]), int) + cache(size)(self=[]) # type: ignore[arg-type] + lru_cache(1)(size)(self=[]) # type: ignore[arg-type] + + # # Tests for @cached_property # diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 6c8ab541fe48..42041befd999 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -46,6 +46,7 @@ _PWrapper = ParamSpec("_PWrapper") _RWrapper = TypeVar("_RWrapper") _WrapperSelfT = TypeVar("_WrapperSelfT") _PBound = ParamSpec("_PBound") +_CacheArgT_contra = TypeVar("_CacheArgT_contra", contravariant=True, default=Hashable) if sys.version_info >= (3, 14): @overload @@ -69,19 +70,23 @@ class _CacheParameters(TypedDict): typed: bool @final -class _lru_cache_wrapper(Generic[_T_co]): +class _lru_cache_wrapper(Generic[_T_co, _CacheArgT_contra]): __wrapped__: Callable[..., _T_co] - def __call__(self, *args: Hashable, **kwargs: Hashable) -> _T_co: ... + def __call__(self, /, *args: _CacheArgT_contra, **kwargs: _CacheArgT_contra) -> _T_co: ... def cache_info(self) -> _CacheInfo: ... def cache_clear(self) -> None: ... def cache_parameters(self) -> _CacheParameters: ... - def __copy__(self) -> _lru_cache_wrapper[_T_co]: ... - def __deepcopy__(self, memo: Any, /) -> _lru_cache_wrapper[_T_co]: ... + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... # as with ``Callable``, we'll assume that these attributes exist __name__: str __qualname__: str +@overload +def lru_cache( + maxsize: Literal[0, False], typed: bool = False +) -> Callable[[Callable[..., _T]], _lru_cache_wrapper[_T, object]]: ... @overload def lru_cache(maxsize: int | None = 128, typed: bool = False) -> Callable[[Callable[..., _T]], _lru_cache_wrapper[_T]]: ... @overload