From 317fe5ba50fb8d9d994fc035b183026c90b2694c Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Wed, 22 Dec 2021 23:59:50 -0700 Subject: [PATCH 01/12] Updated functools.wraps and functools.update_wrapper to use ParamSpec to preserve signatures of wrapped and wrapper functions. --- stdlib/functools.pyi | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 78ed5992a468..168e995f43b7 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -2,7 +2,7 @@ import sys import types from _typeshed import SupportsAllComparisons, SupportsItems from typing import Any, Callable, Generic, Hashable, Iterable, NamedTuple, Sequence, Sized, Tuple, Type, TypeVar, overload -from typing_extensions import final +from typing_extensions import final, ParamSpec if sys.version_info >= (3, 9): from types import GenericAlias @@ -11,7 +11,10 @@ _AnyCallable = Callable[..., Any] _T = TypeVar("_T") _S = TypeVar("_S") - +_P1 = ParamSpec("_P1") +_R1 = TypeVar("_R1") +_P2 = ParamSpec("_P2") +_R2 = TypeVar("_R2") @overload def reduce(function: Callable[[_T, _S], _T], sequence: Iterable[_S], initial: _T) -> _T: ... @overload @@ -42,8 +45,17 @@ else: WRAPPER_ASSIGNMENTS: Sequence[str] WRAPPER_UPDATES: Sequence[str] -def update_wrapper(wrapper: _T, wrapped: _AnyCallable, assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _T: ... -def wraps(wrapped: _AnyCallable, assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> Callable[[_T], _T]: ... +class _Wrapped(Generic[_P1, _R1, _P2, _R2]): + __wrapped__: Callable[_P2, _R2] + def __call__(self, *args: _P1.args, **kwargs: _P1.kwargs) -> _R1: ... + +class _Wrapper(Generic[_P1, _R1]): + def __call__(self, f: Callable[_P2, _R2]) -> _Wrapped[_P1, _R1, _P2, _R2]: ... + +def update_wrapper( + wrapper: Callable[_P2, _R2], wrapped: Callable[_P1, _R1], assigned: Sequence[str] = ..., updated: Sequence[str] = ... +) -> _Wrapped[_P1, _R1, _P2, _R2]: ... +def wraps(wrapped: Callable[_P1, _R1], assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _Wrapper[_P1, _R1]: ... def total_ordering(cls: Type[_T]) -> Type[_T]: ... def cmp_to_key(mycmp: Callable[[_T, _T], int]) -> Callable[[_T], SupportsAllComparisons]: ... From ea7f5cfda1170178fc42cb35252746fa51deaaac Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 23 Dec 2021 07:01:55 +0000 Subject: [PATCH 02/12] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/functools.pyi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 168e995f43b7..1945641d1eb6 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -2,7 +2,7 @@ import sys import types from _typeshed import SupportsAllComparisons, SupportsItems from typing import Any, Callable, Generic, Hashable, Iterable, NamedTuple, Sequence, Sized, Tuple, Type, TypeVar, overload -from typing_extensions import final, ParamSpec +from typing_extensions import ParamSpec, final if sys.version_info >= (3, 9): from types import GenericAlias @@ -15,6 +15,7 @@ _P1 = ParamSpec("_P1") _R1 = TypeVar("_R1") _P2 = ParamSpec("_P2") _R2 = TypeVar("_R2") + @overload def reduce(function: Callable[[_T, _S], _T], sequence: Iterable[_S], initial: _T) -> _T: ... @overload From 10900e2e35b090299914cfe3e58e33bc04f40e05 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 25 Dec 2021 09:06:37 -0700 Subject: [PATCH 03/12] Based on PR feedback, eliminated second ParamSpec and switched to Protocol for _Wrapped and _Wrapper classes. --- stdlib/functools.pyi | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 168e995f43b7..f06c77e5b381 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -1,7 +1,21 @@ import sys import types from _typeshed import SupportsAllComparisons, SupportsItems -from typing import Any, Callable, Generic, Hashable, Iterable, NamedTuple, Sequence, Sized, Tuple, Type, TypeVar, overload +from typing import ( + Any, + Callable, + Generic, + Hashable, + Iterable, + NamedTuple, + Protocol, + Sequence, + Sized, + Tuple, + Type, + TypeVar, + overload, +) from typing_extensions import final, ParamSpec if sys.version_info >= (3, 9): @@ -11,10 +25,9 @@ _AnyCallable = Callable[..., Any] _T = TypeVar("_T") _S = TypeVar("_S") -_P1 = ParamSpec("_P1") -_R1 = TypeVar("_R1") -_P2 = ParamSpec("_P2") -_R2 = TypeVar("_R2") +_P = ParamSpec("_P") +_R = TypeVar("_R", covariant=True) +_C = TypeVar("_C", bound=Callable[..., Any]) @overload def reduce(function: Callable[[_T, _S], _T], sequence: Iterable[_S], initial: _T) -> _T: ... @overload @@ -45,17 +58,17 @@ else: WRAPPER_ASSIGNMENTS: Sequence[str] WRAPPER_UPDATES: Sequence[str] -class _Wrapped(Generic[_P1, _R1, _P2, _R2]): - __wrapped__: Callable[_P2, _R2] - def __call__(self, *args: _P1.args, **kwargs: _P1.kwargs) -> _R1: ... +class _Wrapped(Protocol[_P, _R, _C]): + __wrapped__: _C + def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _R: ... -class _Wrapper(Generic[_P1, _R1]): - def __call__(self, f: Callable[_P2, _R2]) -> _Wrapped[_P1, _R1, _P2, _R2]: ... +class _Wrapper(Protocol[_P, _R]): + def __call__(self, f: _C) -> _Wrapped[_P, _R, _C]: ... def update_wrapper( - wrapper: Callable[_P2, _R2], wrapped: Callable[_P1, _R1], assigned: Sequence[str] = ..., updated: Sequence[str] = ... -) -> _Wrapped[_P1, _R1, _P2, _R2]: ... -def wraps(wrapped: Callable[_P1, _R1], assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _Wrapper[_P1, _R1]: ... + wrapper: _C, wrapped: Callable[_P, _R], assigned: Sequence[str] = ..., updated: Sequence[str] = ... +) -> _Wrapped[_P, _R, _C]: ... +def wraps(wrapped: Callable[_P, _R], assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _Wrapper[_P, _R]: ... def total_ordering(cls: Type[_T]) -> Type[_T]: ... def cmp_to_key(mycmp: Callable[[_T, _T], int]) -> Callable[[_T], SupportsAllComparisons]: ... From e0e7ea2b43e333db931209c756f141384c6a45b8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 25 Dec 2021 16:10:53 +0000 Subject: [PATCH 04/12] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/functools.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index f0078f3a3c30..b28ad70fc6a5 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -28,6 +28,7 @@ _S = TypeVar("_S") _P = ParamSpec("_P") _R = TypeVar("_R", covariant=True) _C = TypeVar("_C", bound=Callable[..., Any]) + @overload def reduce(function: Callable[[_T, _S], _T], sequence: Iterable[_S], initial: _T) -> _T: ... @overload From 3901a151314ea80063329b53bde69984fbcca098 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 25 Dec 2021 10:41:25 -0700 Subject: [PATCH 05/12] Trying another attempt to fix wraps. This time, the wrapped function uses the input signature of the wrapper but the return type of the wrapped. --- stdlib/functools.pyi | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index f0078f3a3c30..6b9685e70755 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -25,9 +25,10 @@ _AnyCallable = Callable[..., Any] _T = TypeVar("_T") _S = TypeVar("_S") -_P = ParamSpec("_P") -_R = TypeVar("_R", covariant=True) -_C = TypeVar("_C", bound=Callable[..., Any]) +_P1 = ParamSpec("_P1") +_R1 = TypeVar("_R1") +_P2 = ParamSpec("_P2") +_R2 = TypeVar("_R2") @overload def reduce(function: Callable[[_T, _S], _T], sequence: Iterable[_S], initial: _T) -> _T: ... @overload @@ -58,17 +59,17 @@ else: WRAPPER_ASSIGNMENTS: Sequence[str] WRAPPER_UPDATES: Sequence[str] -class _Wrapped(Protocol[_P, _R, _C]): - __wrapped__: _C - def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _R: ... +class _Wrapped(Protocol[_P1, _R1, _P2, _R2]): + __wrapped__: Callable[_P2, _R2] + def __call__(self, *args: _P1.args, **kwargs: _P1.kwargs) -> _R2: ... -class _Wrapper(Protocol[_P, _R]): - def __call__(self, f: _C) -> _Wrapped[_P, _R, _C]: ... +class _Wrapper(Protocol[_P1, _R1]): + def __call__(self, f: Callable[_P2, _R2]) -> _Wrapped[_P1, _R1, _P2, _R2]: ... def update_wrapper( - wrapper: _C, wrapped: Callable[_P, _R], assigned: Sequence[str] = ..., updated: Sequence[str] = ... -) -> _Wrapped[_P, _R, _C]: ... -def wraps(wrapped: Callable[_P, _R], assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _Wrapper[_P, _R]: ... + wrapper: Callable[_P2, _R2], wrapped: Callable[_P1, _R1], assigned: Sequence[str] = ..., updated: Sequence[str] = ... +) -> _Wrapped[_P1, _R1, _P2, _R2]: ... +def wraps(wrapped: Callable[_P1, _R1], assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _Wrapper[_P1, _R1]: ... def total_ordering(cls: Type[_T]) -> Type[_T]: ... def cmp_to_key(mycmp: Callable[[_T, _T], int]) -> Callable[[_T], SupportsAllComparisons]: ... From 27ddc44ad713eab3b4a73a8463e4fa808598a098 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 25 Dec 2021 10:48:18 -0700 Subject: [PATCH 06/12] Fixed merge conflict --- stdlib/functools.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index d9af4cb2a4da..7330329aead1 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -26,7 +26,7 @@ _AnyCallable = Callable[..., Any] _T = TypeVar("_T") _S = TypeVar("_S") _P1 = ParamSpec("_P1") -_R = TypeVar("_R", covariant=True) +_R1 = TypeVar("_R1", covariant=True) _P2 = ParamSpec("_P2") _R2 = TypeVar("_R2", contravariant=True) From dc71f767b4a94033c726c8a3757136a42bd59ea5 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 25 Dec 2021 10:51:50 -0700 Subject: [PATCH 07/12] Switched back to Generic from Protocol to avoid variance errors. --- stdlib/functools.pyi | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index 7330329aead1..2814608e014b 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -1,21 +1,7 @@ import sys import types from _typeshed import SupportsAllComparisons, SupportsItems -from typing import ( - Any, - Callable, - Generic, - Hashable, - Iterable, - NamedTuple, - Protocol, - Sequence, - Sized, - Tuple, - Type, - TypeVar, - overload, -) +from typing import Any, Callable, Generic, Hashable, Iterable, NamedTuple, Sequence, Sized, Tuple, Type, TypeVar, overload from typing_extensions import ParamSpec, final if sys.version_info >= (3, 9): @@ -26,9 +12,9 @@ _AnyCallable = Callable[..., Any] _T = TypeVar("_T") _S = TypeVar("_S") _P1 = ParamSpec("_P1") -_R1 = TypeVar("_R1", covariant=True) +_R1 = TypeVar("_R1") _P2 = ParamSpec("_P2") -_R2 = TypeVar("_R2", contravariant=True) +_R2 = TypeVar("_R2") @overload def reduce(function: Callable[[_T, _S], _T], sequence: Iterable[_S], initial: _T) -> _T: ... @@ -60,11 +46,11 @@ else: WRAPPER_ASSIGNMENTS: Sequence[str] WRAPPER_UPDATES: Sequence[str] -class _Wrapped(Protocol[_P1, _R1, _P2, _R2]): +class _Wrapped(Generic[_P1, _R1, _P2, _R2]): __wrapped__: Callable[_P2, _R2] def __call__(self, *args: _P1.args, **kwargs: _P1.kwargs) -> _R2: ... -class _Wrapper(Protocol[_P1, _R1]): +class _Wrapper(Generic[_P1, _R1]): def __call__(self, f: Callable[_P2, _R2]) -> _Wrapped[_P1, _R1, _P2, _R2]: ... def update_wrapper( From 2214a68bb8889b98462831e163e453851eafbda5 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 28 Jan 2022 20:38:06 -0800 Subject: [PATCH 08/12] put wraps back --- stdlib/functools.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index bec77981cf59..75ac3835caa0 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -58,6 +58,7 @@ class _Wrapper(Generic[_P1, _R1]): def update_wrapper( wrapper: Callable[_P2, _R2], wrapped: Callable[_P1, _R1], assigned: Sequence[str] = ..., updated: Sequence[str] = ... ) -> _Wrapped[_P1, _R1, _P2, _R2]: ... +def wraps(wrapped: Callable[_P1, _R1], assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _Wrapper[_P1, _R1]: ... def total_ordering(cls: type[_T]) -> type[_T]: ... def cmp_to_key(mycmp: Callable[[_T, _T], int]) -> Callable[[_T], SupportsAllComparisons]: ... From fad24de0ff11d7ae87348455994a64ee667d7c19 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 21 May 2022 14:36:35 -0700 Subject: [PATCH 09/12] Swapped ParamSpecs for `_Wrapped` class and renamed ParamSpecs and TypeVars for clarity. --- stdlib/functools.pyi | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index dbd7f89a0244..e66c3401e484 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -59,10 +59,10 @@ _AnyCallable: TypeAlias = Callable[..., Any] _T = TypeVar("_T") _S = TypeVar("_S") -_P1 = ParamSpec("_P1") -_R1 = TypeVar("_R1") -_P2 = ParamSpec("_P2") -_R2 = TypeVar("_R2") +_PWrapped = ParamSpec("_PWrapped") +_RWrapped = TypeVar("_RWrapped") +_PWrapper = ParamSpec("_PWrapper") +_RWapper = TypeVar("_RWapper") @overload def reduce(function: Callable[[_T, _S], _T], sequence: Iterable[_S], initial: _T) -> _T: ... @@ -98,17 +98,17 @@ WRAPPER_ASSIGNMENTS: tuple[ ] WRAPPER_UPDATES: tuple[Literal["__dict__"]] -class _Wrapped(Generic[_P1, _R1, _P2, _R2]): - __wrapped__: Callable[_P2, _R2] - def __call__(self, *args: _P1.args, **kwargs: _P1.kwargs) -> _R2: ... +class _Wrapped(Generic[_PWrapped, _RWrapped, _PWrapper, _RWapper]): + __wrapped__: Callable[_PWrapped, _RWrapped] + def __call__(self, *args: _PWrapper.args, **kwargs: _PWrapper.kwargs) -> _RWapper: ... -class _Wrapper(Generic[_P1, _R1]): - def __call__(self, f: Callable[_P2, _R2]) -> _Wrapped[_P1, _R1, _P2, _R2]: ... +class _Wrapper(Generic[_PWrapped, _RWrapped]): + def __call__(self, f: Callable[_PWrapper, _RWapper]) -> _Wrapped[_PWrapped, _RWrapped, _PWrapper, _RWapper]: ... def update_wrapper( - wrapper: Callable[_P2, _R2], wrapped: Callable[_P1, _R1], assigned: Sequence[str] = ..., updated: Sequence[str] = ... -) -> _Wrapped[_P1, _R1, _P2, _R2]: ... -def wraps(wrapped: Callable[_P1, _R1], assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _Wrapper[_P1, _R1]: ... + wrapper: Callable[_PWrapper, _RWapper], wrapped: Callable[_PWrapped, _RWrapped], assigned: Sequence[str] = ..., updated: Sequence[str] = ... +) -> _Wrapped[_PWrapped, _RWrapped, _PWrapper, _RWapper]: ... +def wraps(wrapped: Callable[_PWrapped, _RWrapped], assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _Wrapper[_PWrapped, _RWrapped]: ... def total_ordering(cls: type[_T]) -> type[_T]: ... def cmp_to_key(mycmp: Callable[[_T, _T], int]) -> Callable[[_T], SupportsAllComparisons]: ... From aea60be183b2cdcab2c4656d2d8502c8d8b1bbb9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 21 May 2022 21:37:52 +0000 Subject: [PATCH 10/12] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/functools.pyi | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index e66c3401e484..c28277850083 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -106,9 +106,14 @@ class _Wrapper(Generic[_PWrapped, _RWrapped]): def __call__(self, f: Callable[_PWrapper, _RWapper]) -> _Wrapped[_PWrapped, _RWrapped, _PWrapper, _RWapper]: ... def update_wrapper( - wrapper: Callable[_PWrapper, _RWapper], wrapped: Callable[_PWrapped, _RWrapped], assigned: Sequence[str] = ..., updated: Sequence[str] = ... + wrapper: Callable[_PWrapper, _RWapper], + wrapped: Callable[_PWrapped, _RWrapped], + assigned: Sequence[str] = ..., + updated: Sequence[str] = ..., ) -> _Wrapped[_PWrapped, _RWrapped, _PWrapper, _RWapper]: ... -def wraps(wrapped: Callable[_PWrapped, _RWrapped], assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _Wrapper[_PWrapped, _RWrapped]: ... +def wraps( + wrapped: Callable[_PWrapped, _RWrapped], assigned: Sequence[str] = ..., updated: Sequence[str] = ... +) -> _Wrapper[_PWrapped, _RWrapped]: ... def total_ordering(cls: type[_T]) -> type[_T]: ... def cmp_to_key(mycmp: Callable[[_T, _T], int]) -> Callable[[_T], SupportsAllComparisons]: ... From 823c32d04cf9b8bd46628ec4d9f44d60ed607711 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 Sep 2022 15:32:45 +0000 Subject: [PATCH 11/12] [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 255d074067a6..ca4377e856c3 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -1,6 +1,6 @@ import sys import types -from _typeshed import IdentityFunction, Self, SupportsAllComparisons, SupportsItems +from _typeshed import Self, SupportsAllComparisons, SupportsItems from collections.abc import Callable, Hashable, Iterable, Sequence, Sized from typing import Any, Generic, NamedTuple, TypeVar, overload from typing_extensions import Literal, ParamSpec, TypeAlias, final From 4d7dd16f637c035931e2a9bfd5f4958fc63372db Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 13 Sep 2022 16:38:11 +0100 Subject: [PATCH 12/12] Fix flake8 --- stdlib/functools.pyi | 2 -- 1 file changed, 2 deletions(-) diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index ca4377e856c3..52c08a1ef643 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -28,8 +28,6 @@ if sys.version_info >= (3, 8): if sys.version_info >= (3, 9): __all__ += ["cache"] -_AnyCallable: TypeAlias = Callable[..., object] - _T = TypeVar("_T") _S = TypeVar("_S") _PWrapped = ParamSpec("_PWrapped")