diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 3d0fa1036b..4cefd00cac 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -2,12 +2,10 @@ exclude: |
(?x)
# NOT INSTALLABLE ADDONS
^base_import_async/|
- ^queue_job/|
^queue_job_batch/|
^queue_job_cron/|
^queue_job_cron_jobrunner/|
^queue_job_subscribe/|
- ^test_queue_job/|
^test_queue_job_batch/|
# END NOT INSTALLABLE ADDONS
# Files and folders generated by bots, to avoid loops
diff --git a/queue_job/README.rst b/queue_job/README.rst
index 88b5a4d00b..54304cf76f 100644
--- a/queue_job/README.rst
+++ b/queue_job/README.rst
@@ -21,13 +21,13 @@ Job Queue
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fqueue-lightgray.png?logo=github
- :target: https://github.com/OCA/queue/tree/18.0/queue_job
+ :target: https://github.com/OCA/queue/tree/19.0/queue_job
:alt: OCA/queue
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
- :target: https://translation.odoo-community.org/projects/queue-18-0/queue-18-0-queue_job
+ :target: https://translation.odoo-community.org/projects/queue-19-0/queue-19-0-queue_job
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
- :target: https://runboat.odoo-community.org/builds?repo=OCA/queue&target_branch=18.0
+ :target: https://runboat.odoo-community.org/builds?repo=OCA/queue&target_branch=19.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -661,7 +661,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues `_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
-`feedback `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -720,6 +720,6 @@ Current `maintainer `__:
|maintainer-guewen|
-This module is part of the `OCA/queue `_ project on GitHub.
+This module is part of the `OCA/queue `_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/queue_job/__manifest__.py b/queue_job/__manifest__.py
index 70b9774518..4b282af322 100644
--- a/queue_job/__manifest__.py
+++ b/queue_job/__manifest__.py
@@ -2,7 +2,7 @@
{
"name": "Job Queue",
- "version": "18.0.2.0.2",
+ "version": "19.0.1.0.0",
"author": "Camptocamp,ACSONE SA/NV,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/queue",
"license": "LGPL-3",
@@ -27,7 +27,7 @@
"/queue_job/static/src/views/**/*",
],
},
- "installable": False,
+ "installable": True,
"development_status": "Mature",
"maintainers": ["guewen"],
"post_init_hook": "post_init_hook",
diff --git a/queue_job/controllers/main.py b/queue_job/controllers/main.py
index 6365e6efbc..1e265e36bc 100644
--- a/queue_job/controllers/main.py
+++ b/queue_job/controllers/main.py
@@ -280,7 +280,7 @@ def _create_graph_test_jobs(
priority=priority,
max_retries=max_retries,
channel=channel,
- description="%s #%d" % (description, current_count),
+ description=f"{description} #{current_count}",
)._test_job(failure_rate=failure_rate)
)
diff --git a/queue_job/fields.py b/queue_job/fields.py
index 8cb45af765..3940570a84 100644
--- a/queue_job/fields.py
+++ b/queue_job/fields.py
@@ -10,6 +10,7 @@
from odoo import fields, models
from odoo.tools.func import lazy
+from odoo.tools.misc import SENTINEL
class JobSerialized(fields.Json):
@@ -38,7 +39,7 @@ class JobSerialized(fields.Json):
),
}
- def __init__(self, string=fields.SENTINEL, base_type=fields.SENTINEL, **kwargs):
+ def __init__(self, string=SENTINEL, base_type=SENTINEL, **kwargs):
super().__init__(string=string, _base_type=base_type, **kwargs)
def _setup_attrs(self, model, name): # pylint: disable=missing-return
diff --git a/queue_job/job.py b/queue_job/job.py
index 6cfe12f232..a00faace75 100644
--- a/queue_job/job.py
+++ b/queue_job/job.py
@@ -505,7 +505,7 @@ def perform(self):
# traceback and message:
# http://blog.ianbicking.org/2007/09/12/re-raising-exceptions/
new_exc = FailedJobError(
- "Max. retries (%d) reached: %s" % (self.max_retries, value or type_)
+ f"Max. retries ({self.max_retries}) reached: {value or type_}"
)
raise new_exc from err
raise
@@ -813,7 +813,7 @@ def set_failed(self, **kw):
setattr(self, k, v)
def __repr__(self):
- return "" % (self.uuid, self.priority)
+ return f""
def _get_retry_seconds(self, seconds=None):
retry_pattern = self.job_config.retry_pattern
@@ -856,8 +856,7 @@ def related_action(self):
funcname = record._default_related_action
if not isinstance(funcname, str):
raise ValueError(
- "related_action must be the name of the "
- "method on queue.job as string"
+ "related_action must be the name of the method on queue.job as string"
)
action = getattr(record, funcname)
action_kwargs = self.job_config.related_action_kwargs
diff --git a/queue_job/jobrunner/__init__.py b/queue_job/jobrunner/__init__.py
index e2561b0e74..37806465ab 100644
--- a/queue_job/jobrunner/__init__.py
+++ b/queue_job/jobrunner/__init__.py
@@ -17,7 +17,8 @@
else:
queue_job_config = {}
except ImportError:
- queue_job_config = config.misc.get("queue_job", {})
+ # queue_job_config = config.misc.get("queue_job", {})
+ queue_job_config = {} # misc removed from config on Oct 9, 2024
from .runner import QueueJobRunner, _channels
diff --git a/queue_job/jobrunner/channels.py b/queue_job/jobrunner/channels.py
index c895d9caf3..1d65fd808a 100644
--- a/queue_job/jobrunner/channels.py
+++ b/queue_job/jobrunner/channels.py
@@ -455,12 +455,9 @@ def get_subchannel_by_name(self, subchannel_name):
def __str__(self):
capacity = "∞" if self.capacity is None else str(self.capacity)
- return "%s(C:%s,Q:%d,R:%d,F:%d)" % (
- self.fullname,
- capacity,
- len(self._queue),
- len(self._running),
- len(self._failed),
+ return (
+ f"{self.fullname}(C:{capacity},"
+ f"Q:{self._queue},R:{self._running},F:{self._failed})"
)
def remove(self, job):
@@ -894,8 +891,7 @@ def parse_simple_config(cls, config_string):
)
if k in config:
raise ValueError(
- f"Invalid channel config {config_string}: "
- f"duplicate key {k}"
+ f"Invalid channel config {config_string}: duplicate key {k}"
)
config[k] = v
else:
diff --git a/queue_job/models/base.py b/queue_job/models/base.py
index 3a68ffd11b..cc01bca4fb 100644
--- a/queue_job/models/base.py
+++ b/queue_job/models/base.py
@@ -260,11 +260,15 @@ def _job_prepare_context_before_enqueue(self):
if key in self._job_prepare_context_before_enqueue_keys()
}
+ # Odoo have deprecated _patch_method and api.propagate in v16
@classmethod
def _patch_method(cls, name, method):
origin = getattr(cls, name)
method.origin = origin
- # propagate decorators from origin to method, and apply api decorator
- wrapped = api.propagate(origin, method)
- wrapped.origin = origin
- setattr(cls, name, wrapped)
+
+ # propagate appeared to only deal with the returns decorator
+ # which is now, also, deprecated
+ # wrapped = api.propagate(origin, method)
+ # wrapped.origin = origin
+ # setattr(cls, name, wrapped)
+ setattr(cls, name, method)
diff --git a/queue_job/models/queue_job.py b/queue_job/models/queue_job.py
index 411ae43af5..fb8818da02 100644
--- a/queue_job/models/queue_job.py
+++ b/queue_job/models/queue_job.py
@@ -6,7 +6,7 @@
from datetime import datetime, timedelta
from odoo import _, api, exceptions, fields, models
-from odoo.tools import config, html_escape, index_exists
+from odoo.tools import config, html_escape
from odoo.addons.base_sparse_field.models.fields import Serialized
@@ -127,25 +127,20 @@ class QueueJob(models.Model):
worker_pid = fields.Integer(readonly=True)
def init(self):
- index_1 = "queue_job_identity_key_state_partial_index"
- index_2 = "queue_job_channel_date_done_date_created_index"
- if not index_exists(self._cr, index_1):
- # Used by Job.job_record_with_same_identity_key
- self._cr.execute(
+ self.env.cr.execute(
+ "SELECT indexname FROM pg_indexes WHERE indexname = %s ",
+ ("queue_job_identity_key_state_partial_index",),
+ )
+ if not self.env.cr.fetchone():
+ self.env.cr.execute(
"CREATE INDEX queue_job_identity_key_state_partial_index "
"ON queue_job (identity_key) WHERE state in ('pending', "
"'enqueued', 'wait_dependencies') AND identity_key IS NOT NULL;"
)
- if not index_exists(self._cr, index_2):
- # Used by .autovacuum
- self._cr.execute(
- "CREATE INDEX queue_job_channel_date_done_date_created_index "
- "ON queue_job (channel, date_done, date_created);"
- )
@api.depends("dependencies")
def _compute_dependency_graph(self):
- jobs_groups = self.env["queue.job"].read_group(
+ jobs_groups = self.env["queue.job"]._read_group(
[
(
"graph_uuid",
@@ -153,12 +148,10 @@ def _compute_dependency_graph(self):
[uuid for uuid in self.mapped("graph_uuid") if uuid],
)
],
- ["graph_uuid", "ids:array_agg(id)"],
["graph_uuid"],
+ ["id:array_agg"],
)
- ids_per_graph_uuid = {
- group["graph_uuid"]: group["ids"] for group in jobs_groups
- }
+ ids_per_graph_uuid = {group[0]: group[1] for group in jobs_groups}
for record in self:
if not record.graph_uuid:
record.dependency_graph = {}
@@ -216,7 +209,7 @@ def _dependency_graph_vis_node(self):
}
def _compute_graph_jobs_count(self):
- jobs_groups = self.env["queue.job"].read_group(
+ jobs_groups = self.env["queue.job"]._read_group(
[
(
"graph_uuid",
@@ -356,7 +349,7 @@ def _subscribe_users_domain(self):
if not group:
return None
companies = self.mapped("company_id")
- domain = [("groups_id", "=", group.id)]
+ domain = [("group_ids", "=", group.id)]
if companies:
domain.append(("company_id", "in", companies.ids))
return domain
diff --git a/queue_job/models/queue_job_channel.py b/queue_job/models/queue_job_channel.py
index 4aabb0188c..e8b3710feb 100644
--- a/queue_job/models/queue_job_channel.py
+++ b/queue_job/models/queue_job_channel.py
@@ -26,9 +26,10 @@ class QueueJobChannel(models.Model):
default=lambda self: self.env["queue.job"]._removal_interval, required=True
)
- _sql_constraints = [
- ("name_uniq", "unique(complete_name)", "Channel complete name must be unique")
- ]
+ _name_uniq = models.Constraint(
+ "unique(complete_name)",
+ "Channel complete name must be unique",
+ )
@api.depends("name", "parent_id.complete_name")
def _compute_complete_name(self):
diff --git a/queue_job/security/security.xml b/queue_job/security/security.xml
index 947644e95c..f949869c19 100644
--- a/queue_job/security/security.xml
+++ b/queue_job/security/security.xml
@@ -7,9 +7,8 @@
Job Queue Manager
-
diff --git a/queue_job/static/description/index.html b/queue_job/static/description/index.html
index 6cc2121a4d..0e385a33cb 100644
--- a/queue_job/static/description/index.html
+++ b/queue_job/static/description/index.html
@@ -374,7 +374,7 @@ Job Queue
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:58f9182440bb316576671959b69148ea5454958f9ae8db75bccd30c89012676d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-

+

This addon adds an integrated Job Queue to Odoo.
It allows to postpone method calls executed asynchronously.
Jobs are executed in the background by a Jobrunner, in their own
@@ -962,7 +962,7 @@
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
-feedback.
+feedback.
Do not contact contributors directly about support or help with technical issues.
diff --git a/queue_job/tests/common.py b/queue_job/tests/common.py
index ec036bd639..a6792e985d 100644
--- a/queue_job/tests/common.py
+++ b/queue_job/tests/common.py
@@ -9,7 +9,6 @@
from unittest import TestCase, mock
from odoo.tests.case import TestCase as _TestCase
-from odoo.tests.common import MetaCase
from odoo.addons.queue_job.delay import Graph
@@ -212,7 +211,7 @@ def assert_enqueued_job(self, method, args=None, kwargs=None, properties=None):
if expected_call not in actual_calls:
raise AssertionError(
- "Job {} was not enqueued.\n" "Actual enqueued jobs:\n{}".format(
+ "Job {} was not enqueued.\nActual enqueued jobs:\n{}".format(
self._format_job_call(expected_call),
"\n".join(
f" * {self._format_job_call(call)}" for call in actual_calls
@@ -414,7 +413,7 @@ def test_export(self):
yield delayable_cls, delayable
-class OdooDocTestCase(doctest.DocTestCase, _TestCase, MetaCase("DummyCase", (), {})):
+class OdooDocTestCase(doctest.DocTestCase, _TestCase):
"""
We need a custom DocTestCase class in order to:
- define test_tags to run as part of standard tests
diff --git a/queue_job/tests/test_json_field.py b/queue_job/tests/test_json_field.py
index f5bf760ffe..7bd4bdc12b 100644
--- a/queue_job/tests/test_json_field.py
+++ b/queue_job/tests/test_json_field.py
@@ -6,6 +6,7 @@
from lxml import etree
+from odoo import Command
from odoo.tests import common
# pylint: disable=odoo-addons-relative-import
@@ -14,8 +15,23 @@
class TestJson(common.TransactionCase):
+ @classmethod
+ def setUpClass(cls):
+ res = super().setUpClass()
+ company = cls.env.ref("base.main_company")
+ cls.demo_user = cls.env["res.users"].create(
+ {
+ "name": "Demo User",
+ "login": "demo_demo_demo",
+ "company_id": company.id,
+ "company_ids": [Command.set(company.ids)],
+ "group_ids": [Command.set(cls.env.ref("base.group_user").ids)],
+ }
+ )
+ return res
+
def test_encoder_recordset(self):
- demo_user = self.env.ref("base.user_demo")
+ demo_user = self.demo_user
context = demo_user.context_get()
partner = self.env(user=demo_user, context=context).ref("base.main_partner")
value = partner
@@ -33,7 +49,7 @@ def test_encoder_recordset(self):
self.assertEqual(json.loads(value_json), expected)
def test_encoder_recordset_list(self):
- demo_user = self.env.ref("base.user_demo")
+ demo_user = self.demo_user
context = demo_user.context_get()
partner = self.env(user=demo_user, context=context).ref("base.main_partner")
value = ["a", 1, partner]
@@ -55,7 +71,7 @@ def test_encoder_recordset_list(self):
self.assertEqual(json.loads(value_json), expected)
def test_decoder_recordset(self):
- demo_user = self.env.ref("base.user_demo")
+ demo_user = self.demo_user
context = demo_user.context_get()
partner = self.env(user=demo_user).ref("base.main_partner")
@@ -76,7 +92,7 @@ def test_decoder_recordset(self):
self.assertEqual(demo_user, expected.env.user)
def test_decoder_recordset_list(self):
- demo_user = self.env.ref("base.user_demo")
+ demo_user = self.demo_user
context = demo_user.context_get()
partner = self.env(user=demo_user).ref("base.main_partner")
value_json = json.dumps(
@@ -100,7 +116,7 @@ def test_decoder_recordset_list(self):
def test_decoder_recordset_list_without_user(self):
value_json = (
- '["a", 1, {"_type": "odoo_recordset",' '"model": "res.users", "ids": [1]}]'
+ '["a", 1, {"_type": "odoo_recordset","model": "res.users", "ids": [1]}]'
)
expected = ["a", 1, self.env.ref("base.user_root")]
value = json.loads(value_json, cls=JobDecoder, env=self.env)
@@ -132,7 +148,7 @@ def test_encoder_date(self):
self.assertEqual(json.loads(value_json), expected)
def test_decoder_date(self):
- value_json = '["a", 1, {"_type": "date_isoformat",' '"value": "2017-04-19"}]'
+ value_json = '["a", 1, {"_type": "date_isoformat","value": "2017-04-19"}]'
expected = ["a", 1, date(2017, 4, 19)]
value = json.loads(value_json, cls=JobDecoder, env=self.env)
self.assertEqual(value, expected)
diff --git a/queue_job/tests/test_queue_job_protected_write.py b/queue_job/tests/test_queue_job_protected_write.py
index eadb16ab9c..9a3a8eb14c 100644
--- a/queue_job/tests/test_queue_job_protected_write.py
+++ b/queue_job/tests/test_queue_job_protected_write.py
@@ -22,9 +22,6 @@ def test_create_error(self):
"uuid": "test",
},
},
- headers={
- "Cookie": f"session_id={self.session.sid};",
- },
)
self.assertEqual("odoo.exceptions.AccessError", str(cm.exception))
diff --git a/queue_job/views/queue_job_function_views.xml b/queue_job/views/queue_job_function_views.xml
index e725920b2c..4edd2527cc 100644
--- a/queue_job/views/queue_job_function_views.xml
+++ b/queue_job/views/queue_job_function_views.xml
@@ -35,7 +35,7 @@
-
+
-
+