| Fred Drake | 78a6a36 | 2000-10-11 22:16:45 +0000 | [diff] [blame] | 1 | """Helper to provide extensibility for pickle/cPickle. | 
 | 2 |  | 
 | 3 | This is only useful to add pickle support for extension types defined in | 
 | 4 | C, not for instances of user-defined classes. | 
 | 5 | """ | 
 | 6 |  | 
 | 7 | from types import ClassType as _ClassType | 
| Guido van Rossum | 72be306 | 1997-05-20 18:03:22 +0000 | [diff] [blame] | 8 |  | 
| Guido van Rossum | cf356fd | 2003-01-31 20:34:07 +0000 | [diff] [blame] | 9 | __all__ = ["pickle", "constructor", | 
 | 10 |            "add_extension", "remove_extension", "clear_extension_cache"] | 
| Skip Montanaro | e99d5ea | 2001-01-20 19:54:20 +0000 | [diff] [blame] | 11 |  | 
| Guido van Rossum | 4706562 | 1997-04-09 17:44:11 +0000 | [diff] [blame] | 12 | dispatch_table = {} | 
| Guido van Rossum | 4706562 | 1997-04-09 17:44:11 +0000 | [diff] [blame] | 13 |  | 
| Fred Drake | 78a6a36 | 2000-10-11 22:16:45 +0000 | [diff] [blame] | 14 | def pickle(ob_type, pickle_function, constructor_ob=None): | 
 | 15 |     if type(ob_type) is _ClassType: | 
 | 16 |         raise TypeError("copy_reg is not intended for use with classes") | 
 | 17 |  | 
 | 18 |     if not callable(pickle_function): | 
 | 19 |         raise TypeError("reduction functions must be callable") | 
| Guido van Rossum | 4706562 | 1997-04-09 17:44:11 +0000 | [diff] [blame] | 20 |     dispatch_table[ob_type] = pickle_function | 
 | 21 |  | 
| Jeremy Hylton | f8ecde5 | 2003-06-27 16:58:43 +0000 | [diff] [blame] | 22 |     # The constructor_ob function is a vestige of safe for unpickling. | 
 | 23 |     # There is no reason for the caller to pass it anymore. | 
 | 24 |     if constructor_ob is not None: | 
 | 25 |         constructor(constructor_ob) | 
 | 26 |  | 
| Guido van Rossum | 4706562 | 1997-04-09 17:44:11 +0000 | [diff] [blame] | 27 | def constructor(object): | 
| Fred Drake | 78a6a36 | 2000-10-11 22:16:45 +0000 | [diff] [blame] | 28 |     if not callable(object): | 
 | 29 |         raise TypeError("constructors must be callable") | 
| Guido van Rossum | 4706562 | 1997-04-09 17:44:11 +0000 | [diff] [blame] | 30 |  | 
| Guido van Rossum | 72be306 | 1997-05-20 18:03:22 +0000 | [diff] [blame] | 31 | # Example: provide pickling support for complex numbers. | 
| Guido van Rossum | 4706562 | 1997-04-09 17:44:11 +0000 | [diff] [blame] | 32 |  | 
| Martin v. Löwis | 502ba46 | 2003-06-07 20:10:54 +0000 | [diff] [blame] | 33 | try: | 
 | 34 |     complex | 
 | 35 | except NameError: | 
 | 36 |     pass | 
 | 37 | else: | 
| Guido van Rossum | 72be306 | 1997-05-20 18:03:22 +0000 | [diff] [blame] | 38 |  | 
| Martin v. Löwis | 502ba46 | 2003-06-07 20:10:54 +0000 | [diff] [blame] | 39 |     def pickle_complex(c): | 
 | 40 |         return complex, (c.real, c.imag) | 
 | 41 |  | 
 | 42 |     pickle(complex, pickle_complex, complex) | 
| Guido van Rossum | 3926a63 | 2001-09-25 16:25:58 +0000 | [diff] [blame] | 43 |  | 
| Guido van Rossum | 298e421 | 2003-02-13 16:30:16 +0000 | [diff] [blame] | 44 | # Support for pickling new-style objects | 
| Guido van Rossum | 3926a63 | 2001-09-25 16:25:58 +0000 | [diff] [blame] | 45 |  | 
| Guido van Rossum | 3926a63 | 2001-09-25 16:25:58 +0000 | [diff] [blame] | 46 | def _reconstructor(cls, base, state): | 
| Guido van Rossum | 298e421 | 2003-02-13 16:30:16 +0000 | [diff] [blame] | 47 |     if base is object: | 
 | 48 |         obj = object.__new__(cls) | 
 | 49 |     else: | 
 | 50 |         obj = base.__new__(cls, state) | 
 | 51 |         base.__init__(obj, state) | 
| Guido van Rossum | 3926a63 | 2001-09-25 16:25:58 +0000 | [diff] [blame] | 52 |     return obj | 
| Guido van Rossum | 3926a63 | 2001-09-25 16:25:58 +0000 | [diff] [blame] | 53 |  | 
 | 54 | _HEAPTYPE = 1<<9 | 
 | 55 |  | 
| Guido van Rossum | be53242 | 2003-02-21 22:20:31 +0000 | [diff] [blame] | 56 | # Python code for object.__reduce_ex__ for protocols 0 and 1 | 
 | 57 |  | 
 | 58 | def _reduce_ex(self, proto): | 
 | 59 |     assert proto < 2 | 
| Guido van Rossum | 3926a63 | 2001-09-25 16:25:58 +0000 | [diff] [blame] | 60 |     for base in self.__class__.__mro__: | 
| Guido van Rossum | 00fb0c9 | 2001-11-24 21:04:31 +0000 | [diff] [blame] | 61 |         if hasattr(base, '__flags__') and not base.__flags__ & _HEAPTYPE: | 
| Guido van Rossum | 3926a63 | 2001-09-25 16:25:58 +0000 | [diff] [blame] | 62 |             break | 
 | 63 |     else: | 
 | 64 |         base = object # not really reachable | 
 | 65 |     if base is object: | 
 | 66 |         state = None | 
 | 67 |     else: | 
| Guido van Rossum | 2a6f5b3 | 2001-12-27 16:27:28 +0000 | [diff] [blame] | 68 |         if base is self.__class__: | 
 | 69 |             raise TypeError, "can't pickle %s objects" % base.__name__ | 
| Guido van Rossum | 3926a63 | 2001-09-25 16:25:58 +0000 | [diff] [blame] | 70 |         state = base(self) | 
| Guido van Rossum | 6cef6d5 | 2001-09-28 18:13:29 +0000 | [diff] [blame] | 71 |     args = (self.__class__, base, state) | 
 | 72 |     try: | 
| Guido van Rossum | 00fb0c9 | 2001-11-24 21:04:31 +0000 | [diff] [blame] | 73 |         getstate = self.__getstate__ | 
| Guido van Rossum | 6cef6d5 | 2001-09-28 18:13:29 +0000 | [diff] [blame] | 74 |     except AttributeError: | 
| Guido van Rossum | 3f50cdc | 2003-02-10 21:31:27 +0000 | [diff] [blame] | 75 |         if getattr(self, "__slots__", None): | 
 | 76 |             raise TypeError("a class that defines __slots__ without " | 
 | 77 |                             "defining __getstate__ cannot be pickled") | 
| Guido van Rossum | 00fb0c9 | 2001-11-24 21:04:31 +0000 | [diff] [blame] | 78 |         try: | 
 | 79 |             dict = self.__dict__ | 
 | 80 |         except AttributeError: | 
 | 81 |             dict = None | 
 | 82 |     else: | 
 | 83 |         dict = getstate() | 
| Guido van Rossum | 6cef6d5 | 2001-09-28 18:13:29 +0000 | [diff] [blame] | 84 |     if dict: | 
 | 85 |         return _reconstructor, args, dict | 
 | 86 |     else: | 
 | 87 |         return _reconstructor, args | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 88 |  | 
| Guido van Rossum | be53242 | 2003-02-21 22:20:31 +0000 | [diff] [blame] | 89 | # Helper for __reduce_ex__ protocol 2 | 
| Guido van Rossum | 5aac4e6 | 2003-02-06 22:57:00 +0000 | [diff] [blame] | 90 |  | 
 | 91 | def __newobj__(cls, *args): | 
 | 92 |     return cls.__new__(cls, *args) | 
 | 93 |  | 
| Guido van Rossum | 5aac4e6 | 2003-02-06 22:57:00 +0000 | [diff] [blame] | 94 | def _slotnames(cls): | 
 | 95 |     """Return a list of slot names for a given class. | 
 | 96 |  | 
 | 97 |     This needs to find slots defined by the class and its bases, so we | 
 | 98 |     can't simply return the __slots__ attribute.  We must walk down | 
 | 99 |     the Method Resolution Order and concatenate the __slots__ of each | 
 | 100 |     class found there.  (This assumes classes don't modify their | 
 | 101 |     __slots__ attribute to misrepresent their slots after the class is | 
 | 102 |     defined.) | 
 | 103 |     """ | 
 | 104 |  | 
 | 105 |     # Get the value from a cache in the class if possible | 
 | 106 |     names = cls.__dict__.get("__slotnames__") | 
 | 107 |     if names is not None: | 
 | 108 |         return names | 
 | 109 |  | 
 | 110 |     # Not cached -- calculate the value | 
 | 111 |     names = [] | 
 | 112 |     if not hasattr(cls, "__slots__"): | 
 | 113 |         # This class has no slots | 
 | 114 |         pass | 
 | 115 |     else: | 
 | 116 |         # Slots found -- gather slot names from all base classes | 
 | 117 |         for c in cls.__mro__: | 
 | 118 |             if "__slots__" in c.__dict__: | 
 | 119 |                 names += [name for name in c.__dict__["__slots__"] | 
 | 120 |                                if name not in ("__dict__", "__weakref__")] | 
 | 121 |  | 
 | 122 |     # Cache the outcome in the class if at all possible | 
 | 123 |     try: | 
 | 124 |         cls.__slotnames__ = names | 
 | 125 |     except: | 
 | 126 |         pass # But don't die if we can't | 
 | 127 |  | 
 | 128 |     return names | 
 | 129 |  | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 130 | # A registry of extension codes.  This is an ad-hoc compression | 
 | 131 | # mechanism.  Whenever a global reference to <module>, <name> is about | 
 | 132 | # to be pickled, the (<module>, <name>) tuple is looked up here to see | 
 | 133 | # if it is a registered extension code for it.  Extension codes are | 
 | 134 | # universal, so that the meaning of a pickle does not depend on | 
 | 135 | # context.  (There are also some codes reserved for local use that | 
 | 136 | # don't have this restriction.)  Codes are positive ints; 0 is | 
 | 137 | # reserved. | 
 | 138 |  | 
| Guido van Rossum | d4b920c | 2003-02-04 01:54:49 +0000 | [diff] [blame] | 139 | _extension_registry = {}                # key -> code | 
 | 140 | _inverted_registry = {}                 # code -> key | 
 | 141 | _extension_cache = {}                   # code -> object | 
| Tim Peters | 5b7da39 | 2003-02-04 00:21:07 +0000 | [diff] [blame] | 142 | # Don't ever rebind those names:  cPickle grabs a reference to them when | 
 | 143 | # it's initialized, and won't see a rebinding. | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 144 |  | 
 | 145 | def add_extension(module, name, code): | 
 | 146 |     """Register an extension code.""" | 
 | 147 |     code = int(code) | 
| Tim Peters | 2d62965 | 2003-02-04 05:06:17 +0000 | [diff] [blame] | 148 |     if not 1 <= code <= 0x7fffffff: | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 149 |         raise ValueError, "code out of range" | 
 | 150 |     key = (module, name) | 
| Guido van Rossum | d4b920c | 2003-02-04 01:54:49 +0000 | [diff] [blame] | 151 |     if (_extension_registry.get(key) == code and | 
 | 152 |         _inverted_registry.get(code) == key): | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 153 |         return # Redundant registrations are benign | 
| Guido van Rossum | d4b920c | 2003-02-04 01:54:49 +0000 | [diff] [blame] | 154 |     if key in _extension_registry: | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 155 |         raise ValueError("key %s is already registered with code %s" % | 
| Guido van Rossum | d4b920c | 2003-02-04 01:54:49 +0000 | [diff] [blame] | 156 |                          (key, _extension_registry[key])) | 
 | 157 |     if code in _inverted_registry: | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 158 |         raise ValueError("code %s is already in use for key %s" % | 
| Guido van Rossum | d4b920c | 2003-02-04 01:54:49 +0000 | [diff] [blame] | 159 |                          (code, _inverted_registry[code])) | 
 | 160 |     _extension_registry[key] = code | 
 | 161 |     _inverted_registry[code] = key | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 162 |  | 
 | 163 | def remove_extension(module, name, code): | 
 | 164 |     """Unregister an extension code.  For testing only.""" | 
 | 165 |     key = (module, name) | 
| Guido van Rossum | d4b920c | 2003-02-04 01:54:49 +0000 | [diff] [blame] | 166 |     if (_extension_registry.get(key) != code or | 
 | 167 |         _inverted_registry.get(code) != key): | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 168 |         raise ValueError("key %s is not registered with code %s" % | 
 | 169 |                          (key, code)) | 
| Guido van Rossum | d4b920c | 2003-02-04 01:54:49 +0000 | [diff] [blame] | 170 |     del _extension_registry[key] | 
 | 171 |     del _inverted_registry[code] | 
 | 172 |     if code in _extension_cache: | 
 | 173 |         del _extension_cache[code] | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 174 |  | 
 | 175 | def clear_extension_cache(): | 
| Guido van Rossum | d4b920c | 2003-02-04 01:54:49 +0000 | [diff] [blame] | 176 |     _extension_cache.clear() | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 177 |  | 
 | 178 | # Standard extension code assignments | 
 | 179 |  | 
 | 180 | # Reserved ranges | 
 | 181 |  | 
 | 182 | # First  Last Count  Purpose | 
 | 183 | #     1   127   127  Reserved for Python standard library | 
| Guido van Rossum | cef9db6 | 2003-02-07 20:56:38 +0000 | [diff] [blame] | 184 | #   128   191    64  Reserved for Zope | 
| Guido van Rossum | 255f3ee | 2003-01-29 06:14:11 +0000 | [diff] [blame] | 185 | #   192   239    48  Reserved for 3rd parties | 
 | 186 | #   240   255    16  Reserved for private use (will never be assigned) | 
 | 187 | #   256   Inf   Inf  Reserved for future assignment | 
 | 188 |  | 
 | 189 | # Extension codes are assigned by the Python Software Foundation. |