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

functools.partial should use PEP612 ParamSpec (depends on #8708) #8703

Open
benbariteau opened this issue Sep 7, 2022 · 8 comments
Open
Labels
status: deferred Issue or PR deferred until some precondition is fixed

Comments

@benbariteau
Copy link

Currently, functools.partial's __call__ method takes *args: Any, **kwargs: Any and returns _T (a TypeVar for the return type of the callable the partial is wrapping). This is decent, but matching the parameter typing would make this more useful in more situations.

I can sort of see how to deal with this, although I'll admit I'm unsure how to make this generically work. I imagine you could probably deal with some number of Concatenates (maybe up to 5 or 10) to deal with most cases. It's possible fixing this requires another PEP to allow an arbitrary-length Concatenate-type pattern.

Related to python/mypy#1484

@AlexWaygood
Copy link
Member

AlexWaygood commented Sep 7, 2022

You can nearly get there with a combination of PEP 612 and PEP 646:

import sys
from types import GenericAlias
from typing import Any, Callable, Concatenate, Generic, ParamSpec, TypeVar, TypeVarTuple, overload

_P1 = ParamSpec("_P1")
_P2 = ParamSpec("_P2")
_T = TypeVar("_T")
_R_co = TypeVar("_R_co", covariant=True)
_Ts = TypeVarTuple("_Ts")

class partial(Generic[_P1, _P2, _T, _R_co, *_Ts]):
    @overload
    def __new__(cls, __func: Callable[_P1, _R_co]) -> partial[_P1, _P1, Any, _R_co]: ...
    @overload
    def __new__(cls, __func: Callable[Concatenate[*_Ts, _P2], _R_co], *args: *_Ts) -> partial[Concatenate[*_Ts, _P2], _P2, Any, _R_co, *_Ts]: ...
    @overload
    def __new__(cls, __func: Callable[_P1, _R_co], *args: *_Ts, **kwargs: _T) -> partial[_P1, ..., _T, _R_co, *_Ts]: ...
    def __call__(self, *args: _P2.args, **kwargs: _P2.kwargs) -> _R_co: ...
    @property
    def func(self) -> Callable[_P1, _R_co]: ...
    @property
    def args(self) -> tuple[*_Ts]: ...
    @property
    def keywords(self) -> dict[str, _T]: ...
    if sys.version_info >= (3, 9):
        def __class_getitem__(cls, item: Any) -> GenericAlias: ...

Mypy doesn't support PEP 646 yet, however. And even if it did, there would still be some corner cases that don't work (PyCQA/flake8-pyi#150 (comment))

@benbariteau
Copy link
Author

Hmmm, I think that's probably the best we're gonna get for now. It's a strict improvement in my opinion.

@srittau
Copy link
Collaborator

srittau commented Sep 8, 2022

Cf. #8708

@AlexWaygood AlexWaygood added the status: deferred Issue or PR deferred until some precondition is fixed label Sep 14, 2022
@AlexWaygood AlexWaygood changed the title functools.partial should use PEP612 ParamSpec functools.partial should use PEP612 ParamSpec (depends on #8708) Sep 28, 2022
@andersk
Copy link
Contributor

andersk commented Dec 11, 2023

#8708 has been closed. Can this be un-deferred yet?

@AlexWaygood
Copy link
Member

AlexWaygood commented Dec 11, 2023

#8708 has been closed. Can this be un-deferred yet?

No, pytype still crashes (meaning our CI would fail) if we make a class Generic over a TypeVarTuple, which is what the solution outlined in #8703 (comment) would require.

@Dreamsorcerer
Copy link
Contributor

pytype still crashes

Is that the one that has apparently been fixed a couple of days ago: google/pytype#1525 (comment)
Or is there another issue to track?

@AlexWaygood
Copy link
Member

Is that the one that has apparently been fixed a couple of days ago

no

@erikkemperman
Copy link

erikkemperman commented Jul 18, 2024

@AlexWaygood
It would certainly be fantastic if the type annotations for partial captured something about the arguments as well the return type. But are you sure that the approach you outlined above would work, in principle? I didn't think it would be legal to unnpack a TypeVarTuple within Concatenate? I'm not sure if this is just a matter of the checkers not yet implementing it, or if there is some fundamental reason that this could not work, but currently both pyright and mypy disallow this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: deferred Issue or PR deferred until some precondition is fixed
Projects
None yet
Development

No branches or pull requests

6 participants