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

Updated functools.wraps and functools.update_wrapper to use ParamSpec… #6670

Merged
merged 23 commits into from
Feb 26, 2023
Merged
Changes from 13 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
317fe5b
Updated functools.wraps and functools.update_wrapper to use ParamSpec…
msfterictraut Dec 23, 2021
ea7f5cf
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 23, 2021
10900e2
Based on PR feedback, eliminated second ParamSpec and switched to Pro…
msfterictraut Dec 25, 2021
97af48a
Merge branch 'wraps' of https://github.com/erictraut/typeshed into wraps
msfterictraut Dec 25, 2021
e0e7ea2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 25, 2021
3901a15
Trying another attempt to fix wraps. This time, the wrapped function …
msfterictraut Dec 25, 2021
c8374cf
Merge branch 'wraps' of https://github.com/erictraut/typeshed into wraps
msfterictraut Dec 25, 2021
27ddc44
Fixed merge conflict
msfterictraut Dec 25, 2021
dc71f76
Switched back to Generic from Protocol to avoid variance errors.
msfterictraut Dec 25, 2021
2a20846
Merge branch 'master' into wraps
srittau Jan 6, 2022
1d23078
Merge branch 'master' into wraps
JelleZijlstra Jan 29, 2022
2214a68
put wraps back
JelleZijlstra Jan 29, 2022
743f911
Merge branch 'master' into wraps
AlexWaygood Apr 18, 2022
fad24de
Swapped ParamSpecs for `_Wrapped` class and renamed ParamSpecs and Ty…
msfterictraut May 21, 2022
aea60be
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 21, 2022
88d705f
Merge branch 'master' into wraps
AlexWaygood May 25, 2022
1f7fcfc
Merge branch 'master' into wraps
AlexWaygood Sep 13, 2022
823c32d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 13, 2022
4d7dd16
Fix flake8
AlexWaygood Sep 13, 2022
2bab796
Merge branch 'main' into wraps
srittau Nov 1, 2022
88f4904
Merge branch 'main' into wraps
srittau Nov 1, 2022
fb51f0d
Merge branch 'main' into wraps
AlexWaygood Feb 7, 2023
f2aa253
Merge branch 'main' into wraps
AlexWaygood Feb 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions stdlib/functools.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import types
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, TypeAlias, final
from typing_extensions import Literal, ParamSpec, TypeAlias, final

if sys.version_info >= (3, 9):
from types import GenericAlias
Expand Down Expand Up @@ -59,6 +59,10 @@ _AnyCallable: TypeAlias = Callable[..., Any]

_T = TypeVar("_T")
_S = TypeVar("_S")
_P1 = ParamSpec("_P1")
_R1 = TypeVar("_R1")
_P2 = ParamSpec("_P2")
_R2 = TypeVar("_R2")
srittau marked this conversation as resolved.
Show resolved Hide resolved

@overload
def reduce(function: Callable[[_T, _S], _T], sequence: Iterable[_S], initial: _T) -> _T: ...
Expand Down Expand Up @@ -94,8 +98,17 @@ WRAPPER_ASSIGNMENTS: tuple[
]
WRAPPER_UPDATES: tuple[Literal["__dict__"]]

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]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_P2/_R2 are the "wrapper" types. I believe this should read:

Suggested change
__wrapped__: Callable[_P2, _R2]
__wrapped__: Callable[_P1, _R1]

def __call__(self, *args: _P1.args, **kwargs: _P1.kwargs) -> _R2: ...
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the other hand, update_wrapper() doesn't change the wrapper's signature (unless I'm missing something):

from functools import update_wrapper

def wrapper(x: int) -> str:
    return str(x)

def wrapped(y: str, z: bool) -> float:
    return 42.0

wrapper2 = update_wrapper(wrapper, wrapped)

assert wrapper2 is wrapper
print(wrapper(13))
print(wrapper("", True))  # TypeError

Same for wraps():

from functools import wraps

def my_decorator(f):
    @wraps(f)
    def wrapper() -> int:
        return 42
    return wrapper

@my_decorator
def wrapped(x: int) -> bool:
    return True

print(type(wrapped()))  # -> class 'int'
print(type(wrapped(42)))  # TypeError

So this should read:

Suggested change
def __call__(self, *args: _P1.args, **kwargs: _P1.kwargs) -> _R2: ...
def __call__(self, *args: _P2.args, **kwargs: _P2.kwargs) -> _R2: ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Yes, after looking at your examples above, I realize that I had the ParamSpecs swapped in _Wrapped. Now that I've swizzled those, your recommendation for renaming the ParamSpecs makes sense.


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]: ...
srittau marked this conversation as resolved.
Show resolved Hide resolved
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]: ...

Expand Down