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 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 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):
- with self.assertRaises(SystemError):
+ # 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 between 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
- c.__setstate__((dict.fromkeys('defg'), 0))
- take(20, c)
++ with self.assertRaises(TypeError):
+ cycle('defg').__setstate__([list('abcdefg'), 0])
+
+ # The first argument in the setstate tuple must be a list
+ with self.assertRaises(TypeError):
+ c = cycle('defg')
- # The first argument in the setstate tuple must be a list
++ c.__setstate__((tuple('defg'), 0))
++ take(20, c)
+
- self.assertRaises(TypeError, cycle('').__setstate__, [])
- self.assertRaises(TypeError, cycle('').__setstate__, 0)
++ # The second argument in the setstate tuple must be an int
+ with self.assertRaises(TypeError):
+ cycle('defg').__setstate__((list('abcdefg'), 'x'))
+
+ self.assertRaises(TypeError, cycle('').__setstate__, ())
- self.assertRaises(TypeError, cycle('').__setstate__, ((), 0))
- it = cycle('abc')
- it.__setstate__((['de', 'fg'], 0))
- self.assertEqual(list(islice(it, 15)),
- ['a', 'b', 'c', 'de', 'fg',
- 'a', 'b', 'c', 'de', 'fg',
- 'a', 'b', 'c', 'de', 'fg'])
- it = cycle('abc')
- it.__setstate__((['de', 'fg'], 1))
- self.assertEqual(list(islice(it, 15)),
- ['a', 'b', 'c', 'de', 'fg',
- 'de', 'fg', 'de', 'fg', 'de',
- 'fg', 'de', 'fg', 'de', 'fg'])
+ self.assertRaises(TypeError, cycle('').__setstate__, ([],))
+
def test_groupby(self):
# Check whether it accepts arguments correctly
self.assertEqual([], list(groupby([])))
{
PyObject *saved=NULL;
int firstpass;
-
- if (!PyArg_ParseTuple(state, "O!i", &PyList_Type, &saved, &firstpass))
+ if (!PyTuple_Check(state)) {
+ PyErr_SetString(PyExc_TypeError, "state is not a tuple");
+ return NULL;
+ }
+ if (!PyArg_ParseTuple(state, "O!i", &PyList_Type, &saved, &firstpass)) {
return NULL;
- Py_XINCREF(saved);
+ }
+ Py_INCREF(saved);
Py_XSETREF(lz->saved, saved);
lz->firstpass = firstpass != 0;
+ lz->index = 0;
Py_RETURN_NONE;
}
PyObject *indices, *cycles, *result;
Py_ssize_t n, i;
+ if (!PyTuple_Check(state)) {
+ PyErr_SetString(PyExc_TypeError, "state is not a tuple");
+ return NULL;
+ }
if (!PyArg_ParseTuple(state, "O!O!",
&PyTuple_Type, &indices,
- &PyTuple_Type, &cycles))
+ &PyTuple_Type, &cycles)) {
return NULL;
+ }
n = PyTuple_GET_SIZE(po->pool);
- if (PyTuple_GET_SIZE(indices) != n ||
- PyTuple_GET_SIZE(cycles) != po->r)
- {
+ if (PyTuple_GET_SIZE(indices) != n || PyTuple_GET_SIZE(cycles) != po->r) {
PyErr_SetString(PyExc_ValueError, "invalid arguments");
return NULL;
}