Index: Lib/test/pickletester.py =================================================================== --- Lib/test/pickletester.py (revision 82908) +++ Lib/test/pickletester.py (working copy) @@ -384,6 +384,8 @@ class AbstractPickleTests(unittest.TestCase): # Subclass must define self.dumps, self.loads. + fast = False # Whether we should be testing the fast mode + _testdata = create_data() def setUp(self): @@ -873,6 +875,36 @@ self.assertEqual(x.foo, y.foo) self.assertEqual(x.bar, y.bar) + def test_stdreducecycle(self): + # Fast mode doesn't support cycles. + if self.fast: + return + + # Test standard __reduce__ implementations (reduce_2 in + # typeobject.c and _reduce_ex in copy_reg.py). Using the no-op + # subclasses is necessary to make those functions used instead + # of going through the pickle implementation's special + # handling of builtin types. + + # Simple cycles + L = MyList() + L.append(L) + d = MyDict() + d[0] = d + for proto in protocols: + newL = self.loads(self.dumps(L, proto)) + self.failUnless(newL[0] is newL) + newd = self.loads(self.dumps(d, proto)) + self.failUnless(d[0] is d) + + # More steps (this puts memoize in the cyclic path) + obj = MyList() + d = {'obj': obj} + obj.append(d) + for proto in protocols: + new = self.loads(self.dumps(obj, proto)) + self.failUnless(new[0]['obj'] is new) + def test_reduce_overrides_default_reduce_ex(self): for proto in protocols: x = REX_one() @@ -1000,6 +1032,21 @@ self.assertEqual(dumped, DATA6) + def test_reduce_cycle(self): + for proto in protocols: + x = REX_four() + try: + self.dumps(x, proto) + except Exception as e: + # XXX: Need reference to real PicklingError + exceps = 'PicklingError', + if self.fast: + exceps += 'ValueError', + if e.__class__.__name__ not in exceps: + raise + else: + self.fail("successfully pickled with reduce cycle") + # Test classes for reduce_ex class REX_one(object): @@ -1038,6 +1085,10 @@ return object.__reduce__(self) # This one used to fail with infinite recursion +class REX_four(object): + def __reduce__(self): + return REX_four, (self,) + # Test classes for newobj class MyInt(int):