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.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
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