summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_pickle.py
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2017-11-30 21:30:39 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2017-11-30 21:30:39 (GMT)
commitc91bf742e542dceaf71042a44b5a04fb08bdda70 (patch)
tree62e67f011c71a087b565bc6a12928938ab6a2daa /Lib/test/test_pickle.py
parent92a2c07b71aefc01f84ba4b0eda8e2a45c1a6b65 (diff)
downloadcpython-c91bf742e542dceaf71042a44b5a04fb08bdda70.zip
cpython-c91bf742e542dceaf71042a44b5a04fb08bdda70.tar.gz
cpython-c91bf742e542dceaf71042a44b5a04fb08bdda70.tar.bz2
bpo-28416: Break reference cycles in Pickler and Unpickler subclasses (GH-4080) (#4653)
with the persistent_id() and persistent_load() methods. (cherry picked from commit 986375ebde0dd5ff2b7349e445a06bd28a3a8ee2)
Diffstat (limited to 'Lib/test/test_pickle.py')
-rw-r--r--Lib/test/test_pickle.py65
1 files changed, 63 insertions, 2 deletions
diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py
index ee71c63..895ed48 100644
--- a/Lib/test/test_pickle.py
+++ b/Lib/test/test_pickle.py
@@ -6,6 +6,7 @@ import io
import collections
import struct
import sys
+import weakref
import unittest
from test import support
@@ -117,6 +118,66 @@ class PyIdPersPicklerTests(AbstractIdentityPersistentPicklerTests,
pickler = pickle._Pickler
unpickler = pickle._Unpickler
+ @support.cpython_only
+ def test_pickler_reference_cycle(self):
+ def check(Pickler):
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ f = io.BytesIO()
+ pickler = Pickler(f, proto)
+ pickler.dump('abc')
+ self.assertEqual(self.loads(f.getvalue()), 'abc')
+ pickler = Pickler(io.BytesIO())
+ self.assertEqual(pickler.persistent_id('def'), 'def')
+ r = weakref.ref(pickler)
+ del pickler
+ self.assertIsNone(r())
+
+ class PersPickler(self.pickler):
+ def persistent_id(subself, obj):
+ return obj
+ check(PersPickler)
+
+ class PersPickler(self.pickler):
+ @classmethod
+ def persistent_id(cls, obj):
+ return obj
+ check(PersPickler)
+
+ class PersPickler(self.pickler):
+ @staticmethod
+ def persistent_id(obj):
+ return obj
+ check(PersPickler)
+
+ @support.cpython_only
+ def test_unpickler_reference_cycle(self):
+ def check(Unpickler):
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ unpickler = Unpickler(io.BytesIO(self.dumps('abc', proto)))
+ self.assertEqual(unpickler.load(), 'abc')
+ unpickler = Unpickler(io.BytesIO())
+ self.assertEqual(unpickler.persistent_load('def'), 'def')
+ r = weakref.ref(unpickler)
+ del unpickler
+ self.assertIsNone(r())
+
+ class PersUnpickler(self.unpickler):
+ def persistent_load(subself, pid):
+ return pid
+ check(PersUnpickler)
+
+ class PersUnpickler(self.unpickler):
+ @classmethod
+ def persistent_load(cls, pid):
+ return pid
+ check(PersUnpickler)
+
+ class PersUnpickler(self.unpickler):
+ @staticmethod
+ def persistent_load(pid):
+ return pid
+ check(PersUnpickler)
+
class PyPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests):
@@ -197,7 +258,7 @@ if has_c_implementation:
check_sizeof = support.check_sizeof
def test_pickler(self):
- basesize = support.calcobjsize('5P2n3i2n3iP')
+ basesize = support.calcobjsize('6P2n3i2n3iP')
p = _pickle.Pickler(io.BytesIO())
self.assertEqual(object.__sizeof__(p), basesize)
MT_size = struct.calcsize('3nP0n')
@@ -214,7 +275,7 @@ if has_c_implementation:
0) # Write buffer is cleared after every dump().
def test_unpickler(self):
- basesize = support.calcobjsize('2Pn2P 2P2n2i5P 2P3n6P2n2i')
+ basesize = support.calcobjsize('2P2n2P 2P2n2i5P 2P3n6P2n2i')
unpickler = _pickle.Unpickler
P = struct.calcsize('P') # Size of memo table entry.
n = struct.calcsize('n') # Size of mark table entry.