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