Bläddra i källkod

Task.app is now backwars compatible again

Ask Solem 13 år sedan
förälder
incheckning
27c6107f9e
2 ändrade filer med 39 tillägg och 3 borttagningar
  1. 24 0
      celery/__compat__.py
  2. 15 3
      celery/app/task/__init__.py

+ 24 - 0
celery/__compat__.py

@@ -71,3 +71,27 @@ def get_compat(app, pkg, name, bases=(ModuleType, )):
                     for name, attr in modules[pkg.__name__][name].iteritems())
     sys.modules[fqdn] = module = type(name, bases, attrs)(fqdn)
     return module
+
+
+class class_property(object):
+
+    def __init__(self, fget=None, fset=None):
+        assert fget and isinstance(fget, classmethod)
+        assert fset and isinstance(fset, classmethod)
+        self.__get = fget
+        self.__set = fset
+
+        info = fget.__get__(object)  # just need the info attrs.
+        self.__doc__ = info.__doc__
+        self.__name__ = info.__name__
+        self.__module__ = info.__module__
+
+    def __get__(self, obj, type=None):
+        if obj and type is None:
+            type = obj.__class__
+        return self.__get.__get__(obj, type)()
+
+    def __set__(self, obj, value):
+        if obj is None:
+            return self
+        return self.__set.__get__(obj)(value)

+ 15 - 3
celery/app/task/__init__.py

@@ -17,6 +17,7 @@ import threading
 
 from ... import current_app
 from ... import states
+from ...__compat__ import class_property
 from ...datastructures import ExceptionInfo
 from ...exceptions import MaxRetriesExceededError, RetryTaskError
 from ...result import EagerResult
@@ -303,6 +304,8 @@ class BaseTask(object):
     #: The type of task *(no longer used)*.
     type = "regular"
 
+    __bound__ = False
+
     from_config = (
         ("exchange_type", "CELERY_DEFAULT_EXCHANGE_TYPE"),
         ("delivery_mode", "CELERY_DEFAULT_DELIVERY_MODE"),
@@ -320,6 +323,12 @@ class BaseTask(object):
     # - Tasks are lazily bound, so that configuration is not set
     # - until the task is actually used
 
+    @classmethod
+    def _maybe_bind(cls, app):
+        if not cls.__bound__:
+            cls.__bound__ = True
+            return cls.bind(app)
+
     @classmethod
     def bind(cls, app):
         cls._app = app
@@ -348,14 +357,17 @@ class BaseTask(object):
 
     @classmethod
     def _get_app(cls):
-        if cls._app is None:
-            cls.bind(current_app)
+        if cls._app is None or not cls.__bound__:
+            # if app is set on the class, then the app descriptors
+            # __set__  method is not called, and the cls must
+            # be bound later.
+            cls._maybe_bind(current_app)
         return cls._app
 
     @classmethod
     def _set_app(cls, app):
         cls.bind(app)
-    app = property(_get_app, _set_app)
+    app = class_property(_get_app, _set_app)
 
     # - tasks are pickled into the name of the task only, and the reciever
     # - simply grabs it from the local registry.