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