From 91ea76bd466bf8853d3b357649b11f7dd046b68b Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 15 Aug 2015 13:51:59 -0700 Subject: Fix crash in itertools.cycle.__setstate__() caused by lack of type checking. Will backport after the 3.6 release is done. --- Lib/test/test_itertools.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'Lib/test/test_itertools.py') diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index fcd886911d..53d65649ff 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -613,6 +613,39 @@ class TestBasicOps(unittest.TestCase): for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, cycle('abc')) + def test_cycle_setstate(self): + # Verify both modes for restoring state + + # Mode 0 is efficient. It uses an incompletely consumed input + # iterator to build a cycle object and then passes in state with + # a list of previously consumed values. There is no data + # overlap bewteen the two. + c = cycle('defg') + c.__setstate__((list('abc'), 0)) + self.assertEqual(take(20, c), list('defgabcdefgabcdefgab')) + + # Mode 1 is inefficient. It starts with a cycle object built + # from an iterator over the remaining elements in a partial + # cycle and then passes in state with all of the previously + # seen values (this overlaps values included in the iterator). + c = cycle('defg') + c.__setstate__((list('abcdefg'), 1)) + self.assertEqual(take(20, c), list('defgabcdefgabcdefgab')) + + # The first argument to setstate needs to be a tuple + with self.assertRaises(SystemError): + cycle('defg').__setstate__([list('abcdefg'), 0]) + + # The first argument in the setstate tuple must be a list + with self.assertRaises(TypeError): + c = cycle('defg') + c.__setstate__((dict.fromkeys('defg'), 0)) + take(20, c) + + # The first argument in the setstate tuple must be a list + with self.assertRaises(TypeError): + cycle('defg').__setstate__((list('abcdefg'), 'x')) + def test_groupby(self): # Check whether it accepts arguments correctly self.assertEqual([], list(groupby([]))) -- cgit v1.2.1 From ec7b354e27b2241ae42fcf7df43276f1d6d912d5 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 15 Aug 2015 14:45:49 -0700 Subject: Add more tests for pickling itertools.cycle --- Lib/test/test_itertools.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'Lib/test/test_itertools.py') diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 53d65649ff..c012efd752 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -613,6 +613,23 @@ class TestBasicOps(unittest.TestCase): for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, cycle('abc')) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + # test with partial consumed input iterable + it = iter('abcde') + c = cycle(it) + _ = [next(c) for i in range(2)] # consume to 2 of 5 inputs + p = pickle.dumps(c, proto) + d = pickle.loads(p) # rebuild the cycle object + self.assertEqual(take(20, d), list('cdeabcdeabcdeabcdeab')) + + # test with completely consumed input iterable + it = iter('abcde') + c = cycle(it) + _ = [next(c) for i in range(7)] # consume to 7 of 5 inputs + p = pickle.dumps(c, proto) + d = pickle.loads(p) # rebuild the cycle object + self.assertEqual(take(20, d), list('cdeabcdeabcdeabcdeab')) + def test_cycle_setstate(self): # Verify both modes for restoring state -- cgit v1.2.1 From c00d6c87853b1a978f7b6e6498c5874873810e49 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 15 Aug 2015 14:47:27 -0700 Subject: Improve comment --- Lib/test/test_itertools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Lib/test/test_itertools.py') diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index c012efd752..81e1711d21 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -617,7 +617,7 @@ class TestBasicOps(unittest.TestCase): # test with partial consumed input iterable it = iter('abcde') c = cycle(it) - _ = [next(c) for i in range(2)] # consume to 2 of 5 inputs + _ = [next(c) for i in range(2)] # consume 2 of 5 inputs p = pickle.dumps(c, proto) d = pickle.loads(p) # rebuild the cycle object self.assertEqual(take(20, d), list('cdeabcdeabcdeabcdeab')) @@ -625,7 +625,7 @@ class TestBasicOps(unittest.TestCase): # test with completely consumed input iterable it = iter('abcde') c = cycle(it) - _ = [next(c) for i in range(7)] # consume to 7 of 5 inputs + _ = [next(c) for i in range(7)] # consume 7 of 5 inputs p = pickle.dumps(c, proto) d = pickle.loads(p) # rebuild the cycle object self.assertEqual(take(20, d), list('cdeabcdeabcdeabcdeab')) -- cgit v1.2.1