21
21
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
22
# DEALINGS IN THE SOFTWARE.
23
23
24
+ copyreg = None
25
+
26
+
27
+ def import_copyreg ():
28
+ global copyreg
29
+ if not copyreg :
30
+ import copyreg
31
+
32
+
24
33
def __reduce__ (obj , proto = 0 ):
25
34
if proto >= 2 :
26
- descr = getattr (w_obj , '__getnewargs_ex__' , None )
27
- hasargs = True
28
- if descr is not None :
29
- result = descr ()
30
- if not isinstance (result , tuple ):
31
- raise TypeError ("__getnewargs_ex__ should return a tuple, not '%s'" , type (result ))
32
- n = len (result )
33
- if n != 2 :
34
- raise ValueError ("__getnewargs_ex__ should return a tuple of length 2, not %d" , n )
35
- args , kwargs = result
36
- if isinstance (args , tuple ):
37
- raise TypeError ("first item of the tuple returned by __getnewargs_ex__ must be a tuple, not '%s'" , type (args ))
38
- if not isinstance (kwargs , dict ):
39
- raise TypeError ("second item of the tuple returned by __getnewargs_ex__ must be a dict, not '%s'" , type (kwargs ))
40
- else :
41
- descr = getattr (obj , '__getnewargs__' , None )
42
- if descr is not None :
43
- args = descr (obj )
44
- if not isinstance (args , tuple ):
45
- raise TypeError ("__getnewargs__ should return a tuple, not '%s'" , type (args ))
46
- else :
47
- hasargs = False
48
- args = tuple ()
49
- kwargs = None
50
- getstate = getattr (obj , '__getstate__' )
51
- if getstate is None :
52
- required = (not hasargs and
53
- not isinstance (obj , list ) and
54
- not isinstance (obj , dict ))
55
- obj_type = type (obj )
56
- if required :
57
- raise TypeError ("cannot pickle %s objects" , obj_type )
58
- return reduce_2 (obj , proto , args , kwargs )
59
- return reduce_1 (obj , proto )
60
-
61
-
62
- def _getstate (obj ):
63
- cls = obj .__class__
35
+ return reduce_newobj (obj )
36
+
37
+ proto = int (proto )
38
+ import_copyreg ()
39
+ return copyreg ._reduce_ex (obj , proto )
40
+
41
+
42
+ def _get_new_arguments (obj ):
43
+ # We first attempt to fetch the arguments for __new__ by calling __getnewargs_ex__ on the object.
44
+ getnewargs_ex = getattr (obj , '__getnewargs_ex__' , None )
45
+ if getnewargs_ex is not None :
46
+ newargs = getnewargs_ex ()
47
+ if not isinstance (newargs , tuple ):
48
+ raise TypeError ("__getnewargs_ex__ should return a tuple, not '{}'" .format (type (newargs )))
49
+ if len (newargs ) != 2 :
50
+ raise ValueError ("__getnewargs_ex__ should return a tuple of length 2, not {}" .format (len (newargs )))
51
+ args , kwargs = newargs
52
+ if not isinstance (args , tuple ):
53
+ raise TypeError ("first item of the tuple returned by __getnewargs_ex__ must be a tuple, not '{}" .format (type (args )))
54
+ if not isinstance (kwargs , dict ):
55
+ raise TypeError ("second item of the tuple returned by __getnewargs_ex__ must be a dict, not '{}'" .format (type (kwargs )))
56
+ return args , kwargs
57
+
58
+ getnewargs = getattr (obj , '__getnewargs__' , None )
59
+ if getnewargs is not None :
60
+ args = getnewargs ()
61
+ if not isinstance (args , tuple ):
62
+ raise TypeError ("__getnewargs__ should return a tuple, not '{}'" .format (type (args )))
63
+ return args , None
64
+
65
+ # The object does not have __getnewargs_ex__ and __getnewargs__. This may
66
+ # mean __new__ does not takes any arguments on this object, or that the
67
+ # object does not implement the reduce protocol for pickling or
68
+ # copying.
69
+ return None , None
70
+
71
+
72
+ def reduce_newobj (obj ):
73
+ cls = type (obj )
74
+ args , kwargs = _get_new_arguments (obj )
75
+ import_copyreg ()
76
+
77
+ hasargs = args is not None
78
+ if kwargs is None or len (kwargs ) == 0 :
79
+ newobj = copyreg .__newobj__
80
+ newargs = (cls , ) + args if args else tuple ()
81
+ elif args is not None :
82
+ newobj = copyreg .__newobj_ex__
83
+ newargs = (cls , args , kwargs )
84
+ else :
85
+ import sys
86
+ frame = sys ._getframe (0 )
87
+ file_name = frame .f_code .co_filename
88
+ line_no = frame .f_lineno
89
+ raise SystemError ("{}:{}: bad argument to internal function" .format (file_name , line_no ))
64
90
65
91
try :
66
92
getstate = obj .__getstate__
67
93
except AttributeError :
68
- # and raises a TypeError if the condition holds true, this is done
69
- # just before reduce_2 is called in pypy
70
94
state = getattr (obj , "__dict__" , None )
71
- # CPython returns None if the dict is empty
72
- if state is not None and len (state ) == 0 :
73
- state = None
74
95
names = slotnames (cls ) # not checking for list
75
96
if names is not None :
76
97
slots = {}
@@ -85,44 +106,10 @@ def _getstate(obj):
85
106
state = state , slots
86
107
else :
87
108
state = getstate ()
88
- return state
89
-
90
-
91
- copyreg = None
92
- def reduce_1 (obj , proto ):
93
- global copyreg
94
- if not copyreg :
95
- import copyreg
96
- return copyreg ._reduce_ex (obj , proto )
97
-
98
-
99
- def reduce_2 (obj , proto , args , kwargs ):
100
- cls = obj .__class__
101
-
102
- if not hasattr (type (obj ), "__new__" ):
103
- raise TypeError ("can't pickle %s objects" % type (obj ).__name__ )
104
-
105
- global copyreg
106
- if not copyreg :
107
- import copyreg
108
-
109
- if not isinstance (args , tuple ):
110
- raise TypeError ("__getnewargs__ should return a tuple" )
111
- if not kwargs :
112
- newobj = copyreg .__newobj__
113
- args2 = (cls ,) + args
114
- elif proto >= 4 :
115
- newobj = copyreg .__newobj_ex__
116
- args2 = (cls , args , kwargs )
117
- else :
118
- raise ValueError ("must use protocol 4 or greater to copy this "
119
- "object; since __getnewargs_ex__ returned "
120
- "keyword arguments." )
121
- state = _getstate (obj )
122
109
listitems = iter (obj ) if isinstance (obj , list ) else None
123
- dictitems = iter ( obj .items () ) if isinstance (obj , dict ) else None
110
+ dictitems = obj .iteritems ( ) if isinstance (obj , dict ) else None
124
111
125
- return newobj , args2 , state , listitems , dictitems
112
+ return newobj , newargs , state , listitems , dictitems
126
113
127
114
128
115
def slotnames (cls ):
@@ -144,14 +131,15 @@ def slotnames(cls):
144
131
145
132
146
133
def __reduce_ex__ (obj , proto = 0 ):
147
- obj_reduce = getattr (obj , "__reduce__" , None )
148
- if obj_reduce is not None :
134
+ obj_reduce = getattr (type , "__reduce__" , None )
135
+ _reduce = getattr (obj , "__reduce__" , None )
136
+ if _reduce is not None :
149
137
# Check if __reduce__ has been overridden:
150
138
# "type(obj).__reduce__ is not object.__reduce__"
151
139
cls_reduce = getattr (type (obj ), "__reduce__" , None )
152
140
override = cls_reduce is not obj_reduce
153
141
if override :
154
- return obj_reduce ()
142
+ return _reduce ()
155
143
return __reduce__ (obj , proto )
156
144
157
145
0 commit comments