--- /dev/null
+"""Helper to provide extensibility for pickle/cPickle.\r
+\r
+This is only useful to add pickle support for extension types defined in\r
+C, not for instances of user-defined classes.\r
+"""\r
+\r
+from types import ClassType as _ClassType\r
+\r
+__all__ = ["pickle", "constructor",\r
+ "add_extension", "remove_extension", "clear_extension_cache"]\r
+\r
+dispatch_table = {}\r
+\r
+def pickle(ob_type, pickle_function, constructor_ob=None):\r
+ if type(ob_type) is _ClassType:\r
+ raise TypeError("copy_reg is not intended for use with classes")\r
+\r
+ if not hasattr(pickle_function, '__call__'):\r
+ raise TypeError("reduction functions must be callable")\r
+ dispatch_table[ob_type] = pickle_function\r
+\r
+ # The constructor_ob function is a vestige of safe for unpickling.\r
+ # There is no reason for the caller to pass it anymore.\r
+ if constructor_ob is not None:\r
+ constructor(constructor_ob)\r
+\r
+def constructor(object):\r
+ if not hasattr(object, '__call__'):\r
+ raise TypeError("constructors must be callable")\r
+\r
+# Example: provide pickling support for complex numbers.\r
+\r
+try:\r
+ complex\r
+except NameError:\r
+ pass\r
+else:\r
+\r
+ def pickle_complex(c):\r
+ return complex, (c.real, c.imag)\r
+\r
+ pickle(complex, pickle_complex, complex)\r
+\r
+# Support for pickling new-style objects\r
+\r
+def _reconstructor(cls, base, state):\r
+ if base is object:\r
+ obj = object.__new__(cls)\r
+ else:\r
+ obj = base.__new__(cls, state)\r
+ if base.__init__ != object.__init__:\r
+ base.__init__(obj, state)\r
+ return obj\r
+\r
+_HEAPTYPE = 1<<9\r
+\r
+# Python code for object.__reduce_ex__ for protocols 0 and 1\r
+\r
+def _reduce_ex(self, proto):\r
+ assert proto < 2\r
+ for base in self.__class__.__mro__:\r
+ if hasattr(base, '__flags__') and not base.__flags__ & _HEAPTYPE:\r
+ break\r
+ else:\r
+ base = object # not really reachable\r
+ if base is object:\r
+ state = None\r
+ else:\r
+ if base is self.__class__:\r
+ raise TypeError, "can't pickle %s objects" % base.__name__\r
+ state = base(self)\r
+ args = (self.__class__, base, state)\r
+ try:\r
+ getstate = self.__getstate__\r
+ except AttributeError:\r
+ if getattr(self, "__slots__", None):\r
+ raise TypeError("a class that defines __slots__ without "\r
+ "defining __getstate__ cannot be pickled")\r
+ try:\r
+ dict = self.__dict__\r
+ except AttributeError:\r
+ dict = None\r
+ else:\r
+ dict = getstate()\r
+ if dict:\r
+ return _reconstructor, args, dict\r
+ else:\r
+ return _reconstructor, args\r
+\r
+# Helper for __reduce_ex__ protocol 2\r
+\r
+def __newobj__(cls, *args):\r
+ return cls.__new__(cls, *args)\r
+\r
+def _slotnames(cls):\r
+ """Return a list of slot names for a given class.\r
+\r
+ This needs to find slots defined by the class and its bases, so we\r
+ can't simply return the __slots__ attribute. We must walk down\r
+ the Method Resolution Order and concatenate the __slots__ of each\r
+ class found there. (This assumes classes don't modify their\r
+ __slots__ attribute to misrepresent their slots after the class is\r
+ defined.)\r
+ """\r
+\r
+ # Get the value from a cache in the class if possible\r
+ names = cls.__dict__.get("__slotnames__")\r
+ if names is not None:\r
+ return names\r
+\r
+ # Not cached -- calculate the value\r
+ names = []\r
+ if not hasattr(cls, "__slots__"):\r
+ # This class has no slots\r
+ pass\r
+ else:\r
+ # Slots found -- gather slot names from all base classes\r
+ for c in cls.__mro__:\r
+ if "__slots__" in c.__dict__:\r
+ slots = c.__dict__['__slots__']\r
+ # if class has a single slot, it can be given as a string\r
+ if isinstance(slots, basestring):\r
+ slots = (slots,)\r
+ for name in slots:\r
+ # special descriptors\r
+ if name in ("__dict__", "__weakref__"):\r
+ continue\r
+ # mangled names\r
+ elif name.startswith('__') and not name.endswith('__'):\r
+ names.append('_%s%s' % (c.__name__, name))\r
+ else:\r
+ names.append(name)\r
+\r
+ # Cache the outcome in the class if at all possible\r
+ try:\r
+ cls.__slotnames__ = names\r
+ except:\r
+ pass # But don't die if we can't\r
+\r
+ return names\r
+\r
+# A registry of extension codes. This is an ad-hoc compression\r
+# mechanism. Whenever a global reference to <module>, <name> is about\r
+# to be pickled, the (<module>, <name>) tuple is looked up here to see\r
+# if it is a registered extension code for it. Extension codes are\r
+# universal, so that the meaning of a pickle does not depend on\r
+# context. (There are also some codes reserved for local use that\r
+# don't have this restriction.) Codes are positive ints; 0 is\r
+# reserved.\r
+\r
+_extension_registry = {} # key -> code\r
+_inverted_registry = {} # code -> key\r
+_extension_cache = {} # code -> object\r
+# Don't ever rebind those names: cPickle grabs a reference to them when\r
+# it's initialized, and won't see a rebinding.\r
+\r
+def add_extension(module, name, code):\r
+ """Register an extension code."""\r
+ code = int(code)\r
+ if not 1 <= code <= 0x7fffffff:\r
+ raise ValueError, "code out of range"\r
+ key = (module, name)\r
+ if (_extension_registry.get(key) == code and\r
+ _inverted_registry.get(code) == key):\r
+ return # Redundant registrations are benign\r
+ if key in _extension_registry:\r
+ raise ValueError("key %s is already registered with code %s" %\r
+ (key, _extension_registry[key]))\r
+ if code in _inverted_registry:\r
+ raise ValueError("code %s is already in use for key %s" %\r
+ (code, _inverted_registry[code]))\r
+ _extension_registry[key] = code\r
+ _inverted_registry[code] = key\r
+\r
+def remove_extension(module, name, code):\r
+ """Unregister an extension code. For testing only."""\r
+ key = (module, name)\r
+ if (_extension_registry.get(key) != code or\r
+ _inverted_registry.get(code) != key):\r
+ raise ValueError("key %s is not registered with code %s" %\r
+ (key, code))\r
+ del _extension_registry[key]\r
+ del _inverted_registry[code]\r
+ if code in _extension_cache:\r
+ del _extension_cache[code]\r
+\r
+def clear_extension_cache():\r
+ _extension_cache.clear()\r
+\r
+# Standard extension code assignments\r
+\r
+# Reserved ranges\r
+\r
+# First Last Count Purpose\r
+# 1 127 127 Reserved for Python standard library\r
+# 128 191 64 Reserved for Zope\r
+# 192 239 48 Reserved for 3rd parties\r
+# 240 255 16 Reserved for private use (will never be assigned)\r
+# 256 Inf Inf Reserved for future assignment\r
+\r
+# Extension codes are assigned by the Python Software Foundation.\r