summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2013-09-15 03:51:57 (GMT)
committerRaymond Hettinger <python@rcn.com>2013-09-15 03:51:57 (GMT)
commit46f5ca31d0856f5d258d86085047eda296ee9972 (patch)
tree43404ae894e1ac40995ef165f165df1fb3950442
parent0a32d92bffc9c845253718c43e7ae91cf62bacda (diff)
downloadcpython-46f5ca31d0856f5d258d86085047eda296ee9972.zip
cpython-46f5ca31d0856f5d258d86085047eda296ee9972.tar.gz
cpython-46f5ca31d0856f5d258d86085047eda296ee9972.tar.bz2
Issue #19018: The heapq.merge() function no longer suppresses IndexError
-rw-r--r--Lib/heapq.py14
-rw-r--r--Lib/test/test_heapq.py9
-rw-r--r--Misc/ACKS2
-rw-r--r--Misc/NEWS3
4 files changed, 23 insertions, 5 deletions
diff --git a/Lib/heapq.py b/Lib/heapq.py
index 00b429c..d615239 100644
--- a/Lib/heapq.py
+++ b/Lib/heapq.py
@@ -358,6 +358,7 @@ def merge(*iterables):
'''
_heappop, _heapreplace, _StopIteration = heappop, heapreplace, StopIteration
+ _len = len
h = []
h_append = h.append
@@ -369,17 +370,20 @@ def merge(*iterables):
pass
heapify(h)
- while 1:
+ while _len(h) > 1:
try:
- while 1:
- v, itnum, next = s = h[0] # raises IndexError when h is empty
+ while True:
+ v, itnum, next = s = h[0]
yield v
s[0] = next() # raises StopIteration when exhausted
_heapreplace(h, s) # restore heap condition
except _StopIteration:
_heappop(h) # remove empty iterator
- except IndexError:
- return
+ if h:
+ # fast case when only a single iterator remains
+ v, itnum, next = h[0]
+ yield v
+ yield from next.__self__
# Extend the implementations of nsmallest and nlargest to use a key= argument
_nsmallest = nsmallest
diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py
index b48ca68..b5a2fd8 100644
--- a/Lib/test/test_heapq.py
+++ b/Lib/test/test_heapq.py
@@ -158,6 +158,15 @@ class TestHeap:
self.assertEqual(sorted(chain(*inputs)), list(self.module.merge(*inputs)))
self.assertEqual(list(self.module.merge()), [])
+ def test_merge_does_not_suppress_index_error(self):
+ # Issue 19018: Heapq.merge suppresses IndexError from user generator
+ def iterable():
+ s = list(range(10))
+ for i in range(20):
+ yield s[i] # IndexError when i > 10
+ with self.assertRaises(IndexError):
+ list(self.module.merge(iterable(), iterable()))
+
def test_merge_stability(self):
class Int(int):
pass
diff --git a/Misc/ACKS b/Misc/ACKS
index 9781600..b5ebf06 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -133,6 +133,7 @@ Paul Boddie
Matthew Boedicker
Robin Boerdijk
David Bolen
+Wouter Bolsterlee
Gawain Bolton
Forest Bond
Gregory Bond
@@ -382,6 +383,7 @@ Nils Fischbeck
Frederik Fix
Matt Fleming
Hernán Martínez Foffani
+Artem Fokin
Arnaud Fontaine
Michael Foord
Amaury Forgeot d'Arc
diff --git a/Misc/NEWS b/Misc/NEWS
index 1655238..f74cdb1 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -72,6 +72,9 @@ Library
- Issue #17324: Fix http.server's request handling case on trailing '/'. Patch
contributed by Vajrasky Kok.
+- Issue #19018: The heapq.merge() function no longer suppresses IndexError
+ in the underlying iterables.
+
- Issue #18784: The uuid module no more attempts to load libc via ctypes.CDLL,
if all necessary functions are already found in libuuid.
Patch by Evgeny Sologubov.