From 0503eb28291dfe10714da78b30fa5c019ebabf34 Mon Sep 17 00:00:00 2001 From: Vincent Driessen Date: Sat, 28 Jan 2012 09:00:02 +0100 Subject: [PATCH] Clarified responsibility of the Job class. The Job itself has nothing to do with queueing and dequeueing, so the DequeueError wasn't appropriate here, either. --- rq/exceptions.py | 4 ++++ rq/job.py | 24 ++++++++++++------------ tests/test_job.py | 38 +++++++++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/rq/exceptions.py b/rq/exceptions.py index 979d4f7..9880cd6 100644 --- a/rq/exceptions.py +++ b/rq/exceptions.py @@ -1,5 +1,9 @@ class NoQueueError(Exception): pass +class UnpickleError(Exception): + pass + class DequeueError(Exception): pass + diff --git a/rq/job.py b/rq/job.py index 4b58105..ff9effd 100644 --- a/rq/job.py +++ b/rq/job.py @@ -1,24 +1,25 @@ from pickle import loads -from .exceptions import DequeueError +from .exceptions import UnpickleError class Job(object): """A Job is just a convenient datastructure to pass around job (meta) data. """ - __slots__ = ['func', 'args', 'kwargs', 'rv_key', 'origin'] - @classmethod def unpickle(cls, pickle_data): """Constructs a Job instance form the given pickle'd job tuple data.""" try: - job_tuple = loads(pickle_data) - return Job(job_tuple) - except (AttributeError, ValueError, IndexError): - raise DequeueError('Could not decode job tuple.') - - def __init__(self, job_tuple, origin=None): - self.func, self.args, self.kwargs, self.rv_key = job_tuple - self.origin = origin + return loads(pickle_data) + except (AttributeError, IndexError, TypeError): + raise UnpickleError('Could not decode job tuple.') + + def __init__(self, func, *args, **kwargs): + self.func = func + self.args = args + self.kwargs = kwargs + self.rv_key = None + self.origin = None + self.timestamp = None def perform(self): """Invokes the job function with the job arguments. @@ -38,4 +39,3 @@ class Job(object): def __str__(self): return '' % self.call_string - diff --git a/tests/test_job.py b/tests/test_job.py index 3fef909..460f015 100644 --- a/tests/test_job.py +++ b/tests/test_job.py @@ -1,11 +1,43 @@ from tests import RQTestCase -#from pickle import loads, dumps +from pickle import dumps, loads +from rq.job import Job #from rq import Queue, Worker -#from rq.exceptions import DequeueError +from rq.exceptions import UnpickleError + + +def arbitrary_function(x, y, z=1): + return x * y / z class TestJob(RQTestCase): def test_create_job(self): """Creation of jobs.""" - pass + job = Job(arbitrary_function, 3, 4, z=2) + self.assertEquals(job.func, arbitrary_function) + self.assertEquals(job.args, (3, 4)) + self.assertEquals(job.kwargs, {'z': 2}) + self.assertIsNone(job.origin) + self.assertIsNone(job.timestamp) + self.assertIsNone(job.rv_key) + + def test_pickle_job(self): + """Pickling of jobs.""" + job = Job(arbitrary_function, 3, 4, z=2) + job2 = loads(dumps(job)) + self.assertEquals(job.func, job2.func) + self.assertEquals(job.args, job2.args) + self.assertEquals(job.kwargs, job2.kwargs) + + def test_unpickle_errors(self): + """Handling of unpickl'ing errors.""" + with self.assertRaises(UnpickleError): + Job.unpickle('this is no pickle data') + + with self.assertRaises(UnpickleError): + Job.unpickle(13) + + pickle_data = dumps(Job(arbitrary_function, 2, 3)) + corrupt_data = pickle_data.replace('arbitrary', 'b0rken') + with self.assertRaises(UnpickleError): + Job.unpickle(corrupt_data)