Issue #3873: Speed up unpickling from file objects which have a peek()
method.
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
index 33c85dc..7645b54 100644
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -30,6 +30,21 @@
n += 1
return n
+
+class UnseekableIO(io.BytesIO):
+ def peek(self, *args):
+ raise NotImplementedError
+
+ def seekable(self):
+ return False
+
+ def seek(self, *args):
+ raise io.UnsupportedOperation
+
+ def tell(self):
+ raise io.UnsupportedOperation
+
+
# We can't very well test the extension registry without putting known stuff
# in it, but we have to be careful to restore its original state. Code
# should do this:
@@ -1072,9 +1087,10 @@
# Test the correctness of internal buffering routines when handling
# large data.
for proto in protocols:
- data = (1, b'x' * (256 * 1024))
+ data = (1, min, b'xy' * (30 * 1024), len)
dumped = self.dumps(data, proto)
loaded = self.loads(dumped)
+ self.assertEqual(len(loaded), len(data))
self.assertEqual(loaded, data)
@@ -1373,6 +1389,31 @@
f.seek(0)
self.assertEqual(unpickler.load(), data2)
+ def _check_multiple_unpicklings(self, ioclass):
+ for proto in protocols:
+ data1 = [(x, str(x)) for x in range(2000)] + [b"abcde", len]
+ f = ioclass()
+ pickler = self.pickler_class(f, protocol=proto)
+ pickler.dump(data1)
+ pickled = f.getvalue()
+
+ N = 5
+ f = ioclass(pickled * N)
+ unpickler = self.unpickler_class(f)
+ for i in range(N):
+ if f.seekable():
+ pos = f.tell()
+ self.assertEqual(unpickler.load(), data1)
+ if f.seekable():
+ self.assertEqual(f.tell(), pos + len(pickled))
+ self.assertRaises(EOFError, unpickler.load)
+
+ def test_multiple_unpicklings_seekable(self):
+ self._check_multiple_unpicklings(io.BytesIO)
+
+ def test_multiple_unpicklings_unseekable(self):
+ self._check_multiple_unpicklings(UnseekableIO)
+
if __name__ == "__main__":
# Print some stuff that can be used to rewrite DATA{0,1,2}