- Notifications
You must be signed in to change notification settings - Fork 31.7k
/
Copy pathcopyreg.py
217 lines (183 loc) · 7.44 KB
/
copyreg.py
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
"""Helper to provide extensibility for pickle.
This is only useful to add pickle support for extension types defined in
C, not for instances of user-defined classes.
"""
__all__= ["pickle", "constructor",
"add_extension", "remove_extension", "clear_extension_cache"]
dispatch_table= {}
defpickle(ob_type, pickle_function, constructor_ob=None):
ifnotcallable(pickle_function):
raiseTypeError("reduction functions must be callable")
dispatch_table[ob_type] =pickle_function
# The constructor_ob function is a vestige of safe for unpickling.
# There is no reason for the caller to pass it anymore.
ifconstructor_obisnotNone:
constructor(constructor_ob)
defconstructor(object):
ifnotcallable(object):
raiseTypeError("constructors must be callable")
# Example: provide pickling support for complex numbers.
defpickle_complex(c):
returncomplex, (c.real, c.imag)
pickle(complex, pickle_complex, complex)
defpickle_union(obj):
importfunctools, operator
returnfunctools.reduce, (operator.or_, obj.__args__)
pickle(type(int|str), pickle_union)
# Support for pickling new-style objects
def_reconstructor(cls, base, state):
ifbaseisobject:
obj=object.__new__(cls)
else:
obj=base.__new__(cls, state)
ifbase.__init__!=object.__init__:
base.__init__(obj, state)
returnobj
_HEAPTYPE=1<<9
_new_type=type(int.__new__)
# Python code for object.__reduce_ex__ for protocols 0 and 1
def_reduce_ex(self, proto):
assertproto<2
cls=self.__class__
forbaseincls.__mro__:
ifhasattr(base, '__flags__') andnotbase.__flags__&_HEAPTYPE:
break
new=base.__new__
ifisinstance(new, _new_type) andnew.__self__isbase:
break
else:
base=object# not really reachable
ifbaseisobject:
state=None
else:
ifbaseiscls:
raiseTypeError(f"cannot pickle {cls.__name__!r} object")
state=base(self)
args= (cls, base, state)
try:
getstate=self.__getstate__
exceptAttributeError:
ifgetattr(self, "__slots__", None):
raiseTypeError(f"cannot pickle {cls.__name__!r} object: "
f"a class that defines __slots__ without "
f"defining __getstate__ cannot be pickled "
f"with protocol {proto}") fromNone
try:
dict=self.__dict__
exceptAttributeError:
dict=None
else:
if (type(self).__getstate__isobject.__getstate__and
getattr(self, "__slots__", None)):
raiseTypeError("a class that defines __slots__ without "
"defining __getstate__ cannot be pickled")
dict=getstate()
ifdict:
return_reconstructor, args, dict
else:
return_reconstructor, args
# Helper for __reduce_ex__ protocol 2
def__newobj__(cls, *args):
returncls.__new__(cls, *args)
def__newobj_ex__(cls, args, kwargs):
"""Used by pickle protocol 4, instead of __newobj__ to allow classes with
keyword-only arguments to be pickled correctly.
"""
returncls.__new__(cls, *args, **kwargs)
def_slotnames(cls):
"""Return a list of slot names for a given class.
This needs to find slots defined by the class and its bases, so we
can't simply return the __slots__ attribute. We must walk down
the Method Resolution Order and concatenate the __slots__ of each
class found there. (This assumes classes don't modify their
__slots__ attribute to misrepresent their slots after the class is
defined.)
"""
# Get the value from a cache in the class if possible
names=cls.__dict__.get("__slotnames__")
ifnamesisnotNone:
returnnames
# Not cached -- calculate the value
names= []
ifnothasattr(cls, "__slots__"):
# This class has no slots
pass
else:
# Slots found -- gather slot names from all base classes
forcincls.__mro__:
if"__slots__"inc.__dict__:
slots=c.__dict__['__slots__']
# if class has a single slot, it can be given as a string
ifisinstance(slots, str):
slots= (slots,)
fornameinslots:
# special descriptors
ifnamein ("__dict__", "__weakref__"):
continue
# mangled names
elifname.startswith('__') andnotname.endswith('__'):
stripped=c.__name__.lstrip('_')
ifstripped:
names.append('_%s%s'% (stripped, name))
else:
names.append(name)
else:
names.append(name)
# Cache the outcome in the class if at all possible
try:
cls.__slotnames__=names
except:
pass# But don't die if we can't
returnnames
# A registry of extension codes. This is an ad-hoc compression
# mechanism. Whenever a global reference to <module>, <name> is about
# to be pickled, the (<module>, <name>) tuple is looked up here to see
# if it is a registered extension code for it. Extension codes are
# universal, so that the meaning of a pickle does not depend on
# context. (There are also some codes reserved for local use that
# don't have this restriction.) Codes are positive ints; 0 is
# reserved.
_extension_registry= {} # key -> code
_inverted_registry= {} # code -> key
_extension_cache= {} # code -> object
# Don't ever rebind those names: pickling grabs a reference to them when
# it's initialized, and won't see a rebinding.
defadd_extension(module, name, code):
"""Register an extension code."""
code=int(code)
ifnot1<=code<=0x7fffffff:
raiseValueError("code out of range")
key= (module, name)
if (_extension_registry.get(key) ==codeand
_inverted_registry.get(code) ==key):
return# Redundant registrations are benign
ifkeyin_extension_registry:
raiseValueError("key %s is already registered with code %s"%
(key, _extension_registry[key]))
ifcodein_inverted_registry:
raiseValueError("code %s is already in use for key %s"%
(code, _inverted_registry[code]))
_extension_registry[key] =code
_inverted_registry[code] =key
defremove_extension(module, name, code):
"""Unregister an extension code. For testing only."""
key= (module, name)
if (_extension_registry.get(key) !=codeor
_inverted_registry.get(code) !=key):
raiseValueError("key %s is not registered with code %s"%
(key, code))
del_extension_registry[key]
del_inverted_registry[code]
ifcodein_extension_cache:
del_extension_cache[code]
defclear_extension_cache():
_extension_cache.clear()
# Standard extension code assignments
# Reserved ranges
# First Last Count Purpose
# 1 127 127 Reserved for Python standard library
# 128 191 64 Reserved for Zope
# 192 239 48 Reserved for 3rd parties
# 240 255 16 Reserved for private use (will never be assigned)
# 256 Inf Inf Reserved for future assignment
# Extension codes are assigned by the Python Software Foundation.