1# mode: run 2# tag: pickle 3 4import cython 5import sys 6 7if sys.version_info[0] < 3: 8 __doc__ = """ 9 >>> import cPickle 10 >>> a = A(5); a 11 A(5) 12 >>> cPickle.loads(cPickle.dumps(a)) 13 A(5) 14 15 >>> b = B(0, 1); b 16 B(x=0, y=1) 17 >>> cPickle.loads(cPickle.dumps(b)) 18 B(x=0, y=1) 19 """ 20 21cdef class A: 22 """ 23 >>> a = A(3); a 24 A(3) 25 >>> import pickle 26 >>> pickle.loads(pickle.dumps(a)) 27 A(3) 28 """ 29 30 cdef int value 31 32 def __init__(self, value): 33 self.value = value 34 35 def __repr__(self): 36 return "A(%s)" % self.value 37 38 def __reduce__(self): 39 return A, (self.value,) 40 41cdef class B: 42 """ 43 >>> b = B(x=37, y=389); b 44 B(x=37, y=389) 45 >>> import pickle 46 >>> pickle.loads(pickle.dumps(b)) 47 B(x=37, y=389) 48 """ 49 50 cdef int x, y 51 52 def __cinit__(self): 53 self.x = self.y = -1 54 55 def __init__(self, x=0, y=0): 56 self.x = x 57 self.y = y 58 59 def __repr__(self): 60 return "%s(x=%s, y=%s)" % (self.__class__.__name__, self.x, self.y) 61 62 def __reduce__(self): 63 return makeObj, (type(self), {'x': self.x, 'y': self.y}) 64 65def makeObj(obj_type, kwds): 66 return obj_type(**kwds) 67 68 69cdef class C(B): 70 """ 71 >>> import pickle 72 >>> pickle.loads(pickle.dumps(C(x=37, y=389))) 73 C(x=37, y=389) 74 """ 75 pass 76 77 78@cython.auto_pickle(True) # Not needed, just to test the directive. 79cdef class DefaultReduce(object): 80 """ 81 >>> a = DefaultReduce(11, 'abc'); a 82 DefaultReduce(i=11, s='abc') 83 >>> import pickle 84 >>> pickle.loads(pickle.dumps(a)) 85 DefaultReduce(i=11, s='abc') 86 >>> pickle.loads(pickle.dumps(DefaultReduce(i=11, s=None))) 87 DefaultReduce(i=11, s=None) 88 """ 89 90 cdef readonly int i 91 cdef readonly str s 92 93 def __init__(self, i=0, s=None): 94 self.i = i 95 self.s = s 96 97 def __repr__(self): 98 return "DefaultReduce(i=%s, s=%r)" % (self.i, self.s) 99 100 101cdef class DefaultReduceSubclass(DefaultReduce): 102 """ 103 >>> a = DefaultReduceSubclass(i=11, s='abc', x=1.5); a 104 DefaultReduceSubclass(i=11, s='abc', x=1.5) 105 >>> import pickle 106 >>> pickle.loads(pickle.dumps(a)) 107 DefaultReduceSubclass(i=11, s='abc', x=1.5) 108 """ 109 110 cdef double x 111 112 def __init__(self, **kwargs): 113 self.x = kwargs.pop('x', 0) 114 super(DefaultReduceSubclass, self).__init__(**kwargs) 115 116 def __repr__(self): 117 return "DefaultReduceSubclass(i=%s, s=%r, x=%s)" % (self.i, self.s, self.x) 118 119 120cdef class result(DefaultReduceSubclass): 121 """ 122 >>> a = result(i=11, s='abc', x=1.5); a 123 result(i=11, s='abc', x=1.5) 124 >>> import pickle 125 >>> pickle.loads(pickle.dumps(a)) 126 result(i=11, s='abc', x=1.5) 127 """ 128 129 def __repr__(self): 130 return "result(i=%s, s=%r, x=%s)" % (self.i, self.s, self.x) 131 132 133class DefaultReducePySubclass(DefaultReduce): 134 """ 135 >>> a = DefaultReducePySubclass(i=11, s='abc', x=1.5); a 136 DefaultReducePySubclass(i=11, s='abc', x=1.5) 137 >>> import pickle 138 >>> pickle.loads(pickle.dumps(a)) 139 DefaultReducePySubclass(i=11, s='abc', x=1.5) 140 141 >>> a.self_reference = a 142 >>> a2 = pickle.loads(pickle.dumps(a)) 143 >>> a2.self_reference is a2 144 True 145 """ 146 def __init__(self, **kwargs): 147 self.x = kwargs.pop('x', 0) 148 super(DefaultReducePySubclass, self).__init__(**kwargs) 149 150 def __repr__(self): 151 return "DefaultReducePySubclass(i=%s, s=%r, x=%s)" % (self.i, self.s, self.x) 152 153 154cdef class NoReduceDueToIntPtr(object): 155 """ 156 >>> import pickle 157 >>> pickle.dumps(NoReduceDueToIntPtr()) 158 Traceback (most recent call last): 159 ... 160 TypeError: self.int_ptr cannot be converted to a Python object for pickling 161 """ 162 cdef int* int_ptr 163 164cdef class NoReduceDueToNontrivialCInit(object): 165 """ 166 >>> import pickle 167 >>> pickle.dumps(NoReduceDueToNontrivialCInit(None)) 168 Traceback (most recent call last): 169 ... 170 TypeError: no default __reduce__ due to non-trivial __cinit__ 171 """ 172 def __cinit__(self, arg): 173 pass 174 175 176cdef class NoMembers(object): 177 """ 178 >>> import pickle 179 >>> pickle.loads(pickle.dumps(NoMembers())) 180 NoMembers() 181 """ 182 def __repr__(self): 183 return "NoMembers()" 184 185 186cdef class NoPyMembers(object): 187 """ 188 >>> import pickle 189 >>> pickle.loads(pickle.dumps(NoPyMembers(2, 1.75))) 190 NoPyMembers(ii=[2, 4, 8], x=1.75) 191 """ 192 cdef int[3] ii 193 cdef double x 194 195 def __init__(self, i, x): 196 self.ii[0] = i 197 self.ii[1] = i * i 198 self.ii[2] = i * i * i 199 self.x = x 200 201 def __repr__(self): 202 return "%s(ii=%s, x=%s)" % (type(self).__name__, self.ii, self.x) 203 204class NoPyMembersPySubclass(NoPyMembers): 205 """ 206 >>> import pickle 207 >>> pickle.loads(pickle.dumps(NoPyMembersPySubclass(2, 1.75, 'xyz'))) 208 NoPyMembersPySubclass(ii=[2, 4, 8], x=1.75, s='xyz') 209 """ 210 def __init__(self, i, x, s): 211 super(NoPyMembersPySubclass, self).__init__(i, x) 212 self.s = s 213 def __repr__(self): 214 return (super(NoPyMembersPySubclass, self).__repr__() 215 [:-1] + ', s=%r)' % self.s) 216 217 218cdef struct MyStruct: 219 int i 220 double x 221 222cdef class StructMemberDefault(object): 223 """ 224 >>> import pickle 225 >>> s = StructMemberDefault(1, 1.5); s 226 StructMemberDefault(i=1, x=1.5) 227 >>> pickle.dumps(s) # doctest: +ELLIPSIS 228 Traceback (most recent call last): 229 TypeError: ...my_struct... 230 """ 231 232 cdef MyStruct my_struct 233 234 def __init__(self, i, x): 235 self.my_struct.i = i 236 self.my_struct.x = x 237 238 def __repr__(self): 239 return "%s(i=%s, x=%s)" % ( 240 type(self).__name__, self.my_struct.i, self.my_struct.x) 241 242@cython.auto_pickle(True) # Forced due to the (inherited) struct attribute. 243cdef class StructMemberForcedPickle(StructMemberDefault): 244 """ 245 >>> import pickle 246 >>> s = StructMemberForcedPickle(1, 1.5); s 247 StructMemberForcedPickle(i=1, x=1.5) 248 >>> pickle.loads(pickle.dumps(s)) 249 StructMemberForcedPickle(i=1, x=1.5) 250 """ 251 252 253cdef _unset = object() 254 255# Test cyclic references. 256cdef class Wrapper(object): 257 """ 258 >>> import pickle 259 >>> w = Wrapper(); w 260 Wrapper(...) 261 >>> w2 = pickle.loads(pickle.dumps(w)); w2 262 Wrapper(...) 263 >>> w2.ref is w2 264 True 265 266 >>> pickle.loads(pickle.dumps(Wrapper(DefaultReduce(1, 'xyz')))) 267 Wrapper(DefaultReduce(i=1, s='xyz')) 268 >>> L = [None] 269 >>> L[0] = L 270 >>> w = Wrapper(L) 271 >>> pickle.loads(pickle.dumps(Wrapper(L))) 272 Wrapper([[...]]) 273 274 >>> L[0] = w # Don't print this one out... 275 >>> w2 = pickle.loads(pickle.dumps(w)) 276 >>> w2.ref[0] is w2 277 True 278 """ 279 cdef public object ref 280 def __init__(self, ref=_unset): 281 if ref is _unset: 282 self.ref = self 283 else: 284 self.ref = ref 285 def __repr__(self): 286 if self.ref is self: 287 return "Wrapper(...)" 288 else: 289 return "Wrapper(%r)" % self.ref 290 291 292# Non-regression test for pickling bound and unbound methods of non-extension 293# classes 294if sys.version_info[:2] >= (3, 5): 295 # builtin methods not picklable for python <= 3.4 296 class MyClass(object): 297 """ 298 >>> import pickle 299 >>> pickle.loads(pickle.dumps(MyClass.my_method)) is MyClass.my_method 300 True 301 >>> bound_method = pickle.loads(pickle.dumps(MyClass().my_method)) 302 >>> bound_method(1) 303 1 304 """ 305 def my_method(self, x): 306 return x 307