Browse Source

Using Exception.args to serialize/deserialize exceptions instead of str(Exception) (#4085)

* Using Exception.args for serializetion

* backwards compat

* Fixed exception creating

* Fixed typo

* Test fix

* backwards fixes

* Formatting

* Formatting and exception_to_python fix

* Tests fix

* Fixed exception deserialization

* formatting
Alexander Ovechkin 7 years ago
parent
commit
bd347f7565
2 changed files with 17 additions and 5 deletions
  1. 14 4
      celery/backends/base.py
  2. 3 1
      t/unit/backends/test_base.py

+ 14 - 4
celery/backends/base.py

@@ -29,7 +29,7 @@ from celery._state import get_current_task
 from celery.exceptions import (
     ChordError, TimeoutError, TaskRevokedError, ImproperlyConfigured,
 )
-from celery.five import items, string
+from celery.five import items
 from celery.result import (
     GroupResult, ResultBase, allow_join_result, result_from_tuple,
 )
@@ -237,14 +237,24 @@ class Backend(object):
         serializer = self.serializer if serializer is None else serializer
         if serializer in EXCEPTION_ABLE_CODECS:
             return get_pickleable_exception(exc)
-        return {'exc_type': type(exc).__name__, 'exc_message': string(exc)}
+        return {'exc_type': type(exc).__name__,
+                'exc_message': exc.args,
+                'exc_module': type(exc).__module__}
 
     def exception_to_python(self, exc):
         """Convert serialized exception to Python exception."""
         if exc:
             if not isinstance(exc, BaseException):
-                exc = create_exception_cls(
-                    from_utf8(exc['exc_type']), __name__)(exc['exc_message'])
+                exc_module = exc.get('exc_module')
+                if exc_module is None:
+                    cls = create_exception_cls(
+                        from_utf8(exc['exc_type']), __name__)
+                else:
+                    exc_module = from_utf8(exc_module)
+                    exc_type = from_utf8(exc['exc_type'])
+                    cls = getattr(sys.modules[exc_module], exc_type)
+                exc_msg = exc['exc_message']
+                exc = cls(*exc_msg if isinstance(exc_msg, tuple) else exc_msg)
             if self.serializer in EXCEPTION_ABLE_CODECS:
                 exc = get_pickled_exception(exc)
         return exc

+ 3 - 1
t/unit/backends/test_base.py

@@ -142,7 +142,9 @@ class test_prepare_exception:
     def test_unicode_message(self):
         message = u'\u03ac'
         x = self.b.prepare_exception(Exception(message))
-        assert x == {'exc_message': message, 'exc_type': 'Exception'}
+        assert x == {'exc_message': (message,),
+                     'exc_type': Exception.__name__,
+                     'exc_module': Exception.__module__}
 
 
 class KVBackend(KeyValueStoreBackend):