Author: Ronan Lamy <[email protected]>
Branch: py3k
Changeset: r83634:255a852e6292
Date: 2016-04-12 20:18 +0100
http://bitbucket.org/pypy/pypy/changeset/255a852e6292/
Log: Merged in marky1991/pypy_new/33_fix_itertools (pull request #424)
Py3k: Fix itertools tests
diff --git a/lib-python/3/test/test_itertools.py
b/lib-python/3/test/test_itertools.py
--- a/lib-python/3/test/test_itertools.py
+++ b/lib-python/3/test/test_itertools.py
@@ -1728,6 +1728,7 @@
class LengthTransparency(unittest.TestCase):
+ @support.impl_detail("__length_hint__() API is undocumented")
def test_repeat(self):
from test.test_iterlen import len
self.assertEqual(len(repeat(None, 50)), 50)
diff --git a/pypy/module/itertools/__init__.py
b/pypy/module/itertools/__init__.py
--- a/pypy/module/itertools/__init__.py
+++ b/pypy/module/itertools/__init__.py
@@ -40,6 +40,7 @@
'cycle' : 'interp_itertools.W_Cycle',
'dropwhile' : 'interp_itertools.W_DropWhile',
'groupby' : 'interp_itertools.W_GroupBy',
+ '_groupby' : 'interp_itertools.W_GroupByIterator',
'filterfalse' : 'interp_itertools.W_FilterFalse',
'islice' : 'interp_itertools.W_ISlice',
'permutations' : 'interp_itertools.W_Permutations',
diff --git a/pypy/module/itertools/interp_itertools.py
b/pypy/module/itertools/interp_itertools.py
--- a/pypy/module/itertools/interp_itertools.py
+++ b/pypy/module/itertools/interp_itertools.py
@@ -114,6 +114,15 @@
else:
s = 'repeat(%s)' % (objrepr,)
return self.space.wrap(s)
+
+ def descr_reduce(self):
+ space = self.space
+ if self.counting:
+ args_w = [self.w_obj, space.wrap(self.count)]
+ else:
+ args_w = [self.w_obj]
+ return space.newtuple([space.gettypefor(W_Repeat),
+ space.newtuple(args_w)])
def W_Repeat___new__(space, w_subtype, w_object, w_times=None):
r = space.allocate_instance(W_Repeat, w_subtype)
@@ -127,6 +136,7 @@
__length_hint__ = interp2app(W_Repeat.length_w),
__next__ = interp2app(W_Repeat.next_w),
__repr__ = interp2app(W_Repeat.repr_w),
+ __reduce__ = interp2app(W_Repeat.descr_reduce),
__doc__ = """Make an iterator that returns object over and over again.
Runs indefinitely unless the times argument is specified. Used
as argument to imap() for invariant parameters to the called
@@ -268,6 +278,10 @@
class W_FilterFalse(W_Filter):
reverse = True
+ def descr_reduce(self, space):
+ args_w = [space.w_None if self.no_predicate else self.w_predicate,
+ self.iterable]
+ return space.newtuple([space.type(self), space.newtuple(args_w)])
def W_FilterFalse___new__(space, w_subtype, w_predicate, w_iterable):
r = space.allocate_instance(W_FilterFalse, w_subtype)
@@ -279,6 +293,7 @@
__new__ = interp2app(W_FilterFalse___new__),
__iter__ = interp2app(W_FilterFalse.iter_w),
__next__ = interp2app(W_FilterFalse.next_w),
+ __reduce__ = interp2app(W_FilterFalse.descr_reduce),
__doc__ = """Make an iterator that filters elements from iterable
returning
only those for which the predicate is False. If predicate is
None, return the items that are false.
@@ -448,11 +463,16 @@
return self.space.wrap(self)
def _advance(self):
+ if self.w_iterables is None:
+ raise OperationError(self.space.w_StopIteration, self.space.w_None)
self.w_it = self.space.iter(self.space.next(self.w_iterables))
def next_w(self):
if not self.w_it:
- self._advance()
+ try:
+ self._advance()
+ except OperationError, e:
+ raise e
try:
return self.space.next(self.w_it)
except OperationError, e:
@@ -462,12 +482,45 @@
while True:
if not e.match(self.space, self.space.w_StopIteration):
raise e
- self._advance() # may raise StopIteration itself
+ try:
+ self._advance() # may raise StopIteration itself
+ except OperationError, e:
+ self.w_iterables = None
+ raise e
try:
return self.space.next(self.w_it)
except OperationError, e:
pass # loop back to the start of _handle_error(e)
+ def descr_reduce(self, space):
+ if self.w_iterables is not None:
+ if self.w_it is not None:
+ inner_contents = [self.w_iterables, self.w_it]
+ else:
+ inner_contents = [self.w_iterables]
+ result_w = [space.type(self),
+ space.newtuple([]),
+ space.newtuple(inner_contents)]
+ else:
+ result_w = [space.type(self),
+ space.newtuple([])]
+ return space.newtuple(result_w)
+ def descr_setstate(self, space, w_state):
+ state = space.unpackiterable(w_state)
+ num_args = len(state)
+ if num_args < 1:
+ raise OperationError(space.w_TypeError,
+ space.wrap("function takes at least 1
argument "
+ "(" + str(num_args) + " given)"))
+ elif num_args == 1:
+ self.w_iterables = state[0]
+ elif num_args == 2:
+ self.w_iterables, self.w_it = state
+ else:
+ raise OperationError(space.w_TypeError,
+ space.wrap("function takes at most 2
arguments "
+ "(" + str(num_args) + " given)"))
+
def W_Chain___new__(space, w_subtype, args_w):
r = space.allocate_instance(W_Chain, w_subtype)
w_args = space.newtuple(args_w)
@@ -488,6 +541,8 @@
__new__ = interp2app(W_Chain___new__),
__iter__ = interp2app(W_Chain.iter_w),
__next__ = interp2app(W_Chain.next_w),
+ __reduce__ = interp2app(W_Chain.descr_reduce),
+ __setstate__ = interp2app(W_Chain.descr_setstate),
from_iterable = interp2app(chain_from_iterable, as_classmethod=True),
__doc__ = """Make an iterator that returns elements from the first
iterable
until it is exhausted, then proceeds to the next iterable, until
@@ -538,6 +593,23 @@
raise OperationError(self.space.w_StopIteration, self.space.w_None)
return [self._fetch(index) for index in range(nb)]
+ def descr_reduce(self, space):
+ result_w = [space.type(self)]
+
+ if self.iterators_w is not None:
+ iterators = [iterator if iterator is not None else
space.newtuple([])
+ for iterator in self.iterators_w]
+ iterators = space.newtuple(iterators)
+ else:
+ iterators = space.newtuple([])
+ result_w = [space.type(self),
+ iterators,
+ self.w_fillvalue]
+
+ return space.newtuple(result_w)
+ def descr_setstate(self, space, w_state):
+ self.w_fillvalue = w_state
+
def W_ZipLongest___new__(space, w_subtype, __args__):
arguments_w, kwds_w = __args__.unpack()
w_fillvalue = space.w_None
@@ -561,6 +633,8 @@
__new__ = interp2app(W_ZipLongest___new__),
__iter__ = interp2app(W_ZipLongest.iter_w),
__next__ = interp2app(W_ZipLongest.next_w),
+ __reduce__ = interp2app(W_ZipLongest.descr_reduce),
+ __setstate__ = interp2app(W_ZipLongest.descr_setstate),
__doc__ = """Return a zip_longest object whose .next() method returns
a tuple where
the i-th element comes from the i-th iterable argument. The .next()
method continues until the longest iterable in the argument sequence
@@ -669,6 +743,13 @@
w_obj = self.space.next(self.w_iterable)
return self.space.call(self.w_fun, w_obj)
+ def descr_reduce(self):
+ return self.space.newtuple([self.space.gettypefor(W_StarMap),
+ self.space.newtuple([
+ self.w_fun,
+ self.w_iterable])
+ ])
+
def W_StarMap___new__(space, w_subtype, w_fun, w_iterable):
r = space.allocate_instance(W_StarMap, w_subtype)
r.__init__(space, w_fun, w_iterable)
@@ -679,6 +760,7 @@
__new__ = interp2app(W_StarMap___new__),
__iter__ = interp2app(W_StarMap.iter_w),
__next__ = interp2app(W_StarMap.next_w),
+ __reduce__ = interp2app(W_StarMap.descr_reduce),
__doc__ = """Make an iterator that computes the function using
arguments
tuples obtained from the iterable. Used instead of imap() when
argument parameters are already grouped in tuples from a single
@@ -871,6 +953,37 @@
self.lookahead = True
self.new_group = True #new group
raise StopIteration
+ def descr_reduce(self, space):
+ if self.started:
+ return space.newtuple([
+ space.type(self),
+ space.newtuple([
+ self.w_iterable,
+ self.w_fun]),
+ space.newtuple([
+ self.w_key,
+ self.w_lookahead,
+ self.w_key])
+ ])
+ else:
+ return space.newtuple([
+ space.type(self),
+ space.newtuple([
+ self.w_iterable,
+ self.w_fun])])
+ def descr_setstate(self, space, w_state):
+ state = space.unpackiterable(w_state)
+ num_args = len(state)
+ if num_args != 3:
+ raise OperationError(space.w_TypeError,
+ space.wrap("function takes exactly 3
arguments "
+ "(" + str(num_args) + " given)"))
+ w_key, w_lookahead, _ = state
+ self.w_key = w_key
+ self.w_lookahead = w_lookahead
+ if self.w_lookahead:
+ self.started = True
+ self.lookahead = True
def W_GroupBy___new__(space, w_subtype, w_iterable, w_key=None):
r = space.allocate_instance(W_GroupBy, w_subtype)
@@ -882,6 +995,8 @@
__new__ = interp2app(W_GroupBy___new__),
__iter__ = interp2app(W_GroupBy.iter_w),
__next__ = interp2app(W_GroupBy.next_w),
+ __reduce__ = interp2app(W_GroupBy.descr_reduce),
+ __setstate__ = interp2app(W_GroupBy.descr_setstate),
__doc__ = """Make an iterator that returns consecutive keys and
groups from the
iterable. The key is a function computing a key value for each
element. If not specified or is None, key defaults to an identity
@@ -924,10 +1039,27 @@
else:
return w_obj
+ def descr_reduce(self, space):
+ return space.newtuple([
+ space.type(self),
+ space.newtuple([
+ space.wrap(self.index),
+ space.wrap(self.groupby)]),
+ ])
+
+def W_GroupByIterator__new__(space, w_subtype, w_index, w_groupby):
+ r = space.allocate_instance(W_GroupByIterator, w_subtype)
+ index = space.int_w(w_index)
+ groupby = space.interp_w(W_GroupBy, w_groupby)
+ r.__init__(space, index, groupby)
+ return space.wrap(r)
+
W_GroupByIterator.typedef = TypeDef(
'itertools._groupby',
+ __new__ = interp2app(W_GroupByIterator__new__),
__iter__ = interp2app(W_GroupByIterator.iter_w),
- __next__ = interp2app(W_GroupByIterator.next_w))
+ __next__ = interp2app(W_GroupByIterator.next_w),
+ __reduce__ = interp2app(W_GroupByIterator.descr_reduce))
W_GroupByIterator.typedef.acceptable_as_base_class = False
@@ -988,10 +1120,12 @@
for gear in self.gears:
if len(gear) == 0:
self.lst = None
+ self.stopped = True
break
else:
self.indices = [0] * len(self.gears)
- self.lst = [gear[0] for gear in self.gears]
+ self.lst = None
+ self.stopped = False
def _rotate_previous_gears(self):
lst = self.lst
@@ -1013,10 +1147,16 @@
x -= 1
else:
self.lst = None
+ self.stopped = True
def fill_next_result(self):
# the last gear is done here, in a function with no loop,
# to allow the JIT to look inside
+ if self.lst is None:
+ self.lst = [None for gear in self.gears]
+ for index, gear in enumerate(self.gears):
+ self.lst[index] = gear[0]
+ return
lst = self.lst
x = len(self.gears) - 1
if x >= 0:
@@ -1029,18 +1169,50 @@
else:
self._rotate_previous_gears()
else:
- self.lst = None
+ self.stopped = True
def iter_w(self, space):
return space.wrap(self)
def next_w(self, space):
- if self.lst is None:
+ if not self.stopped:
+ self.fill_next_result()
+ if self.stopped:
raise OperationError(space.w_StopIteration, space.w_None)
w_result = space.newtuple(self.lst[:])
- self.fill_next_result()
return w_result
+ def descr_reduce(self, space):
+ if not self.stopped:
+ gears = [space.newtuple(gear) for gear in self.gears]
+ result_w = [
+ space.type(self),
+ space.newtuple(gears)
+ ]
+ if self.lst is not None:
+ result_w = result_w + [
+ space.newtuple([
+ space.wrap(index) for index in self.indices])]
+ else:
+ result_w = [
+ space.type(self),
+ space.newtuple([space.newtuple([])])
+ ]
+ return space.newtuple(result_w)
+ def descr_setstate(self, space, w_state):
+ gear_count = len(self.gears)
+ indices_w = space.unpackiterable(w_state)
+ lst = []
+ for i, gear in enumerate(self.gears):
+ w_index = indices_w[i]
+ index = space.int_w(w_index)
+ if index < 0:
+ index = 0
+ if index > gear_count - 1:
+ index = gear_count - 1
+ self.indices[i] = index
+ lst.append(gear[self.indices[i]])
+ self.lst = lst
def W_Product__new__(space, w_subtype, __args__):
arguments_w, kwds_w = __args__.unpack()
@@ -1062,6 +1234,8 @@
__new__ = interp2app(W_Product__new__),
__iter__ = interp2app(W_Product.iter_w),
__next__ = interp2app(W_Product.next_w),
+ __reduce__ = interp2app(W_Product.descr_reduce),
+ __setstate__ = interp2app(W_Product.descr_setstate),
__doc__ = """
Cartesian product of input iterables.
@@ -1179,7 +1353,7 @@
index = max
if index < 0:
index = 0
- self.indices.append(index)
+ self.indices[i] = index
self.last_result_w = [
self.pool_w[self.indices[i]]
for i in range(self.r)]
@@ -1221,6 +1395,41 @@
def max_index(self, j):
return self.indices[j - 1]
+ def descr_reduce(self, space):
+ if self.stopped:
+ pool_w = []
+ else:
+ pool_w = self.pool_w
+ result_w = [
+ space.type(self),
+ space.newtuple([
+ space.newtuple(pool_w), space.wrap(self.r)
+ ])]
+ if self.last_result_w is not None and not self.stopped:
+ # we must pickle the indices and use them for setstate
+ result_w = result_w + [
+ space.newtuple([
+ space.wrap(index) for index in self.indices])]
+ return space.newtuple(result_w)
+
+ def descr_setstate(self, space, w_state):
+ indices_w = space.fixedview(w_state)
+ if len(indices_w) != self.r:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "invalid arguments"))
+ for i in range(self.r):
+ index = space.int_w(indices_w[i])
+ max = self.get_maximum(i)
+ # clamp the index (beware of negative max)
+ if index > max:
+ index = max
+ if index < 0:
+ index = 0
+ self.indices[i] = index
+ self.last_result_w = [
+ self.pool_w[self.indices[i]]
+ for i in range(self.r)]
+
@unwrap_spec(r=int)
def W_CombinationsWithReplacement__new__(space, w_subtype, w_iterable, r):
pool_w = space.fixedview(w_iterable)
@@ -1237,6 +1446,8 @@
__new__ = interp2app(W_CombinationsWithReplacement__new__),
__iter__ = interp2app(W_CombinationsWithReplacement.descr__iter__),
__next__ = interp2app(W_CombinationsWithReplacement.descr_next),
+ __reduce__ = interp2app(W_CombinationsWithReplacement.descr_reduce),
+ __setstate__ = interp2app(W_CombinationsWithReplacement.descr_setstate),
__doc__ = """\
combinations_with_replacement(iterable, r) --> combinations_with_replacement
object
@@ -1253,17 +1464,19 @@
n = len(pool_w)
n_minus_r = n - r
if n_minus_r < 0:
- self.stopped = True
+ self.stopped = self.raised_stop_iteration = True
else:
- self.stopped = False
+ self.stopped = self.raised_stop_iteration = False
self.indices = range(n)
self.cycles = range(n, n_minus_r, -1)
+ self.started = False
def descr__iter__(self, space):
return self
def descr_next(self, space):
if self.stopped:
+ self.raised_stop_iteration = True
raise OperationError(space.w_StopIteration, space.w_None)
r = self.r
indices = self.indices
@@ -1286,7 +1499,63 @@
indices[n1] = num
i -= 1
self.stopped = True
+ if self.started:
+ raise OperationError(space.w_StopIteration, space.w_None)
+ else:
+ self.started = True
return w_result
+ def descr_reduce(self, space):
+ if self.raised_stop_iteration:
+ pool_w = []
+ else:
+ pool_w = self.pool_w
+ result_w = [
+ space.type(self),
+ space.newtuple([
+ space.newtuple(pool_w), space.wrap(self.r)
+ ])]
+ if not self.raised_stop_iteration:
+ # we must pickle the indices and use them for setstate
+ result_w = result_w + [
+ space.newtuple([
+ space.newtuple([
+ space.wrap(index) for index in self.indices]),
+ space.newtuple([
+ space.wrap(num) for num in self.cycles]),
+ space.wrap(self.started)
+ ])]
+ return space.newtuple(result_w)
+ def descr_setstate(self, space, w_state):
+ state = space.unpackiterable(w_state)
+ if len(state) == 3:
+ w_indices, w_cycles, w_started = state
+ indices_w = space.unpackiterable(w_indices)
+ cycles_w = space.unpackiterable(w_cycles)
+ self.started = space.bool_w(w_started)
+ else:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "invalid arguments"))
+
+ if len(indices_w) != len(self.pool_w) or len(cycles_w) != self.r:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "inavalid arguments"))
+
+ n = len(self.pool_w)
+ for i in range(n):
+ index = space.int_w(indices_w[i])
+ if index < 0:
+ index = 0
+ elif index > n-1:
+ index = n-1
+ self.indices[i] = index
+
+ for i in range(self.r):
+ index = space.int_w(cycles_w[i])
+ if index < 1:
+ index = 1
+ elif index > n-i:
+ index = n-i
+ self.cycles[i] = index
def W_Permutations__new__(space, w_subtype, w_iterable, w_r=None):
pool_w = space.fixedview(w_iterable)
@@ -1302,6 +1571,8 @@
__new__ = interp2app(W_Permutations__new__),
__iter__ = interp2app(W_Permutations.descr__iter__),
__next__ = interp2app(W_Permutations.descr_next),
+ __reduce__ = interp2app(W_Permutations.descr_reduce),
+ __setstate__ = interp2app(W_Permutations.descr_setstate),
__doc__ = """\
permutations(iterable[, r]) --> permutations object
@@ -1315,7 +1586,7 @@
def __init__(self, space, w_iterable, w_func=None):
self.space = space
self.w_iterable = w_iterable
- self.w_func = w_func
+ self.w_func = w_func if not space.is_w(w_func, space.w_None) else None
self.w_total = None
def iter_w(self):
@@ -1333,15 +1604,15 @@
self.w_total = self.space.call_function(self.w_func, self.w_total,
w_value)
return self.w_total
- def reduce_w(self):
+ def descr_reduce(self):
space = self.space
w_total = space.w_None if self.w_total is None else self.w_total
w_func = space.w_None if self.w_func is None else self.w_func
return space.newtuple([space.gettypefor(W_Accumulate),
space.newtuple([self.w_iterable, w_func]),
w_total])
- def setstate_w(self, w_total):
- self.w_total = w_total
+ def descr_setstate(self, space, w_state):
+ self.w_total = w_state if not space.is_w(w_state, space.w_None) else
None
def W_Accumulate__new__(space, w_subtype, w_iterable, w_func=None):
r = space.allocate_instance(W_Accumulate, w_subtype)
@@ -1352,8 +1623,8 @@
__new__ = interp2app(W_Accumulate__new__),
__iter__ = interp2app(W_Accumulate.iter_w),
__next__ = interp2app(W_Accumulate.next_w),
- __reduce__ = interp2app(W_Accumulate.reduce_w),
- __setstate__ = interp2app(W_Accumulate.setstate_w),
+ __reduce__ = interp2app(W_Accumulate.descr_reduce),
+ __setstate__ = interp2app(W_Accumulate.descr_setstate),
__doc__ = """\
"accumulate(iterable) --> accumulate object
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit