[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