Replies: 2 comments 1 reply
-
For args case you could use typevartuple (pep 646) to describe it. Something like from typing import TypeVar, Protocol, Generic
from typing_extensions import TypeVarTuple, Unpack
R = TypeVar('R')
Ts = TypeVarTuple('Ts')
class TaskFn(Protocol, Generic[R, Ts]):
def apply(self, args: tuple[Unpack[Ts]]) -> R:
...
def task(func: Callable[[Unpack[Ts]], R]) -> TaskFn[R, Ts]:
... I don't see a way to do anything for keyword args. For paramspec currently P.args/P.kwargs are only allowed to be used with *args/**kwags. You can't use them elsewhere. It'd be a bit messy as what happens if you pass both? add.apply(args=(1,), kwargs={"y": 1})
add.apply(args=(1,1), kwargs={"x": 1, "y": 1}) Also how would rules for things like required arguments be handled? Would signature be allowed to use P.args/P.kwargs multiple times if it was allowed for non *args/**kwargs? |
Beta Was this translation helpful? Give feedback.
-
Not sure this is the best place to ask .. but .. supporting this use-case feels like it would be quite useful. Do we think there's a likelihood that support for this might appear at some point? The background tasks use-case is what I'd had in mind and came looking for a discussion around how to type this. There's a Django proposal which is exploring adding a general interface for tasks (django/deps#86) and it would be great if that could be designed from the start to have typing support. |
Beta Was this translation helpful? Give feedback.
-
We now have
ParamSpec
that easily lets you represent the exact signature of an arbitrary function. I'm however curious about a slightly different case, where you have a callable that takes the same arguments as another function, but as separateargs
andkwargs
arguments that aren't unpacked. This is common in task queues, here are some examples:https://docs.celeryq.dev/en/stable/reference/celery.app.task.html#celery.app.task.Task.apply
https://huey.readthedocs.io/en/latest/api.html#TaskWrapper.schedule
https://dramatiq.io/reference.html#dramatiq.Actor.send_with_options
https://python-rq.org/docs/
To elaborate on the first example, the way it works is:
Notice how it's not
add.apply(1, 1)
, because it doesn't unpack the arguments. There is a similar method that does just that: https://docs.celeryq.dev/en/stable/reference/celery.app.task.html#celery.app.task.Task.delay. The latter is easy to type withParamSpec
. You'll just do something likeYou can't type
apply
though, at least not in the most straight forward way ofdef apply(args: P.args, kwargs: P.kwargs): ...
. That's not a valid use location according to theParamSpec
PEP: https://peps.python.org/pep-0612/#id1Is there another way to type this? If not, have there been considerations to expanding on the
ParamSpec
spec to support a case like this?Beta Was this translation helpful? Give feedback.
All reactions