using super in celery task

541 views Asked by At

I have some base class like:

class Auto(object):
    _year = None
    _base_price = None

    @classmethod
    def calculate_price(cls):
        return cls._base_price + 5000 * (2016 - cls._year)

class BMW(Auto):
    _year = 2015
    _base_price = 40000

    @celery.task(filter=task_method,
             name='queue_name',
             base=basetask(), bind=True)
    def calculate_price(self):
        super(BMW, self).calculate_price()

So, my problem is with the last line of code, it raises: TypeError: super(type, obj): obj must be an instance or subtype of type

I was trying to remove bind=True and play a little with it, but with no results. Any ideas how to fix this issue?

UPDATE: where

celery = Celery(...)

so, I'm using decorator like app.task

1

There are 1 answers

0
Armando Pérez Marqués On

You are mixing two styles of methods: Class methods (@classmethod), and instance methods (def calculate_price(self):).

I haven't really tried this in code, but what about:

class Auto(object):
    _year = None
    _base_price = None

    @classmethod
    def calculate_price(cls):
        return cls._base_price + 5000 * (2016 - cls._year)

class BMW(Auto):
    _year = 2015
    _base_price = 40000

    @celery.task(filter=task_method, name='queue_name', base=basetask(), bind=True)
    @classmethod
    def calculate_price(cls, task_self):
        super(BMW, cls).calculate_price()

So the @classmethod decorator is applied first to def calculate_price(...):, and then the @celery.task is applied to the class method.

If you do need calculate_price() to be an instance method, then the signature could be def calculate_price(self, task_self): but you need to apply the decorator when you already have an instance, like:

my_car = BMW()
celery.task(my_car.calculate_price)

When you access a method using instance<dot>method you don't get the function you wrote, you get a method descriptor that when called, it will take care of fill out the first argument (self) leaving to you filling the remaining arguments. In this case, is only the task_self argument, and the @celery.task decorator will take care of that one.

In any case, I think you should step back, and rethink your problem in a more generic way instead of figuring out how to tie class/instance methods to Celery. In general, Celery tasks should be just functions living in a module inside your application, which accept parameters that can be easily serialized using JSON.