diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 3d0fa1036..4cefd00ca 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 88b5a4d00..54304cf76 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 70b977451..4b282af32 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 6365e6efb..1e265e36b 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 8cb45af76..3940570a8 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 6cfe12f23..a00faace7 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 e2561b0e7..37806465a 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 c895d9caf..1d65fd808 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 3a68ffd11..cc01bca4f 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 411ae43af..fb8818da0 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 4aabb0188..e8b3710fe 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 947644e95..f949869c1 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 6cc2121a4..0e385a33c 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 ec036bd63..a6792e985 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 f5bf760ff..7bd4bdc12 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 eadb16ab9..9a3a8eb14 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 e725920b2..4edd2527c 100644
--- a/queue_job/views/queue_job_function_views.xml
+++ b/queue_job/views/queue_job_function_views.xml
@@ -35,7 +35,7 @@
-
+
-
+