-
Notifications
You must be signed in to change notification settings - Fork 258
TypeVarTuple with Callable and default arguments #1231
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
Comments
Thanks for the thoughtful use case. Yeah, we didn't address this in the PEP. For the above case, Pyre currently uses all the parameters, default or not. So, it expects 3 arguments in So, only one of the possible ways of calling A workaround is to assign the function to a variable of type @mrahtz If that sounds good to you too, we could mention this limitation in the PEP. |
Thanks for the response @pradeep90!
From my experience so far, if a codebase uses functions like Regarding the issues with an implementation, Eric did first mention that The other case would be def func1(cb1: Callable[[*Ts], None]) -> tuple[*Ts]:
...
def func2(x: int, y: int = 0, z: int = 0) -> None: ...
func1(func2) # Type is ambiguous; could be tuple[int] or tuple[int, int] If |
I think I might be missing something here for no one to have brought it up already, but isn't this what from typing import Any, Callable, TypeVar, ParamSpec
P = ParamSpec('P')
def call_later(
cb: Callable[P, Any],
*args: P.args,
**kwargs: P.kwargs,
) -> None: ...
def func1(x: int, y: str, z: float) -> None: ...
call_later(func1, 0, '0', 0.0) # Ok
def func2(x: int, y: str = '0', z: float = 0.0) -> None: ...
call_later(func2, 0) # Ok
call_later(func2, 0, '0') # Ok
call_later(func2, 0, '0', 0.0) # Ok
call_later(func2, 0, 0) # Not ok Or is the point that, sure, it's doable with |
This is only possible if A while back I suggested allowing only |
Oh huh, I didn't realise. Mulling this over, even with potential future extensions, I don't think def func1(cb1: Callable[[*Ts], None], cb2: Callable[[*Ts], None]) -> tuple[*Ts]:
... The question of whether
(And as Eric points out, there's still the issue of what the Even if we did implement some way of using But for the def call_later(cb: Callable[[*Ts], None], *args: *Ts) -> None: ... I'm wondering whether it might be possible to specifying the exact behaviour desired manually with something like: ArgType = *Ts | *tuple[*Ts, T1] | *tuple[*Ts, T1, T2] # | Etc
def call_later(cb: Callable[[ArgType], None], *args: ArgType) -> None: ... So if we want to use that with def func2(x: int, y: str = '0', z: float = 0.0) -> None: ... We could do:
@pradeep90 Am I crazy, or could this work? |
Not fully certain, but wouldn't we need a constraint and nested TypeVarTuple for that? T1 = TypeVar("T1")
T2 = TypeVar("T2")
Ts = TypeVarTuple("Ts")
Tu = TypeVarTuple("Tu", *Ts, *tuple[*Ts, T1], *tuple[*Ts, T1, T2])
def call_later(cb: Callable[[*Tu], None], *args: *Tu) -> None: ... Without |
I think this complexity strongly leans me towards support P.args only / P.kwargs only solution. I'd rather make this legal, def foo(func: Callable[P, object], *args: P.args):
... then work out remaining implications of typevartuple with defaults. Rules here I'd expect is func must not have any required keyword only arguments and that when foo is called it can not have any keyword arguments passed (besides func to allow foo(func=f). |
Previous discussion: microsoft/pyright#3775
I've been playing around with TypeVarTuples recently, in particular together with Callable and args.
https://peps.python.org/pep-0646/#type-variable-tuples-with-callable
One issue became obvious early on which isn't defined in the PEP itself.
A common pattern, especially in async code, is to pass a callable and it's args to a function
That works well if all arguments are required
However, what should happen if
y
andz
have default arguments?Instinctively, I would think that it should work, too. As @erictraut did point out though, there are at least a few cases where the behavior would need to be further specified / or explicitly forbidden.
The text was updated successfully, but these errors were encountered: