| 
					
				 | 
			
			
				@@ -1,5 +1,64 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 """celery.backends.base""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from celery.timer import TimeoutTimer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    import cPickle as pickle 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+except ImportError: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    import pickle 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import sys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def find_nearest_pickleable_exception(exc): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """With an exception instance, iterate over its super classes (by mro) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    and find the first super exception that is pickleable. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :param exc: An exception instance. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :rtype: :exc:`Exception` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for supercls in exc.__class__.mro(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            superexc = supercls(exc.args) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            pickle.dumps(superexc) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        except: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            pass 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return superexc 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return exc 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class UnpickleableExceptionWrapper(Exception): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """Wraps unpickleable exceptions. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :param exc_module: see :attr:`exc_module`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :param exc_cls_name: see :attr:`exc_cls_name`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :param exc_args: The arguments for the original exception. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .. attribute:: exc_module 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        The module of the original exception. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .. attribute:: exc_cls_name 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        The name of the original exception class. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Example 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        >>> try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ...     something_raising_unpickleable_exc() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        >>> except Exception, e: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ...     exc = UnpickleableException(e.__class__.__module__, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ...                                 e.__class__.__name__, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ...                                 e.args) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ...     pickle.dumps(exc) # Works fine. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def __init__(self, exc_module, exc_cls_name, exc_args): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.exc_module = exc_module 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.exc_cls = exc_cls_name 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        super(Exception, self).__init__(exc_module, exc_cls_name, exc_args) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class BaseBackend(object): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -18,6 +77,19 @@ class BaseBackend(object): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         """Mark task as executed with failure. Stores the execption.""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return self.store_result(task_id, exc, status="FAILURE") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def prepare_exception(self, exc): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        exc = find_nearest_pickleable_exception(exc) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            pickle.dumps(exc) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        except pickle.PickleError: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            excwrapper = UnpickleableExceptionWrapper( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            exc.__class__.__module__, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            exc.__class__.__name__, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            exc.args) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return excwrapper 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return exc 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def mark_as_retry(self, task_id, exc): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         """Mark task for retry.""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return self.store_result(task_id, exc, status="RETRY") 
			 |