Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions queue_job/delay.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ class Delayable:
"recordset",
"_graph",
"_job_method",
"_job_method_name",
"_job_args",
"_job_kwargs",
"_generated_job",
Expand Down Expand Up @@ -471,6 +472,7 @@ def __init__(
self.identity_key = identity_key

self._job_method = None
self._job_method_name = ""
self._job_args = ()
self._job_kwargs = {}

Expand All @@ -484,8 +486,7 @@ def _tail(self):

def __repr__(self):
return (
f"Delayable({self.recordset}."
f"{self._job_method.__name__ if self._job_method else ''}"
f"Delayable({self.recordset}.{self._job_method_name}"
f"({self._job_args}, {self._job_kwargs}))"
)

Expand Down Expand Up @@ -548,7 +549,8 @@ def split(self, size, chain=False):
identity_key=self.identity_key,
)
# Update the __self__
delayable._job_method = getattr(recordset, self._job_method.__name__)
delayable._job_method = getattr(recordset, self._job_method_name)
delayable._job_method_name = self._job_method_name
delayable._job_args = self._job_args
delayable._job_kwargs = self._job_kwargs

Expand All @@ -557,7 +559,7 @@ def split(self, size, chain=False):
description = self.description or (
self._job_method.__doc__.splitlines()[0].strip()
if self._job_method.__doc__
else f"{self.recordset._name}.{self._job_method.__name__}"
else f"{self.recordset._name}.{self._job_method_name}"
)
for index, delayable in enumerate(delayables):
delayable.set(
Expand All @@ -574,6 +576,7 @@ def _build_job(self):
return self._generated_job
self._generated_job = Job(
self._job_method,
method_name=self._job_method_name,
args=self._job_args,
kwargs=self._job_kwargs,
priority=self.priority,
Expand All @@ -599,6 +602,10 @@ def __getattr__(self, name):
)
recordset_method = getattr(self.recordset, name)
self._job_method = recordset_method
# Keep the name that was looked up: the method found under it may
# carry another __name__ (e.g. replaced by auditlog), and the job must
# resolve the same attribute again when it is loaded and run.
self._job_method_name = name
return self._store_args

def _execute_direct(self):
Expand Down
9 changes: 7 additions & 2 deletions queue_job/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ def _load_from_db_record(cls, job_db_record):

job_ = cls(
method,
method_name=method_name,
args=args,
kwargs=kwargs,
priority=stored.priority,
Expand Down Expand Up @@ -385,6 +386,7 @@ def __init__(
description=None,
channel=None,
identity_key=None,
method_name=None,
):
"""Create a Job

Expand All @@ -409,6 +411,9 @@ def __init__(
:param identity_key: A hash to uniquely identify a job, or a function
that returns this hash (the function takes the job
as argument)
:param method_name: name of the method on the recordset. Defaults to
``func.__name__``; pass it when the method was
looked up under a different name than its own.
"""
if args is None:
args = ()
Expand All @@ -424,7 +429,7 @@ def __init__(
raise TypeError("Job accepts only methods of Models")

recordset = func.__self__
self.method_name = func.__name__
self.method_name = method_name or func.__name__
self.recordset = recordset

self.job_config = (
Expand Down Expand Up @@ -781,7 +786,7 @@ def description(self):
elif self.func.__doc__:
return self.func.__doc__.splitlines()[0].strip()
else:
return f"{self.model_name}.{self.func.__name__}"
return f"{self.model_name}.{self.method_name}"

@property
def uuid(self):
Expand Down
36 changes: 36 additions & 0 deletions test_queue_job/tests/test_delayable.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
chain,
group,
)
from odoo.addons.queue_job.job import Job


class TestDelayable(common.TransactionCase):
Expand Down Expand Up @@ -308,3 +309,38 @@ def test_delay_job_already_exists(self):
node.on_done(node2).delay()
self.assert_generated_job(node, node2)
self.assert_dependencies({node: {}, node2: {node}})

def _replace_testing_method_under_another_name(self):
"""Put a function named ``testing_method_renamed`` into the
``testing_method`` slot, the way auditlog replaces write and unlink."""
cls = type(self.test_model)
original = cls.testing_method

def testing_method_renamed(self, *args, **kwargs):
return original(self, *args, **kwargs)

self.patch(cls, "testing_method", testing_method_renamed)

def test_delayable_keeps_requested_method_name(self):
self._replace_testing_method_under_another_name()
node = Delayable(self.test_model).testing_method(1)
node.delay()
job = node._generated_job
self.assertEqual(job.method_name, "testing_method")
self.assertEqual(job.db_record().method_name, "testing_method")
# Loading the job resolves the same name again
loaded = Job.load(self.env, job.uuid)
self.assertEqual(loaded.method_name, "testing_method")

def test_with_delay_keeps_requested_method_name(self):
self._replace_testing_method_under_another_name()
job = self.test_model.with_delay().testing_method(1)
self.assertEqual(job.method_name, "testing_method")

def test_delayable_split_keeps_requested_method_name(self):
self._replace_testing_method_under_another_name()
records = self.test_model.create([{"name": "a"}, {"name": "b"}])
group = Delayable(records).testing_method(1).split(1)
group.delay()
for node in group._delayables:
self.assertEqual(node._generated_job.method_name, "testing_method")
Loading