Issue #26015: Added new tests for pickling iterators of mutable sequences.

This commit is contained in:
Serhiy Storchaka 2016-03-06 14:10:24 +02:00
parent d55162517d
commit aabafe7bc2
6 changed files with 212 additions and 46 deletions

View File

@ -284,19 +284,42 @@ class BaseTest:
self.assertEqual(type(a), type(b)) self.assertEqual(type(a), type(b))
def test_iterator_pickle(self): def test_iterator_pickle(self):
data = array.array(self.typecode, self.example) orig = array.array(self.typecode, self.example)
data = list(orig)
data2 = data[::-1]
for proto in range(pickle.HIGHEST_PROTOCOL + 1): for proto in range(pickle.HIGHEST_PROTOCOL + 1):
orgit = iter(data) # initial iterator
d = pickle.dumps(orgit, proto) itorig = iter(orig)
it = pickle.loads(d) d = pickle.dumps((itorig, orig), proto)
self.assertEqual(type(orgit), type(it)) it, a = pickle.loads(d)
self.assertEqual(list(it), list(data)) a.fromlist(data2)
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data + data2)
if len(data): # running iterator
it = pickle.loads(d) next(itorig)
next(it) d = pickle.dumps((itorig, orig), proto)
d = pickle.dumps(it, proto) it, a = pickle.loads(d)
self.assertEqual(list(it), list(data)[1:]) a.fromlist(data2)
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data[1:] + data2)
# empty iterator
for i in range(1, len(data)):
next(itorig)
d = pickle.dumps((itorig, orig), proto)
it, a = pickle.loads(d)
a.fromlist(data2)
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data2)
# exhausted iterator
self.assertRaises(StopIteration, next, itorig)
d = pickle.dumps((itorig, orig), proto)
it, a = pickle.loads(d)
a.fromlist(data2)
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data2)
def test_insert(self): def test_insert(self):
a = array.array(self.typecode, self.example) a = array.array(self.typecode, self.example)

View File

@ -595,10 +595,9 @@ class BaseBytesTest:
self.assertEqual(list(it), data) self.assertEqual(list(it), data)
it = pickle.loads(d) it = pickle.loads(d)
try: if not b:
next(it)
except StopIteration:
continue continue
next(it)
d = pickle.dumps(it, proto) d = pickle.dumps(it, proto)
it = pickle.loads(d) it = pickle.loads(d)
self.assertEqual(list(it), data[1:]) self.assertEqual(list(it), data[1:])
@ -1284,6 +1283,43 @@ class ByteArrayTest(BaseBytesTest, unittest.TestCase):
from _testcapi import getbuffer_with_null_view from _testcapi import getbuffer_with_null_view
self.assertRaises(BufferError, getbuffer_with_null_view, bytearray()) self.assertRaises(BufferError, getbuffer_with_null_view, bytearray())
def test_iterator_pickling2(self):
orig = bytearray(b'abc')
data = list(b'qwerty')
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
# initial iterator
itorig = iter(orig)
d = pickle.dumps((itorig, orig), proto)
it, b = pickle.loads(d)
b[:] = data
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data)
# running iterator
next(itorig)
d = pickle.dumps((itorig, orig), proto)
it, b = pickle.loads(d)
b[:] = data
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data[1:])
# empty iterator
for i in range(1, len(orig)):
next(itorig)
d = pickle.dumps((itorig, orig), proto)
it, b = pickle.loads(d)
b[:] = data
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data[len(orig):])
# exhausted iterator
self.assertRaises(StopIteration, next, itorig)
d = pickle.dumps((itorig, orig), proto)
it, b = pickle.loads(d)
b[:] = data
self.assertEqual(list(it), [])
class AssortedBytesTest(unittest.TestCase): class AssortedBytesTest(unittest.TestCase):
# #
# Test various combinations of bytes and bytearray # Test various combinations of bytes and bytearray

View File

@ -638,18 +638,45 @@ class TestBasic(unittest.TestCase):
## self.assertEqual(id(e), id(e[-1])) ## self.assertEqual(id(e), id(e[-1]))
def test_iterator_pickle(self): def test_iterator_pickle(self):
data = deque(range(200)) orig = deque(range(200))
data = [i*1.01 for i in orig]
for proto in range(pickle.HIGHEST_PROTOCOL + 1): for proto in range(pickle.HIGHEST_PROTOCOL + 1):
it = itorg = iter(data) # initial iterator
d = pickle.dumps(it, proto) itorg = iter(orig)
it = pickle.loads(d) dump = pickle.dumps((itorg, orig), proto)
self.assertEqual(type(itorg), type(it)) it, d = pickle.loads(dump)
self.assertEqual(list(it), list(data)) for i, x in enumerate(data):
d[i] = x
self.assertEqual(type(it), type(itorg))
self.assertEqual(list(it), data)
it = pickle.loads(d) # running iterator
next(it) next(itorg)
d = pickle.dumps(it, proto) dump = pickle.dumps((itorg, orig), proto)
self.assertEqual(list(it), list(data)[1:]) it, d = pickle.loads(dump)
for i, x in enumerate(data):
d[i] = x
self.assertEqual(type(it), type(itorg))
self.assertEqual(list(it), data[1:])
# empty iterator
for i in range(1, len(data)):
next(itorg)
dump = pickle.dumps((itorg, orig), proto)
it, d = pickle.loads(dump)
for i, x in enumerate(data):
d[i] = x
self.assertEqual(type(it), type(itorg))
self.assertEqual(list(it), [])
# exhausted iterator
self.assertRaises(StopIteration, next, itorg)
dump = pickle.dumps((itorg, orig), proto)
it, d = pickle.loads(dump)
for i, x in enumerate(data):
d[i] = x
self.assertEqual(type(it), type(itorg))
self.assertEqual(list(it), [])
def test_deepcopy(self): def test_deepcopy(self):
mut = [10] mut = [10]

View File

@ -153,6 +153,42 @@ class TestCase(unittest.TestCase):
def test_seq_class_iter(self): def test_seq_class_iter(self):
self.check_iterator(iter(SequenceClass(10)), list(range(10))) self.check_iterator(iter(SequenceClass(10)), list(range(10)))
def test_mutating_seq_class_iter_pickle(self):
orig = SequenceClass(5)
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
# initial iterator
itorig = iter(orig)
d = pickle.dumps((itorig, orig), proto)
it, seq = pickle.loads(d)
seq.n = 7
self.assertIs(type(it), type(itorig))
self.assertEqual(list(it), list(range(7)))
# running iterator
next(itorig)
d = pickle.dumps((itorig, orig), proto)
it, seq = pickle.loads(d)
seq.n = 7
self.assertIs(type(it), type(itorig))
self.assertEqual(list(it), list(range(1, 7)))
# empty iterator
for i in range(1, 5):
next(itorig)
d = pickle.dumps((itorig, orig), proto)
it, seq = pickle.loads(d)
seq.n = 7
self.assertIs(type(it), type(itorig))
self.assertEqual(list(it), list(range(5, 7)))
# exhausted iterator
self.assertRaises(StopIteration, next, itorig)
d = pickle.dumps((itorig, orig), proto)
it, seq = pickle.loads(d)
seq.n = 7
self.assertTrue(isinstance(it, collections.abc.Iterator))
self.assertEqual(list(it), [])
# Test a new_style class with __iter__ but no next() method # Test a new_style class with __iter__ but no next() method
def test_new_style_iter_class(self): def test_new_style_iter_class(self):
class IterClass(object): class IterClass(object):

View File

@ -72,34 +72,76 @@ class ListTest(list_tests.CommonTest):
check(1000000) check(1000000)
def test_iterator_pickle(self): def test_iterator_pickle(self):
# Userlist iterators don't support pickling yet since orig = self.type2test([4, 5, 6, 7])
# they are based on generators. data = [10, 11, 12, 13, 14, 15]
data = self.type2test([4, 5, 6, 7])
for proto in range(pickle.HIGHEST_PROTOCOL + 1): for proto in range(pickle.HIGHEST_PROTOCOL + 1):
it = itorg = iter(data) # initial iterator
d = pickle.dumps(it, proto) itorig = iter(orig)
it = pickle.loads(d) d = pickle.dumps((itorig, orig), proto)
self.assertEqual(type(itorg), type(it)) it, a = pickle.loads(d)
self.assertEqual(self.type2test(it), self.type2test(data)) a[:] = data
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data)
it = pickle.loads(d) # running iterator
next(it) next(itorig)
d = pickle.dumps(it, proto) d = pickle.dumps((itorig, orig), proto)
self.assertEqual(self.type2test(it), self.type2test(data)[1:]) it, a = pickle.loads(d)
a[:] = data
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data[1:])
# empty iterator
for i in range(1, len(orig)):
next(itorig)
d = pickle.dumps((itorig, orig), proto)
it, a = pickle.loads(d)
a[:] = data
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data[len(orig):])
# exhausted iterator
self.assertRaises(StopIteration, next, itorig)
d = pickle.dumps((itorig, orig), proto)
it, a = pickle.loads(d)
a[:] = data
self.assertEqual(list(it), [])
def test_reversed_pickle(self): def test_reversed_pickle(self):
data = self.type2test([4, 5, 6, 7]) orig = self.type2test([4, 5, 6, 7])
data = [10, 11, 12, 13, 14, 15]
for proto in range(pickle.HIGHEST_PROTOCOL + 1): for proto in range(pickle.HIGHEST_PROTOCOL + 1):
it = itorg = reversed(data) # initial iterator
d = pickle.dumps(it, proto) itorig = reversed(orig)
it = pickle.loads(d) d = pickle.dumps((itorig, orig), proto)
self.assertEqual(type(itorg), type(it)) it, a = pickle.loads(d)
self.assertEqual(self.type2test(it), self.type2test(reversed(data))) a[:] = data
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data[len(orig)-1::-1])
it = pickle.loads(d) # running iterator
next(it) next(itorig)
d = pickle.dumps(it, proto) d = pickle.dumps((itorig, orig), proto)
self.assertEqual(self.type2test(it), self.type2test(reversed(data))[1:]) it, a = pickle.loads(d)
a[:] = data
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), data[len(orig)-2::-1])
# empty iterator
for i in range(1, len(orig)):
next(itorig)
d = pickle.dumps((itorig, orig), proto)
it, a = pickle.loads(d)
a[:] = data
self.assertEqual(type(it), type(itorig))
self.assertEqual(list(it), [])
# exhausted iterator
self.assertRaises(StopIteration, next, itorig)
d = pickle.dumps((itorig, orig), proto)
it, a = pickle.loads(d)
a[:] = data
self.assertEqual(list(it), [])
def test_no_comdat_folding(self): def test_no_comdat_folding(self):
# Issue 8847: In the PGO build, the MSVC linker's COMDAT folding # Issue 8847: In the PGO build, the MSVC linker's COMDAT folding

View File

@ -274,6 +274,8 @@ Documentation
Tests Tests
----- -----
- Issue #26015: Added new tests for pickling iterators of mutable sequences.
- Issue #26325: Added test.support.check_no_resource_warning() to check that - Issue #26325: Added test.support.check_no_resource_warning() to check that
no ResourceWarning is emitted. no ResourceWarning is emitted.