/usr/share/pyshared/celery/utils/serialization.py is in python-celery 2.5.3-4.
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 168 169 170 171 172 173 174 175 176 | # -*- coding: utf-8 -*-
"""
celery.utils.serialization
~~~~~~~~~~~~~~~~~~~~~~~~~~
Utilities for safely pickling exceptions.
:copyright: (c) 2009 - 2012 by Ask Solem.
:license: BSD, see LICENSE for more details.
"""
from __future__ import absolute_import
import inspect
import sys
import types
from copy import deepcopy
import pickle as pypickle
try:
import cPickle as cpickle
except ImportError:
cpickle = None # noqa
from .encoding import safe_repr
if sys.version_info < (2, 6): # pragma: no cover
# cPickle is broken in Python <= 2.6.
# It unsafely and incorrectly uses relative instead of absolute imports,
# so e.g.:
# exceptions.KeyError
# becomes:
# celery.exceptions.KeyError
#
# Your best choice is to upgrade to Python 2.6,
# as while the pure pickle version has worse performance,
# it is the only safe option for older Python versions.
pickle = pypickle
else:
pickle = cpickle or pypickle
#: List of base classes we probably don't want to reduce to.
unwanted_base_classes = (StandardError, Exception, BaseException, object)
if sys.version_info < (2, 5): # pragma: no cover
# Prior to Python 2.5, Exception was an old-style class
def subclass_exception(name, parent, unused):
return types.ClassType(name, (parent,), {})
else:
def subclass_exception(name, parent, module): # noqa
return type(name, (parent,), {'__module__': module})
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. 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.
:returns: the nearest exception if it's not :exc:`Exception` or below,
if it is it returns :const:`None`.
:rtype :exc:`Exception`:
"""
cls = exc.__class__
getmro_ = getattr(cls, "mro", None)
# old-style classes doesn't have mro()
if not getmro_:
# all Py2.4 exceptions has a baseclass.
if not getattr(cls, "__bases__", ()):
return
# Use inspect.getmro() to traverse bases instead.
getmro_ = lambda: inspect.getmro(cls)
for supercls in getmro_():
if supercls in unwanted_base_classes:
# only BaseException and object, from here on down,
# we don't care about these.
return
try:
exc_args = getattr(exc, "args", [])
superexc = supercls(*exc_args)
pickle.dumps(superexc)
except:
pass
else:
return superexc
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
>>> try:
... something_raising_unpickleable_exc()
>>> except Exception, e:
... exc = UnpickleableException(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):
self.exc_module = exc_module
self.exc_cls_name = exc_cls_name
self.exc_args = exc_args
self.text = text
Exception.__init__(self, exc_module, exc_cls_name, 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."""
nearest = find_nearest_pickleable_exception(exc)
if nearest:
return nearest
try:
pickle.dumps(deepcopy(exc))
except Exception:
return UnpickleableExceptionWrapper.from_exception(exc)
return exc
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
|