# mode: run # tag: pickle import cython import sys if sys.version_info[0] < 3: __doc__ = """ >>> import cPickle >>> a = A(5); a A(5) >>> cPickle.loads(cPickle.dumps(a)) A(5) >>> b = B(0, 1); b B(x=0, y=1) >>> cPickle.loads(cPickle.dumps(b)) B(x=0, y=1) """ cdef class A: """ >>> a = A(3); a A(3) >>> import pickle >>> pickle.loads(pickle.dumps(a)) A(3) """ cdef int value def __init__(self, value): self.value = value def __repr__(self): return "A(%s)" % self.value def __reduce__(self): return A, (self.value,) cdef class B: """ >>> b = B(x=37, y=389); b B(x=37, y=389) >>> import pickle >>> pickle.loads(pickle.dumps(b)) B(x=37, y=389) """ cdef int x, y def __cinit__(self): self.x = self.y = -1 def __init__(self, x=0, y=0): self.x = x self.y = y def __repr__(self): return "%s(x=%s, y=%s)" % (self.__class__.__name__, self.x, self.y) def __reduce__(self): return makeObj, (type(self), {'x': self.x, 'y': self.y}) def makeObj(obj_type, kwds): return obj_type(**kwds) cdef class C(B): """ >>> import pickle >>> pickle.loads(pickle.dumps(C(x=37, y=389))) C(x=37, y=389) """ pass @cython.auto_pickle(True) # Not needed, just to test the directive. cdef class DefaultReduce(object): """ >>> a = DefaultReduce(11, 'abc'); a DefaultReduce(i=11, s='abc') >>> import pickle >>> pickle.loads(pickle.dumps(a)) DefaultReduce(i=11, s='abc') >>> pickle.loads(pickle.dumps(DefaultReduce(i=11, s=None))) DefaultReduce(i=11, s=None) """ cdef readonly int i cdef readonly str s def __init__(self, i=0, s=None): self.i = i self.s = s def __repr__(self): return "DefaultReduce(i=%s, s=%r)" % (self.i, self.s) cdef class DefaultReduceSubclass(DefaultReduce): """ >>> a = DefaultReduceSubclass(i=11, s='abc', x=1.5); a DefaultReduceSubclass(i=11, s='abc', x=1.5) >>> import pickle >>> pickle.loads(pickle.dumps(a)) DefaultReduceSubclass(i=11, s='abc', x=1.5) """ cdef double x def __init__(self, **kwargs): self.x = kwargs.pop('x', 0) super(DefaultReduceSubclass, self).__init__(**kwargs) def __repr__(self): return "DefaultReduceSubclass(i=%s, s=%r, x=%s)" % (self.i, self.s, self.x) cdef class result(DefaultReduceSubclass): """ >>> a = result(i=11, s='abc', x=1.5); a result(i=11, s='abc', x=1.5) >>> import pickle >>> pickle.loads(pickle.dumps(a)) result(i=11, s='abc', x=1.5) """ def __repr__(self): return "result(i=%s, s=%r, x=%s)" % (self.i, self.s, self.x) class DefaultReducePySubclass(DefaultReduce): """ >>> a = DefaultReducePySubclass(i=11, s='abc', x=1.5); a DefaultReducePySubclass(i=11, s='abc', x=1.5) >>> import pickle >>> pickle.loads(pickle.dumps(a)) DefaultReducePySubclass(i=11, s='abc', x=1.5) >>> a.self_reference = a >>> a2 = pickle.loads(pickle.dumps(a)) >>> a2.self_reference is a2 True """ def __init__(self, **kwargs): self.x = kwargs.pop('x', 0) super(DefaultReducePySubclass, self).__init__(**kwargs) def __repr__(self): return "DefaultReducePySubclass(i=%s, s=%r, x=%s)" % (self.i, self.s, self.x) cdef class NoReduceDueToIntPtr(object): """ >>> import pickle >>> pickle.dumps(NoReduceDueToIntPtr()) Traceback (most recent call last): ... TypeError: self.int_ptr cannot be converted to a Python object for pickling """ cdef int* int_ptr cdef class NoReduceDueToNontrivialCInit(object): """ >>> import pickle >>> pickle.dumps(NoReduceDueToNontrivialCInit(None)) Traceback (most recent call last): ... TypeError: no default __reduce__ due to non-trivial __cinit__ """ def __cinit__(self, arg): pass cdef class NoMembers(object): """ >>> import pickle >>> pickle.loads(pickle.dumps(NoMembers())) NoMembers() """ def __repr__(self): return "NoMembers()" cdef class NoPyMembers(object): """ >>> import pickle >>> pickle.loads(pickle.dumps(NoPyMembers(2, 1.75))) NoPyMembers(ii=[2, 4, 8], x=1.75) """ cdef int[3] ii cdef double x def __init__(self, i, x): self.ii[0] = i self.ii[1] = i * i self.ii[2] = i * i * i self.x = x def __repr__(self): return "%s(ii=%s, x=%s)" % (type(self).__name__, self.ii, self.x) class NoPyMembersPySubclass(NoPyMembers): """ >>> import pickle >>> pickle.loads(pickle.dumps(NoPyMembersPySubclass(2, 1.75, 'xyz'))) NoPyMembersPySubclass(ii=[2, 4, 8], x=1.75, s='xyz') """ def __init__(self, i, x, s): super(NoPyMembersPySubclass, self).__init__(i, x) self.s = s def __repr__(self): return (super(NoPyMembersPySubclass, self).__repr__() [:-1] + ', s=%r)' % self.s) cdef struct MyStruct: int i double x cdef class StructMemberDefault(object): """ >>> import pickle >>> s = StructMemberDefault(1, 1.5); s StructMemberDefault(i=1, x=1.5) >>> pickle.dumps(s) # doctest: +ELLIPSIS Traceback (most recent call last): TypeError: ...my_struct... """ cdef MyStruct my_struct def __init__(self, i, x): self.my_struct.i = i self.my_struct.x = x def __repr__(self): return "%s(i=%s, x=%s)" % ( type(self).__name__, self.my_struct.i, self.my_struct.x) @cython.auto_pickle(True) # Forced due to the (inherited) struct attribute. cdef class StructMemberForcedPickle(StructMemberDefault): """ >>> import pickle >>> s = StructMemberForcedPickle(1, 1.5); s StructMemberForcedPickle(i=1, x=1.5) >>> pickle.loads(pickle.dumps(s)) StructMemberForcedPickle(i=1, x=1.5) """ cdef _unset = object() # Test cyclic references. cdef class Wrapper(object): """ >>> import pickle >>> w = Wrapper(); w Wrapper(...) >>> w2 = pickle.loads(pickle.dumps(w)); w2 Wrapper(...) >>> w2.ref is w2 True >>> pickle.loads(pickle.dumps(Wrapper(DefaultReduce(1, 'xyz')))) Wrapper(DefaultReduce(i=1, s='xyz')) >>> L = [None] >>> L[0] = L >>> w = Wrapper(L) >>> pickle.loads(pickle.dumps(Wrapper(L))) Wrapper([[...]]) >>> L[0] = w # Don't print this one out... >>> w2 = pickle.loads(pickle.dumps(w)) >>> w2.ref[0] is w2 True """ cdef public object ref def __init__(self, ref=_unset): if ref is _unset: self.ref = self else: self.ref = ref def __repr__(self): if self.ref is self: return "Wrapper(...)" else: return "Wrapper(%r)" % self.ref