/usr/lib/python3/dist-packages/celery/utils/serialization.py is in python3-celery 3.1.20-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | # -*- coding: utf-8 -*-
"""
celery.utils.serialization
~~~~~~~~~~~~~~~~~~~~~~~~~~
Utilities for safely pickling exceptions.
"""
from __future__ import absolute_import
from inspect import getmro
from itertools import takewhile
try:
import cPickle as pickle
except ImportError:
import pickle # noqa
from .encoding import safe_repr
__all__ = ['UnpickleableExceptionWrapper', 'subclass_exception',
'find_pickleable_exception', 'create_exception_cls',
'get_pickleable_exception', 'get_pickleable_etype',
'get_pickled_exception']
#: List of base classes we probably don't want to reduce to.
try:
unwanted_base_classes = (StandardError, Exception, BaseException, object)
except NameError: # pragma: no cover
unwanted_base_classes = (Exception, BaseException, object) # py3k
def subclass_exception(name, parent, module): # noqa
return type(name, (parent, ), {'__module__': module})
def find_pickleable_exception(exc, loads=pickle.loads,
dumps=pickle.dumps):
"""With an exception instance, iterate over its super classes (by mro)
and find the first super exception that is pickleable. It does
not go below :exc:`Exception` (i.e. it skips :exc:`Exception`,
:class:`BaseException` and :class:`object`). If that happens
you should use :exc:`UnpickleableException` instead.
:param exc: An exception instance.
Will return the nearest pickleable parent exception class
(except :exc:`Exception` and parents), or if the exception is
pickleable it will return :const:`None`.
:rtype :exc:`Exception`:
"""
exc_args = getattr(exc, 'args', [])
for supercls in itermro(exc.__class__, unwanted_base_classes):
try:
superexc = supercls(*exc_args)
loads(dumps(superexc))
except:
pass
else:
return superexc
find_nearest_pickleable_exception = find_pickleable_exception # XXX compat
def itermro(cls, stop):
return takewhile(lambda sup: sup not in stop, getmro(cls))
def create_exception_cls(name, module, parent=None):
"""Dynamically create an exception class."""
if not parent:
parent = Exception
return subclass_exception(name, parent, module)
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: see :attr:`exc_args`
**Example**
.. code-block:: python
>>> def pickle_it(raising_function):
... try:
... raising_function()
... except Exception as e:
... exc = UnpickleableExceptionWrapper(
... e.__class__.__module__,
... e.__class__.__name__,
... e.args,
... )
... pickle.dumps(exc) # Works fine.
"""
#: The module of the original exception.
exc_module = None
#: The name of the original exception class.
exc_cls_name = None
#: The arguments for the original exception.
exc_args = None
def __init__(self, exc_module, exc_cls_name, exc_args, text=None):
safe_exc_args = []
for arg in exc_args:
try:
pickle.dumps(arg)
safe_exc_args.append(arg)
except Exception:
safe_exc_args.append(safe_repr(arg))
self.exc_module = exc_module
self.exc_cls_name = exc_cls_name
self.exc_args = safe_exc_args
self.text = text
Exception.__init__(self, exc_module, exc_cls_name, safe_exc_args, text)
def restore(self):
return create_exception_cls(self.exc_cls_name,
self.exc_module)(*self.exc_args)
def __str__(self):
return self.text
@classmethod
def from_exception(cls, exc):
return cls(exc.__class__.__module__,
exc.__class__.__name__,
getattr(exc, 'args', []),
safe_repr(exc))
def get_pickleable_exception(exc):
"""Make sure exception is pickleable."""
try:
pickle.loads(pickle.dumps(exc))
except Exception:
pass
else:
return exc
nearest = find_pickleable_exception(exc)
if nearest:
return nearest
return UnpickleableExceptionWrapper.from_exception(exc)
def get_pickleable_etype(cls, loads=pickle.loads, dumps=pickle.dumps):
try:
loads(dumps(cls))
except:
return Exception
else:
return cls
def get_pickled_exception(exc):
"""Get original exception from exception pickled using
:meth:`get_pickleable_exception`."""
if isinstance(exc, UnpickleableExceptionWrapper):
return exc.restore()
return exc
|