]> granicus.if.org Git - python/commitdiff
Issue #21321: itertools.islice() now releases the reference to the source iterator...
authorAntoine Pitrou <solipsis@pitrou.net>
Tue, 29 Apr 2014 10:13:46 +0000 (12:13 +0200)
committerAntoine Pitrou <solipsis@pitrou.net>
Tue, 29 Apr 2014 10:13:46 +0000 (12:13 +0200)
Patch by Anton Afanasyev.

Lib/test/test_itertools.py
Misc/ACKS
Misc/NEWS
Modules/itertoolsmodule.c

index 7233e7c270dea2e5b1294e78f463d5969fb35922..291aeb0471413c357ecc31c0517f242cefb5dc4c 100644 (file)
@@ -1,7 +1,7 @@
 import unittest
 from test import test_support
 from itertools import *
-from weakref import proxy
+import weakref
 from decimal import Decimal
 from fractions import Fraction
 import sys
@@ -792,6 +792,15 @@ class TestBasicOps(unittest.TestCase):
         self.assertEqual(list(islice(c, 1, 3, 50)), [1])
         self.assertEqual(next(c), 3)
 
+        # Issue #21321: check source iterator is not referenced
+        # from islice() after the latter has been exhausted
+        it = (x for x in (1, 2))
+        wr = weakref.ref(it)
+        it = islice(it, 1)
+        self.assertIsNotNone(wr())
+        list(it) # exhaust the iterator
+        self.assertIsNone(wr())
+
     def test_takewhile(self):
         data = [1, 3, 5, 20, 2, 4, 6, 8]
         underten = lambda x: x<10
@@ -901,7 +910,7 @@ class TestBasicOps(unittest.TestCase):
 
         # test that tee objects are weak referencable
         a, b = tee(xrange(10))
-        p = proxy(a)
+        p = weakref.proxy(a)
         self.assertEqual(getattr(p, '__class__'), type(b))
         del a
         self.assertRaises(ReferenceError, getattr, p, '__class__')
index 2d0862754982655e86964eea5cce4cf615b42b80..c8c388079701e5fbd9ad3140fddba68af78b1f90 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -17,6 +17,7 @@ Rajiv Abraham
 David Abrahams
 Marc Abramowitz
 Ron Adam
+Anton Afanasyev
 Ali Afshar
 Nitika Agarwal
 Jim Ahlstrom
index f086cc3f6e51fc6497776f5de644d0a915c1d697..ab71e0173ee00b95c4cd13a1f9af362b955164d9 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -46,6 +46,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #21321: itertools.islice() now releases the reference to the source
+  iterator when the slice is exhausted.  Patch by Anton Afanasyev.
+
 - Issue #9291: Do not attempt to re-encode mimetype data read from registry in
   ANSI mode. Initial patches by Dmitry Jemerov & Vladimir Iofik.
 
index c0456b839f7280abc0dc107f6aa4277f91c51330..a7cd3f4a644403f082646303cbd1bafcc8f4cec4 100644 (file)
@@ -1241,19 +1241,22 @@ islice_next(isliceobject *lz)
     Py_ssize_t oldnext;
     PyObject *(*iternext)(PyObject *);
 
+    if (it == NULL)
+        return NULL;
+
     iternext = *Py_TYPE(it)->tp_iternext;
     while (lz->cnt < lz->next) {
         item = iternext(it);
         if (item == NULL)
-            return NULL;
+            goto empty;
         Py_DECREF(item);
         lz->cnt++;
     }
     if (stop != -1 && lz->cnt >= stop)
-        return NULL;
+        goto empty;
     item = iternext(it);
     if (item == NULL)
-        return NULL;
+        goto empty;
     lz->cnt++;
     oldnext = lz->next;
     /* The (size_t) cast below avoids the danger of undefined
@@ -1262,6 +1265,10 @@ islice_next(isliceobject *lz)
     if (lz->next < oldnext || (stop != -1 && lz->next > stop))
         lz->next = stop;
     return item;
+
+empty:
+    Py_CLEAR(lz->it);
+    return NULL;
 }
 
 PyDoc_STRVAR(islice_doc,