Closed mosmuell closed 1 week ago
A simple implementation of such a decorator is:
import logging
from collections.abc import Callable
from typing import Any, Concatenate, Generic, ParamSpec, TypeVar
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
P = ParamSpec("P")
R = TypeVar("R")
class Task(Generic[P, R]):
def __init__(self, func: Callable[P, R]) -> None:
self._func = func
def start(self, *args: P.args, **kwargs: P.kwargs) -> R:
logger.info("Starting task")
return self._func(*args, **kwargs)
def stop(self) -> None:
logger.info("Stopping task")
class TaskDecorator(Generic[P, R]):
def __init__(
self, func: Callable[Concatenate[Any, P], R], *, autostart: bool
) -> None:
self._func = func
def __get__(self, obj: Any, obj_type: Any) -> Task[P, R]:
# need to use this descriptor to bind the function to the instance of the class
# containing the function
bound_func = self._func.__get__(obj)
return Task(bound_func)
def task(
*,
autostart: bool = True,
) -> Callable[[Callable[Concatenate[Any, P], R]], TaskDecorator[P, R]]:
def task_decorator(func: Callable[Concatenate[Any, P], R]) -> TaskDecorator[P, R]:
return TaskDecorator(func, autostart=autostart)
return task_decorator
class Test:
@task()
def my_task(self, something: str = "") -> str:
print("Inside task")
return something
Is your feature request related to a problem? Please describe. At the moment, every asynchronous function is considered as a task, i.e. start and stop functions will be generated automatically. This poses a couple of problems:
start_
andstop_
functions for each async function.Describe the solution you'd like A solution could be a decorator that turns functions into objects with start and stop methods, e.g.:
Alternatively, tasks could really be instances of a task object.