]> granicus.if.org Git - python/commitdiff
Issue #25718: Fixed pickling and copying the accumulate() iterator with total is...
authorSerhiy Storchaka <storchaka@gmail.com>
Sun, 6 Mar 2016 12:00:45 +0000 (14:00 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Sun, 6 Mar 2016 12:00:45 +0000 (14:00 +0200)
Lib/test/test_itertools.py
Misc/NEWS
Modules/itertoolsmodule.c

index 5b3ba7e2970547d752ca6c3b9b8c3d781cf5d5ae..08c9f3951f3ee500d446d6d65b25d143fb3f3658 100644 (file)
@@ -1398,6 +1398,16 @@ class TestExamples(unittest.TestCase):
         self.assertEqual(list(copy.deepcopy(it)), accumulated[1:])
         self.assertEqual(list(copy.copy(it)), accumulated[1:])
 
+    def test_accumulate_reducible_none(self):
+        # Issue #25718: total is None
+        it = accumulate([None, None, None], operator.is_)
+        self.assertEqual(next(it), None)
+        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+            it_copy = pickle.loads(pickle.dumps(it, proto))
+            self.assertEqual(list(it_copy), [True, False])
+        self.assertEqual(list(copy.deepcopy(it)), [True, False])
+        self.assertEqual(list(copy.copy(it)), [True, False])
+
     def test_chain(self):
         self.assertEqual(''.join(chain('ABC', 'DEF')), 'ABCDEF')
 
index fd9a4d6cdb1263c45f0329649dcfa234b1544aeb..70e7760fff4c3f827d34370a20167c25cd82aaaf 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -91,6 +91,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #25718: Fixed pickling and copying the accumulate() iterator with
+  total is None.
+
 - Issue #26475: Fixed debugging output for regular expressions with the (?x)
   flag.
 
index cac02ad75a8f509e3c6211771483b307fb5db8ba..11ce5ea075c4709944a59a7b74c87471e82866e6 100644 (file)
@@ -3460,6 +3460,23 @@ accumulate_next(accumulateobject *lz)
 static PyObject *
 accumulate_reduce(accumulateobject *lz)
 {
+    if (lz->total == Py_None) {
+        PyObject *it;
+
+        if (PyType_Ready(&chain_type) < 0)
+            return NULL;
+        if (PyType_Ready(&islice_type) < 0)
+            return NULL;
+        it = PyObject_CallFunction((PyObject *)&chain_type, "(O)O",
+                                   lz->total, lz->it);
+        if (it == NULL)
+            return NULL;
+        it = PyObject_CallFunction((PyObject *)Py_TYPE(lz), "NO",
+                                   it, lz->binop ? lz->binop : Py_None);
+        if (it == NULL)
+            return NULL;
+        return Py_BuildValue("O(NiO)", &islice_type, it, 1, Py_None);
+    }
     return Py_BuildValue("O(OO)O", Py_TYPE(lz),
                             lz->it, lz->binop?lz->binop:Py_None,
                             lz->total?lz->total:Py_None);