From 922b74e445c7a895f3d2e022633a73028f70ef93 Mon Sep 17 00:00:00 2001 From: Charles Leifer Date: Thu, 11 Jan 2024 11:02:03 -0600 Subject: [PATCH] Clarify docs slightly on revoked behavior, clean up code. Fixes #784 --- docs/api.rst | 19 +++++++++++++++++++ huey/api.py | 11 ++++++++++- huey/tests/test_api.py | 9 +++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index b8209a0a..90bbb13a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -731,6 +731,25 @@ Huey object .. py:method:: is_revoked(task, timestamp=None) + :param task: either a task instance, a task ID, a Result, or a Task class. + + This method should rarely need to be called directly. Typically you + should rather use the ``is_revoked`` method on the object that is being + revoked, for example: + + .. code-block:: python + + @huey.task() + def greet(name): + return 'Hello %s' % name + + r = greet.schedule(delay=60, args=('Huey',)) + r.revoke() # Revoke this task. + r.is_revoked() # True. + + greet.revoke() # Revoke ALL invocations of this task. + greet.is_revoked() # True. + .. seealso:: For task instances, use :py:meth:`Result.is_revoked`. diff --git a/huey/api.py b/huey/api.py index db392dfc..b0f41591 100644 --- a/huey/api.py +++ b/huey/api.py @@ -514,11 +514,15 @@ def _task_key(self, task_class, key): return ':'.join((key, self._registry.task_to_string(task_class))) def revoke_all(self, task_class, revoke_until=None, revoke_once=False): + if isinstance(task_class, TaskWrapper): + task_class = task_class.task_class if revoke_until is not None: revoke_until = normalize_time(revoke_until, utc=self.utc) self.put(self._task_key(task_class, 'rt'), (revoke_until, revoke_once)) def restore_all(self, task_class): + if isinstance(task_class, TaskWrapper): + task_class = task_class.task_class return self.delete(self._task_key(task_class, 'rt')) def revoke(self, task, revoke_until=None, revoke_once=False): @@ -563,6 +567,8 @@ def _check_revoked(self, revoke_id, timestamp=None, peek=True): return True, False def is_revoked(self, task, timestamp=None, peek=True): + if isinstance(task, TaskWrapper): + task = task.task_class if inspect.isclass(task) and issubclass(task, Task): key = self._task_key(task, 'rt') is_revoked, can_restore = self._check_revoked(key, timestamp, peek) @@ -570,7 +576,9 @@ def is_revoked(self, task, timestamp=None, peek=True): self.restore_all(task) return is_revoked - if not isinstance(task, Task): + if isinstance(task, Result): + task = task.task + elif not isinstance(task, Task): # Assume we've been given a task ID. task = Task(id=task) @@ -951,6 +959,7 @@ def my_task(a, b): def __init__(self, huey, task): self.huey = huey self.task = task + self.revoke_id = task.revoke_id self._result = EmptyData def __repr__(self): diff --git a/huey/tests/test_api.py b/huey/tests/test_api.py index 99d75933..4ea8b044 100644 --- a/huey/tests/test_api.py +++ b/huey/tests/test_api.py @@ -176,6 +176,10 @@ def task_a(n): # The result-wrapper will indicate the tasks are revoked. for r in (r1, r2, r3): self.assertTrue(r.is_revoked()) + self.assertTrue(self.huey.is_revoked(r)) + # We don't have the task class when using an ID so this doesn't + # work. + self.assertFalse(self.huey.is_revoked(r.task.id)) # Task is discarded and not executed, due to being revoked. t1 = self.huey.dequeue() @@ -218,6 +222,11 @@ def task_a(n): self.assertFalse(r2.is_revoked()) self.assertTrue(r3.is_revoked()) + self.assertTrue(self.huey.is_revoked(r1)) + self.assertTrue(self.huey.is_revoked(r1.task.id)) + self.assertFalse(self.huey.is_revoked(r2)) + self.assertFalse(self.huey.is_revoked(r2.task.id)) + # Task is discarded and not executed, due to being revoked. t1 = self.huey.dequeue() self.assertTrue(self.huey.execute(t1) is None)