2

I'm using django-rq, the django bindings for python-rq, to try generate a PDF asynchronously. The class TemplateProcesser initializes with two arguments and automatically generates the PDF in the __init__ function. This works fine synchronously, outside of django-rq, but with django-rq it fails with this error:

Error:

AttributeError: type object 'TemplateProcesser' has no attribute 'rsplit'

From this call:

django_rq.enqueue(TemplateProcesser, nail_order=serializer.object, user_photo=base64_image)

Any idea on how to correctly include the uninstantiated class in django-rq?

Class:

class TemplateProcesser(object):

    def __init__(self, nail_order, user_photo, *args, **kwargs):
        self.nail_order = nail_order
        self.user_photo = user_photo
        ...
        self.procces_template()
    ...

StackTrace:

Traceback (most recent call last):
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rq/worker.py", line 426, in perform_job
    rv = job.perform()
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rq/job.py", line 386, in perform
    self._result = self.func(*self.args, **self.kwargs)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rq/job.py", line 154, in func
    return import_attribute(self.func_name)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rq/utils.py", line 168, in import_attribute
    module_name, attribute = name.rsplit('.', 1)
AttributeError: type object 'TemplateProcesser' has no attribute 'rsplit'

Traceback after metaperture's answer:

Traceback (most recent call last):
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/django/views/generic/base.py", line 69, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rest_framework/views.py", line 400, in dispatch
    response = self.handle_exception(exc)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rest_framework/views.py", line 397, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/admin/dev/ncla-web/ncla/api/views.py", line 91, in post
    django_rq.enqueue(self.template_processor_factory, **parameter_dict)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/django_rq/queues.py", line 162, in enqueue
    return get_queue().enqueue(func, *args, **kwargs)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rq/queue.py", line 213, in enqueue
    description=description, depends_on=depends_on)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/django_rq/queues.py", line 42, in enqueue_call
    return self.original_enqueue_call(*args, **kwargs)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/django_rq/queues.py", line 37, in original_enqueue_call
    return super(DjangoRQ, self).enqueue_call(*args, **kwargs)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rq/queue.py", line 176, in enqueue_call
    return self.enqueue_job(job)
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rq/queue.py", line 232, in enqueue_job
    job.save()
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rq/job.py", line 360, in save
    connection.hmset(key, self.dump())
  File "/Users/admin/dev/ncla-web/env/lib/python2.7/site-packages/rq/job.py", line 329, in dump
    obj['data'] = dumps(self.job_tuple)
  File "/Users/admin/dev/ncla-web/env/bin/../lib/python2.7/copy_reg.py", line 70, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle BytesIO objects
agconti
  • 17,780
  • 15
  • 80
  • 114

1 Answers1

0

Looks like python-rq expects a function as the first argument. I would try:

def template_processor_factory(*args, **kwargs):
    return TemplateProcessor(*args, **kwargs)

django_rq.enqueue(template_processer_factory, nail_order=serializer.object,
                  user_photo=base64_image)
s16h
  • 4,647
  • 1
  • 21
  • 33
metaperture
  • 2,393
  • 1
  • 18
  • 19
  • Its a great idea, but I get a `TypeError: can't pickle BytesIO objects`, when its picked and sent to the redis queue. Though i'm not sure what could be BytesIO object thats throwing the error. – agconti May 28 '14 at 22:39
  • I would guess that the BytesIO object is the base64_image--what's it's type? Often IO object like that will have a dump to string that you can use to serialize/serialize on the other side of the queue. – metaperture May 28 '14 at 22:49
  • its a base64 encoded image, so its a `str`. I previously got around the BytesIO with the image by encoding it in this way. – agconti May 28 '14 at 22:50
  • Perhaps it's returning back to a BytesIO object at some point before it should. What's the traceback when you get the TypeError, now? Also, what's the rest of TemplateProcesser? You can also try pickling your class at various stages yourself, now that you know pickling is required. – metaperture May 28 '14 at 22:59
  • updated with traceback. It shouldn't be, its encoded the line before its passed in as in. – agconti May 28 '14 at 23:11
  • additionally, I can tell from the redis worker process the the image is indeed passed in as a base64 encoded string. – agconti May 29 '14 at 14:02