|  | @@ -21,6 +21,7 @@ from kombu.utils import cached_property
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  from celery import current_app
 | 
	
		
			
				|  |  |  from celery import states
 | 
	
		
			
				|  |  | +from celery.__compat__ import class_property
 | 
	
		
			
				|  |  |  from celery.datastructures import ExceptionInfo
 | 
	
		
			
				|  |  |  from celery.exceptions import MaxRetriesExceededError, RetryTaskError
 | 
	
		
			
				|  |  |  from celery.result import EagerResult
 | 
	
	
		
			
				|  | @@ -304,8 +305,9 @@ class BaseTask(object):
 | 
	
		
			
				|  |  |      # - Tasks are lazily bound, so that configuration is not set
 | 
	
		
			
				|  |  |      # - until the task is actually used
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    @classmethod
 | 
	
		
			
				|  |  |      def bind(self, app):
 | 
	
		
			
				|  |  | -        self.__bound__ = True
 | 
	
		
			
				|  |  | +        was_bound, self.__bound__ = self.__bound__, True
 | 
	
		
			
				|  |  |          self._app = app
 | 
	
		
			
				|  |  |          conf = app.conf
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -319,25 +321,46 @@ class BaseTask(object):
 | 
	
		
			
				|  |  |              self.backend = app.backend
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          # decorate with annotations from config.
 | 
	
		
			
				|  |  | -        self.annotate()
 | 
	
		
			
				|  |  | +        if not was_bound:
 | 
	
		
			
				|  |  | +            self.annotate()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          # PeriodicTask uses this to add itself to the PeriodicTask schedule.
 | 
	
		
			
				|  |  |          self.on_bound(app)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          return app
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    @classmethod
 | 
	
		
			
				|  |  |      def on_bound(self, app):
 | 
	
		
			
				|  |  |          """This method can be defined to do additional actions when the
 | 
	
		
			
				|  |  |          task class is bound to an app."""
 | 
	
		
			
				|  |  |          pass
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    @classmethod
 | 
	
		
			
				|  |  |      def _get_app(self):
 | 
	
		
			
				|  |  |          if not self.__bound__ or self._app is None:
 | 
	
		
			
				|  |  |              # The app property's __set__  method is not called
 | 
	
		
			
				|  |  |              # if Task.app is set (on the class), so must bind on use.
 | 
	
		
			
				|  |  |              self.bind(current_app)
 | 
	
		
			
				|  |  |          return self._app
 | 
	
		
			
				|  |  | -    app = property(_get_app, bind)
 | 
	
		
			
				|  |  | +    app = class_property(_get_app, bind)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @classmethod
 | 
	
		
			
				|  |  | +    def annotate(self):
 | 
	
		
			
				|  |  | +        for d in resolve_all_annotations(self.app.annotations, self):
 | 
	
		
			
				|  |  | +            for key, value in d.iteritems():
 | 
	
		
			
				|  |  | +                if key.startswith('@'):
 | 
	
		
			
				|  |  | +                    self.add_around(key[1:], value)
 | 
	
		
			
				|  |  | +                else:
 | 
	
		
			
				|  |  | +                    setattr(self, key, value)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @classmethod
 | 
	
		
			
				|  |  | +    def add_around(self, attr, around):
 | 
	
		
			
				|  |  | +        orig = getattr(self, attr)
 | 
	
		
			
				|  |  | +        if getattr(orig, "__wrapped__", None):
 | 
	
		
			
				|  |  | +            orig = orig.__wrapped__
 | 
	
		
			
				|  |  | +        meth = around(orig)
 | 
	
		
			
				|  |  | +        meth.__wrapped__ = orig
 | 
	
		
			
				|  |  | +        setattr(self, attr, meth)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def __call__(self, *args, **kwargs):
 | 
	
		
			
				|  |  |          return self.run(*args, **kwargs)
 | 
	
	
		
			
				|  | @@ -682,13 +705,12 @@ class BaseTask(object):
 | 
	
		
			
				|  |  |                                          if key in supported_keys)
 | 
	
		
			
				|  |  |              kwargs.update(extend_with)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        tb = None
 | 
	
		
			
				|  |  |          retval, info = eager_trace_task(task, task_id, args, kwargs,
 | 
	
		
			
				|  |  |                                          request=request, propagate=throw)
 | 
	
		
			
				|  |  |          if isinstance(retval, ExceptionInfo):
 | 
	
		
			
				|  |  | -            retval = retval.exception
 | 
	
		
			
				|  |  | -        state, tb = states.SUCCESS, ''
 | 
	
		
			
				|  |  | -        if info is not None:
 | 
	
		
			
				|  |  | -            state, tb = info.state, info.strtb
 | 
	
		
			
				|  |  | +            retval, tb = retval.exception, retval.traceback
 | 
	
		
			
				|  |  | +        state = states.SUCCESS if info is None else info.state
 | 
	
		
			
				|  |  |          return EagerResult(task_id, retval, state, traceback=tb)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def AsyncResult(self, task_id):
 | 
	
	
		
			
				|  | @@ -823,11 +845,6 @@ class BaseTask(object):
 | 
	
		
			
				|  |  |          """
 | 
	
		
			
				|  |  |          request.execute_using_pool(pool, loglevel, logfile)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    def annotate(self):
 | 
	
		
			
				|  |  | -        for d in resolve_all_annotations(self.app.annotations, self):
 | 
	
		
			
				|  |  | -            for key, value in d.iteritems():
 | 
	
		
			
				|  |  | -                setattr(self, key, value)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      def __repr__(self):
 | 
	
		
			
				|  |  |          """`repr(task)`"""
 | 
	
		
			
				|  |  |          return "<@task: %s>" % (self.name, )
 |