[Checkins] SVN: persistent/trunk/ Convert pickling doctests to unittests + Sphinx API docs.
Tres Seaver
cvs-admin at zope.org
Thu Jun 28 22:49:47 UTC 2012
Log message for revision 127155:
Convert pickling doctests to unittests + Sphinx API docs.
Changed:
_U persistent/trunk/
A persistent/trunk/docs/api/pickling.rst
U persistent/trunk/docs/api.rst
U persistent/trunk/persistent/tests/test_pickle.py
U persistent/trunk/persistent/tests/test_pyPersistence.py
-=-
Added: persistent/trunk/docs/api/pickling.rst
===================================================================
--- persistent/trunk/docs/api/pickling.rst (rev 0)
+++ persistent/trunk/docs/api/pickling.rst 2012-06-28 22:49:43 UTC (rev 127155)
@@ -0,0 +1,171 @@
+Pickling Persistent Objects
+===========================
+
+Persistent objects are designed to make the standard Python pickling
+machinery happy:
+
+.. doctest::
+
+ >>> import pickle
+ >>> from persistent.tests.test_pickle import Simple
+ >>> from persistent.tests.test_pickle import print_dict
+
+ >>> x = Simple('x', aaa=1, bbb='foo')
+ >>> print_dict(x.__dict__)
+ {'__name__': 'x', 'aaa': 1, 'bbb': 'foo'}
+
+ >>> print_dict(x.__getstate__())
+ {'__name__': 'x', 'aaa': 1, 'bbb': 'foo'}
+
+ >>> f, (c,), state = x.__reduce__()
+ >>> f.__name__
+ '__newobj__'
+ >>> f.__module__
+ 'copy_reg'
+ >>> c.__name__
+ 'Simple'
+
+ >>> print_dict(state)
+ {'__name__': 'x', 'aaa': 1, 'bbb': 'foo'}
+
+ >>> import pickle
+ >>> pickle.loads(pickle.dumps(x)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 0)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 1)) == x
+ True
+
+ >>> pickle.loads(pickle.dumps(x, 2)) == x
+ True
+
+ >>> x.__setstate__({'z': 1})
+ >>> x.__dict__
+ {'z': 1}
+
+This support even works well for derived classes which customize pickling
+by overriding :meth:`__getnewargs__`, :meth:`__getstate__` and
+:meth:`__setstate__`.
+
+.. doctest::
+
+ >>> from persistent.tests.test_pickle import Custom
+
+ >>> x = Custom('x', 'y')
+ >>> x.__getnewargs__()
+ ('x', 'y')
+ >>> x.a = 99
+
+ >>> (f, (c, ax, ay), a) = x.__reduce__()
+ >>> f.__name__
+ '__newobj__'
+ >>> f.__module__
+ 'copy_reg'
+ >>> c.__name__
+ 'Custom'
+ >>> ax, ay, a
+ ('x', 'y', 99)
+
+ >>> pickle.loads(pickle.dumps(x)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 0)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 1)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 2)) == x
+ True
+
+The support works for derived classes which define :attr:`__slots__`. It
+ignores any slots which map onto the "persistent" namespace (prefixed with
+``_p_``) or the "volatile" namespace (prefixed with ``_v_``):
+
+.. doctest::
+
+ >>> import copy_reg
+ >>> from persistent.tests.test_pickle import SubSlotted
+ >>> x = SubSlotted('x', 'y', 'z')
+
+Note that we haven't yet assiged a value to the ``s4`` attribute:
+
+.. doctest::
+
+ >>> d, s = x.__getstate__()
+ >>> d
+ >>> print_dict(s)
+ {'s1': 'x', 's2': 'y', 's3': 'z'}
+
+ >>> import pickle
+ >>> pickle.loads(pickle.dumps(x)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 0)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 1)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 2)) == x
+ True
+
+
+After assigning it:
+
+.. doctest::
+
+ >>> x.s4 = 'spam'
+
+ >>> d, s = x.__getstate__()
+ >>> d
+ >>> print_dict(s)
+ {'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'}
+
+ >>> pickle.loads(pickle.dumps(x)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 0)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 1)) == x
+ True
+ >>> pickle.loads(pickle.dumps(x, 2)) == x
+ True
+
+:class:`persistent.Persistent` supports derived classes which have base
+classes defining :attr:`__slots`, but which do not define attr:`__slots__`
+themselves:
+
+.. doctest::
+
+ >>> from persistent.tests.test_pickle import SubSubSlotted
+ >>> x = SubSubSlotted('x', 'y', 'z')
+
+ >>> d, s = x.__getstate__()
+ >>> print_dict(d)
+ {}
+ >>> print_dict(s)
+ {'s1': 'x', 's2': 'y', 's3': 'z'}
+
+ >>> import pickle
+ >>> pickle.loads(pickle.dumps(x)) == x
+ 1
+ >>> pickle.loads(pickle.dumps(x, 0)) == x
+ 1
+ >>> pickle.loads(pickle.dumps(x, 1)) == x
+ 1
+ >>> pickle.loads(pickle.dumps(x, 2)) == x
+ 1
+
+ >>> x.s4 = 'spam'
+ >>> x.foo = 'bar'
+ >>> x.baz = 'bam'
+
+ >>> d, s = x.__getstate__()
+ >>> print_dict(d)
+ {'baz': 'bam', 'foo': 'bar'}
+ >>> print_dict(s)
+ {'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'}
+
+ >>> pickle.loads(pickle.dumps(x)) == x
+ 1
+ >>> pickle.loads(pickle.dumps(x, 0)) == x
+ 1
+ >>> pickle.loads(pickle.dumps(x, 1)) == x
+ 1
+ >>> pickle.loads(pickle.dumps(x, 2)) == x
+ 1
+
Modified: persistent/trunk/docs/api.rst
===================================================================
--- persistent/trunk/docs/api.rst 2012-06-28 22:49:40 UTC (rev 127154)
+++ persistent/trunk/docs/api.rst 2012-06-28 22:49:43 UTC (rev 127155)
@@ -5,3 +5,4 @@
:maxdepth: 2
api/interfaces
+ api/pickling
Modified: persistent/trunk/persistent/tests/test_pickle.py
===================================================================
--- persistent/trunk/persistent/tests/test_pickle.py 2012-06-28 22:49:40 UTC (rev 127154)
+++ persistent/trunk/persistent/tests/test_pickle.py 2012-06-28 22:49:43 UTC (rev 127155)
@@ -11,7 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-import unittest
+# Example objects for pickling.
from persistent import Persistent
@@ -42,41 +42,6 @@
def __cmp__(self, other):
return cmpattrs(self, other, '__class__', *(self.__dict__.keys()))
-def test_basic_pickling():
- """
- >>> x = Simple('x', aaa=1, bbb='foo')
-
- >>> print_dict(x.__getstate__())
- {'__name__': 'x', 'aaa': 1, 'bbb': 'foo'}
-
- >>> f, (c,), state = x.__reduce__()
- >>> f.__name__
- '__newobj__'
- >>> f.__module__
- 'copy_reg'
- >>> c.__name__
- 'Simple'
-
- >>> print_dict(state)
- {'__name__': 'x', 'aaa': 1, 'bbb': 'foo'}
-
- >>> import pickle
- >>> pickle.loads(pickle.dumps(x)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 0)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 1)) == x
- 1
-
- >>> pickle.loads(pickle.dumps(x, 2)) == x
- 1
-
- >>> x.__setstate__({'z': 1})
- >>> x.__dict__
- {'z': 1}
-
- """
-
class Custom(Simple):
def __new__(cls, x, y):
@@ -97,88 +62,28 @@
self.a = a
-def test_pickling_w_overrides():
- """
- >>> x = Custom('x', 'y')
- >>> x.a = 99
-
- >>> (f, (c, ax, ay), a) = x.__reduce__()
- >>> f.__name__
- '__newobj__'
- >>> f.__module__
- 'copy_reg'
- >>> c.__name__
- 'Custom'
- >>> ax, ay, a
- ('x', 'y', 99)
-
- >>> import pickle
- >>> pickle.loads(pickle.dumps(x)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 0)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 1)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 2)) == x
- 1
-
- """
-
class Slotted(Persistent):
+
__slots__ = 's1', 's2', '_p_splat', '_v_eek'
+
def __init__(self, s1, s2):
self.s1, self.s2 = s1, s2
self._v_eek = 1
self._p_splat = 2
+
class SubSlotted(Slotted):
+
__slots__ = 's3', 's4'
+
def __init__(self, s1, s2, s3):
Slotted.__init__(self, s1, s2)
self.s3 = s3
-
def __cmp__(self, other):
return cmpattrs(self, other, '__class__', 's1', 's2', 's3', 's4')
-def test_pickling_w_slots_only():
- """
- >>> x = SubSlotted('x', 'y', 'z')
-
- >>> d, s = x.__getstate__()
- >>> d
- >>> print_dict(s)
- {'s1': 'x', 's2': 'y', 's3': 'z'}
-
- >>> import pickle
- >>> pickle.loads(pickle.dumps(x)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 0)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 1)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 2)) == x
- 1
-
- >>> x.s4 = 'spam'
-
- >>> d, s = x.__getstate__()
- >>> d
- >>> print_dict(s)
- {'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'}
-
- >>> pickle.loads(pickle.dumps(x)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 0)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 1)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 2)) == x
- 1
-
- """
-
class SubSubSlotted(SubSlotted):
def __init__(self, s1, s2, s3, **kw):
@@ -191,89 +96,3 @@
return cmpattrs(self, other,
'__class__', 's1', 's2', 's3', 's4',
*(self.__dict__.keys()))
-
-def test_pickling_w_slots():
- """
- >>> x = SubSubSlotted('x', 'y', 'z', aaa=1, bbb='foo')
-
- >>> d, s = x.__getstate__()
- >>> print_dict(d)
- {'aaa': 1, 'bbb': 'foo'}
- >>> print_dict(s)
- {'s1': 'x', 's2': 'y', 's3': 'z'}
-
- >>> import pickle
- >>> pickle.loads(pickle.dumps(x)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 0)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 1)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 2)) == x
- 1
-
- >>> x.s4 = 'spam'
-
- >>> d, s = x.__getstate__()
- >>> print_dict(d)
- {'aaa': 1, 'bbb': 'foo'}
- >>> print_dict(s)
- {'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'}
-
- >>> pickle.loads(pickle.dumps(x)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 0)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 1)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 2)) == x
- 1
-
- """
-
-def test_pickling_w_slots_w_empty_dict():
- """
- >>> x = SubSubSlotted('x', 'y', 'z')
-
- >>> d, s = x.__getstate__()
- >>> print_dict(d)
- {}
- >>> print_dict(s)
- {'s1': 'x', 's2': 'y', 's3': 'z'}
-
- >>> import pickle
- >>> pickle.loads(pickle.dumps(x)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 0)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 1)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 2)) == x
- 1
-
- >>> x.s4 = 'spam'
-
- >>> d, s = x.__getstate__()
- >>> print_dict(d)
- {}
- >>> print_dict(s)
- {'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'}
-
- >>> pickle.loads(pickle.dumps(x)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 0)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 1)) == x
- 1
- >>> pickle.loads(pickle.dumps(x, 2)) == x
- 1
-
- """
-
-
-
-def test_suite():
- from doctest import DocTestSuite
- return unittest.TestSuite((
- DocTestSuite(),
- ))
Modified: persistent/trunk/persistent/tests/test_pyPersistence.py
===================================================================
--- persistent/trunk/persistent/tests/test_pyPersistence.py 2012-06-28 22:49:40 UTC (rev 127154)
+++ persistent/trunk/persistent/tests/test_pyPersistence.py 2012-06-28 22:49:43 UTC (rev 127155)
@@ -788,6 +788,17 @@
self.assertEqual(second, (self._getTargetClass(),))
self.assertEqual(third, None)
+ def test___reduce__w_subclass_having_getnewargs(self):
+ from copy_reg import __newobj__
+ class Derived(self._getTargetClass()):
+ def __getnewargs__(self):
+ return ('a', 'b')
+ inst = Derived()
+ first, second, third = inst.__reduce__()
+ self.failUnless(first is __newobj__)
+ self.assertEqual(second, (Derived, 'a', 'b'))
+ self.assertEqual(third, {})
+
def test___reduce__w_subclass_having_getstate(self):
from copy_reg import __newobj__
class Derived(self._getTargetClass()):
@@ -799,7 +810,7 @@
self.assertEqual(second, (Derived,))
self.assertEqual(third, {})
- def test___reduce__w_subclass_having_gna_and_getstate(self):
+ def test___reduce__w_subclass_having_getnewargs_and_getstate(self):
from copy_reg import __newobj__
class Derived(self._getTargetClass()):
def __getnewargs__(self):
@@ -812,6 +823,74 @@
self.assertEqual(second, (Derived, 'a', 'b'))
self.assertEqual(third, {'foo': 'bar'})
+ def test_pickle_roundtrip_simple(self):
+ import pickle
+ # XXX s.b. 'examples'
+ from persistent.tests.test_pickle import Simple
+ inst = Simple('testing')
+ copy = pickle.loads(pickle.dumps(inst))
+ self.assertEqual(copy, inst)
+ for protocol in 0, 1, 2:
+ copy = pickle.loads(pickle.dumps(inst, protocol))
+ self.assertEqual(copy, inst)
+
+ def test_pickle_roundtrip_w_getnewargs_and_getstate(self):
+ import pickle
+ # XXX s.b. 'examples'
+ from persistent.tests.test_pickle import Custom
+ inst = Custom('x', 'y')
+ copy = pickle.loads(pickle.dumps(inst))
+ self.assertEqual(copy, inst)
+ for protocol in 0, 1, 2:
+ copy = pickle.loads(pickle.dumps(inst, protocol))
+ self.assertEqual(copy, inst)
+
+ def test_pickle_roundtrip_w_slots_missing_slot(self):
+ import pickle
+ # XXX s.b. 'examples'
+ from persistent.tests.test_pickle import SubSlotted
+ inst = SubSlotted('x', 'y', 'z')
+ copy = pickle.loads(pickle.dumps(inst))
+ self.assertEqual(copy, inst)
+ for protocol in 0, 1, 2:
+ copy = pickle.loads(pickle.dumps(inst, protocol))
+ self.assertEqual(copy, inst)
+
+ def test_pickle_roundtrip_w_slots_filled_slot(self):
+ import pickle
+ # XXX s.b. 'examples'
+ from persistent.tests.test_pickle import SubSlotted
+ inst = SubSlotted('x', 'y', 'z')
+ inst.s4 = 'a'
+ copy = pickle.loads(pickle.dumps(inst))
+ self.assertEqual(copy, inst)
+ for protocol in 0, 1, 2:
+ copy = pickle.loads(pickle.dumps(inst, protocol))
+ self.assertEqual(copy, inst)
+
+ def test_pickle_roundtrip_w_slots_and_empty_dict(self):
+ import pickle
+ # XXX s.b. 'examples'
+ from persistent.tests.test_pickle import SubSubSlotted
+ inst = SubSubSlotted('x', 'y', 'z')
+ copy = pickle.loads(pickle.dumps(inst))
+ self.assertEqual(copy, inst)
+ for protocol in 0, 1, 2:
+ copy = pickle.loads(pickle.dumps(inst, protocol))
+ self.assertEqual(copy, inst)
+
+ def test_pickle_roundtrip_w_slots_and_filled_dict(self):
+ import pickle
+ # XXX s.b. 'examples'
+ from persistent.tests.test_pickle import SubSubSlotted
+ inst = SubSubSlotted('x', 'y', 'z', foo='bar', baz='bam')
+ inst.s4 = 'a'
+ copy = pickle.loads(pickle.dumps(inst))
+ self.assertEqual(copy, inst)
+ for protocol in 0, 1, 2:
+ copy = pickle.loads(pickle.dumps(inst, protocol))
+ self.assertEqual(copy, inst)
+
def test__p_activate_from_unsaved(self):
inst = self._makeOne()
inst._p_activate() # noop w/o jar
More information about the checkins
mailing list