-
Notifications
You must be signed in to change notification settings - Fork 282
Description
I would like to use ParamSpec to type a function that accepts a Callable[P, Any] and *args which will be passed to the callable. The function itself does not accept keyword arguments. As an example, AbstractEventLoop.call_soon behaves similar. This is the current Typeshed definition
def call_soon(self, callback: Callable[..., Any], *args: Any) -> Handle: ...typeshed -> stdlib/asyncio/events.pyi -> AbstractEventLoop
P = ParamSpec("P")
def call_soon(self, callback: Callable[P, Any], *args: P.args) -> Handle: ...Intuitively adding a ParamSpec variable like this would make sense: "Only except *args. If any arguments are passed, they need to match those of the callback." I would also expect that if callback has required arguments, they need to be passed with *args to call_soon.
The issue here is that PEP 612 explicitly forbids specifying P.args or P.kwargs alone. They always need to be together.
https://www.python.org/dev/peps/pep-0612/#id2
Furthermore, because the default kind of parameter in Python ((x: int)) may be addressed
both positionally and through its name, two valid invocations of a (*args: P.args, **kwargs: P.kwargs)
function may give different partitions of the same set of parameters. Therefore, we need to make
sure that these special types are only brought into the world together, and are used together,
so that our usage is valid for all possible partitions.
I do wonder if this strict limitation makes sense or if there are other ways to work around it so the case described above could be supported. After all it's similar to adding **kwargs to the function signature without ever passing keyword arguments.
def call_soon(self, callback: Callable[P, Any], *args: P.args, **kwargs: P.kwargs) -> Handle: ...