Merge lp:~acsone-openerp/openerp-connector/7.0-connector-parameterized-job-desciption into lp:~openerp-connector-core-editors/openerp-connector/7.0

Proposed by Laurent Mignon (Acsone)
Status: Merged
Merged at revision: 598
Proposed branch: lp:~acsone-openerp/openerp-connector/7.0-connector-parameterized-job-desciption
Merge into: lp:~openerp-connector-core-editors/openerp-connector/7.0
Diff against target: 155 lines (+39/-8)
3 files modified
connector/CHANGES.rst (+3/-0)
connector/queue/job.py (+16/-7)
connector/tests/test_job.py (+20/-1)
To merge this branch: bzr merge lp:~acsone-openerp/openerp-connector/7.0-connector-parameterized-job-desciption
Reviewer Review Type Date Requested Status
Stéphane Bidoul (Acsone) (community) Approve
Guewen Baconnier @ Camptocamp code review Approve
Review via email: mp+195572@code.launchpad.net

Description of the change

Improve Job description
=======================

Jobs are tasks to execute later. While the functionality is really robust and performs well, it is not always easy for the end user to visually distinguish the purpose of a job in the list of jobs. The description displayed in the list is computed from the documentation of the delayed function or from its name and there is no way to particularize this message by job instance.

This proposal aims to address this limitation by adding to the delay function a new optional parameter 'description'. The description given in the call to the delay function is used and displayed for the description of the job instead of the default one.

This proposal is backward compatible.

To post a comment you must log in.
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

This is a very interesting improvement and well done!
Thanks

review: Approve (code review)
Revision history for this message
Laurent Mignon (Acsone) (lmi) wrote :

It's nice to contribute ;-)

On Mon, Nov 18, 2013 at 11:29 AM, Guewen Baconnier @ Camptocamp <
<email address hidden>> wrote:

> Review: Approve code review
>
> This is a very interesting improvement and well done!
> Thanks
> --
>
> https://code.launchpad.net/~acsone-openerp/openerp-connector/7.0-connector-parameterized-job-desciption/+merge/195572
> Your team Acsone OpenErp Team is subscribed to branch
> lp:~acsone-openerp/openerp-connector/7.0-connector-parameterized-job-desciption.
>

--
*Laurent Mignon*
*Senior Software Engineer*

*Tel : +352 20 21 10 20 32*
*Fax : +352 20 21 10 21*
*Gsm : +352 691 506 009*
*Email: <email address hidden> <email address hidden>*

*Acsone SA, Succursale de Luxembourg*
*22, Zone industrielle*
*L-8287 Kehlen, Luxembourg*
*www.acsone.eu <http://www.acsone.eu>*

Revision history for this message
David BEAL (ak) (davidbeal) wrote :

Good idea,

But perhaps we may use 'description' argument as complement of self.func.__doc__ or 'Function %s' and not instead of

Revision history for this message
Stéphane Bidoul (Acsone) (sbi) wrote :

This is working quite nicely in production already.

Nitpicking:
- * description : a human description of the job
+ * description : a human-readable description of the job,
+ intended to discriminate job instances

review: Approve
600. By Laurent Mignon (Acsone)

little doc improvement as suggested by Stéphane Bidoul (Acsone) (sbi)

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

David Beal:
> Good idea,
>
> But perhaps we may use 'description' argument as complement of
> self.func.__doc__ or 'Function %s' and not instead of

Perhaps can you precise what you have in mind with some examples?
Appending them would give somewhat weird results (redundancy, unrelated messages).

We must keep things simple, this proposal stays simple while still allowing to fully customize the job descriptions. That's why a totally support it.

Laurent Mignon
> It's nice to contribute ;-)

Even more when the contribution is scrupulous about details (including tests, docs, ...) :-)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'connector/CHANGES.rst'
--- connector/CHANGES.rst 2013-10-09 18:52:36 +0000
+++ connector/CHANGES.rst 2013-11-18 14:29:22 +0000
@@ -4,6 +4,9 @@
42.0.1.dev042.0.1.dev0
5~~~~~~~~~~5~~~~~~~~~~
66
7* Add a new optional keyword argument 'description' to the delay function of a job. If given, the description is used as name of the queue.job model stored in OpenErp
8and displayed in the list of jobs.
9
72.0.1 (2013-09-12)102.0.1 (2013-09-12)
8~~~~~~~~~~~~~~~~~~11~~~~~~~~~~~~~~~~~~
912
1013
=== modified file 'connector/queue/job.py'
--- connector/queue/job.py 2013-10-28 15:17:17 +0000
+++ connector/queue/job.py 2013-11-18 14:29:22 +0000
@@ -102,9 +102,9 @@
102 "Model %s not found" % self._job_model_name)102 "Model %s not found" % self._job_model_name)
103103
104 def enqueue(self, func, model_name=None, args=None, kwargs=None,104 def enqueue(self, func, model_name=None, args=None, kwargs=None,
105 priority=None, eta=None, max_retries=None):105 priority=None, eta=None, max_retries=None, description=None):
106 job = Job(func=func, model_name=model_name, args=args, kwargs=kwargs,106 job = Job(func=func, model_name=model_name, args=args, kwargs=kwargs,
107 priority=priority, eta=eta, max_retries=max_retries)107 priority=priority, eta=eta, max_retries=max_retries, description=description)
108 job.user_id = self.session.uid108 job.user_id = self.session.uid
109 self.store(job)109 self.store(job)
110110
@@ -114,12 +114,14 @@
114 eta = kwargs.pop('eta', None)114 eta = kwargs.pop('eta', None)
115 model_name = kwargs.pop('model_name', None)115 model_name = kwargs.pop('model_name', None)
116 max_retries = kwargs.pop('max_retries', None)116 max_retries = kwargs.pop('max_retries', None)
117 description = kwargs.pop('description', None)
117118
118 return self.enqueue(func, model_name=model_name,119 return self.enqueue(func, model_name=model_name,
119 args=args, kwargs=kwargs,120 args=args, kwargs=kwargs,
120 priority=priority,121 priority=priority,
121 max_retries=max_retries,122 max_retries=max_retries,
122 eta=eta)123 eta=eta,
124 description=description)
123125
124 def exists(self, job_uuid):126 def exists(self, job_uuid):
125 """Returns if a job still exists in the storage."""127 """Returns if a job still exists in the storage."""
@@ -229,7 +231,7 @@
229 eta = datetime.strptime(stored.eta, DEFAULT_SERVER_DATETIME_FORMAT)231 eta = datetime.strptime(stored.eta, DEFAULT_SERVER_DATETIME_FORMAT)
230232
231 job = Job(func=func_name, args=args, kwargs=kwargs,233 job = Job(func=func_name, args=args, kwargs=kwargs,
232 priority=stored.priority, eta=eta, job_uuid=stored.uuid)234 priority=stored.priority, eta=eta, job_uuid=stored.uuid, description=stored.name)
233235
234 if stored.date_created:236 if stored.date_created:
235 job.date_created = datetime.strptime(237 job.date_created = datetime.strptime(
@@ -360,7 +362,7 @@
360362
361 def __init__(self, func=None, model_name=None,363 def __init__(self, func=None, model_name=None,
362 args=None, kwargs=None, priority=None,364 args=None, kwargs=None, priority=None,
363 eta=None, job_uuid=None, max_retries=None):365 eta=None, job_uuid=None, max_retries=None, description=None):
364 """ Create a Job366 """ Create a Job
365367
366 :param func: function to execute368 :param func: function to execute
@@ -379,6 +381,8 @@
379 :param job_uuid: UUID of the job381 :param job_uuid: UUID of the job
380 :param max_retries: maximum number of retries before giving up and set382 :param max_retries: maximum number of retries before giving up and set
381 the job state to 'failed'. A value of 0 means infinite retries.383 the job state to 'failed'. A value of 0 means infinite retries.
384 :param description: human description of the job. If None, description
385 is computed from the function doc or name
382 """386 """
383 if args is None:387 if args is None:
384 args = ()388 args = ()
@@ -423,6 +427,7 @@
423 self.priority = DEFAULT_PRIORITY427 self.priority = DEFAULT_PRIORITY
424428
425 self.date_created = datetime.now()429 self.date_created = datetime.now()
430 self._description = description
426 self.date_enqueued = None431 self.date_enqueued = None
427 self.date_started = None432 self.date_started = None
428 self.date_done = None433 self.date_done = None
@@ -483,7 +488,7 @@
483488
484 @property489 @property
485 def description(self):490 def description(self):
486 return self.func.__doc__ or 'Function %s' % self.func.__name__491 return self._description or self.func.__doc__ or 'Function %s' % self.func.__name__
487492
488 @property493 @property
489 def uuid(self):494 def uuid(self):
@@ -597,7 +602,7 @@
597 Arguments and keyword arguments which will be given to the called602 Arguments and keyword arguments which will be given to the called
598 function once the job is executed. They should be ``pickle-able``.603 function once the job is executed. They should be ``pickle-able``.
599604
600 There is 3 special and reserved keyword arguments that you can use:605 There is 4 special and reserved keyword arguments that you can use:
601606
602 * priority: priority of the job, the smaller is the higher priority.607 * priority: priority of the job, the smaller is the higher priority.
603 Default is 10.608 Default is 10.
@@ -606,6 +611,10 @@
606 infinite retries. Default is 5.611 infinite retries. Default is 5.
607 * eta: the job can be executed only after this datetime612 * eta: the job can be executed only after this datetime
608 (or now + timedelta if a timedelta or integer is given)613 (or now + timedelta if a timedelta or integer is given)
614
615 * description : a human description of the job,
616 intended to discriminate job instances
617 (Default is the func.__doc__ or 'Function %s' % func.__name__)
609618
610 Example:619 Example:
611620
612621
=== modified file 'connector/tests/test_job.py'
--- connector/tests/test_job.py 2013-03-04 12:22:57 +0000
+++ connector/tests/test_job.py 2013-11-18 14:29:22 +0000
@@ -20,6 +20,8 @@
2020
2121
22def task_a(session, model_name):22def task_a(session, model_name):
23 """ Task description
24 """
23 pass25 pass
2426
2527
@@ -76,6 +78,22 @@
76 result = job.perform(self.session)78 result = job.perform(self.session)
77 self.assertEqual(result, 'ok!')79 self.assertEqual(result, 'ok!')
7880
81 def test_description(self):
82 """ If no description is given to the job, it
83 should be computed from the function
84 """
85 # if a doctstring is defined for the function
86 # it's used as description
87 job_a = Job(func=task_a)
88 self.assertEqual(job_a.description, task_a.__doc__)
89 # if no docstring, the description is computed
90 job_b = Job(func=task_b)
91 self.assertEqual(job_b.description, "Function task_b")
92 # case when we explicitly specify the description
93 description = "My description"
94 job_a = Job(func=task_a, description=description)
95 self.assertEqual(job_a.description, description)
96
79 def test_retryable_error(self):97 def test_retryable_error(self):
80 job = Job(func=retryable_error_task,98 job = Job(func=retryable_error_task,
81 max_retries=3)99 max_retries=3)
@@ -112,7 +130,8 @@
112 args=('o', 'k'),130 args=('o', 'k'),
113 kwargs={'c': '!'},131 kwargs={'c': '!'},
114 priority=15,132 priority=15,
115 eta=eta)133 eta=eta,
134 description="My description")
116 job.user_id = 1135 job.user_id = 1
117 storage = OpenERPJobStorage(self.session)136 storage = OpenERPJobStorage(self.session)
118 storage.store(job)137 storage.store(job)