Author: Mark Young <marky1...@gmail.com> Branch: py3k Changeset: r84047:e16f720c6101 Date: 2016-04-29 17:02 -0400 http://bitbucket.org/pypy/pypy/changeset/e16f720c6101/
Log: Merged in marky1991/pypy_new/33_fix_itertools (pull request #437) 33_fix_itertools 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 @@ -1204,6 +1204,7 @@ p = proxy(a) self.assertEqual(getattr(p, '__class__'), type(b)) del a + support.gc_collect() self.assertRaises(ReferenceError, getattr, p, '__class__') ans = list('abc') 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 @@ -49,6 +49,8 @@ 'starmap' : 'interp_itertools.W_StarMap', 'takewhile' : 'interp_itertools.W_TakeWhile', 'tee' : 'interp_itertools.tee', + '_tee' : 'interp_itertools.W_TeeIterable', + '_tee_dataobject' : 'interp_itertools.W_TeeChainedListNode', 'zip_longest' : 'interp_itertools.W_ZipLongest', } 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 @@ -318,6 +318,7 @@ def __init__(self, space, w_iterable, w_startstop, args_w): self.iterable = space.iter(w_iterable) self.space = space + self.exhausted = False num_args = len(args_w) @@ -326,7 +327,7 @@ w_stop = w_startstop elif num_args <= 2: if space.is_w(w_startstop, space.w_None): - start = 0 + start = -1 else: start = self.arg_int_w(w_startstop, 0, "Indicies for islice() must be None or non-negative integers") @@ -383,24 +384,24 @@ # has no effect any more if stop > 0: self._ignore_items(stop) - self.iterable = None + self.exhausted = True raise OperationError(self.space.w_StopIteration, self.space.w_None) self.stop = stop - (ignore + 1) if ignore > 0: self._ignore_items(ignore) - if self.iterable is None: + if self.exhausted: raise OperationError(self.space.w_StopIteration, self.space.w_None) try: return self.space.next(self.iterable) except OperationError as e: if e.match(self.space, self.space.w_StopIteration): - self.iterable = None + self.exhausted = True raise def _ignore_items(self, num): w_iterator = self.iterable - if w_iterator is None: + if self.exhausted: raise OperationError(self.space.w_StopIteration, self.space.w_None) tp = self.space.type(w_iterator) @@ -413,18 +414,28 @@ self.space.next(w_iterator) except OperationError as e: if e.match(self.space, self.space.w_StopIteration): - self.iterable = None + self.exhausted = True raise num -= 1 if num <= 0: break def descr_reduce(self, space): + start = self.start + stop = self.stop + if start == -1: + w_start = space.w_None + else: + w_start = space.wrap(start) + if stop == -1: + w_stop = space.w_None + else: + w_stop = space.wrap(stop) return space.newtuple([ space.type(self), space.newtuple([self.iterable, - space.wrap(self.start), - space.wrap(self.stop), + w_start, + w_stop, space.wrap(self.ignore + 1)]), ]) @@ -809,53 +820,130 @@ raise OperationError(space.w_ValueError, space.wrap("n must be >= 0")) if isinstance(w_iterable, W_TeeIterable): # optimization only - chained_list = w_iterable.chained_list + w_chained_list = w_iterable.w_chained_list w_iterator = w_iterable.w_iterator iterators_w = [w_iterable] * n for i in range(1, n): iterators_w[i] = space.wrap(W_TeeIterable(space, w_iterator, - chained_list)) + w_chained_list)) else: w_iterator = space.iter(w_iterable) - chained_list = TeeChainedListNode() + w_chained_list = W_TeeChainedListNode(space) iterators_w = [space.wrap( - W_TeeIterable(space, w_iterator, chained_list)) + W_TeeIterable(space, w_iterator, w_chained_list)) for x in range(n)] return space.newtuple(iterators_w) -class TeeChainedListNode(object): - w_obj = None +class W_TeeChainedListNode(W_Root): + def __init__(self, space): + self.space = space + self.w_next = None + self.w_obj = None + + def reduce_w(self): + list_w = [] + node = self + while node is not None: + if node.w_obj is not None: + list_w.append(node.w_obj) + node = node.w_next + else: + break + space = self.space + if list_w: + return self.space.newtuple([space.type(self), + space.newtuple([]), + space.newtuple([space.newlist(list_w)]) + ]) + else: + return self.space.newtuple([space.type(self), + space.newtuple([])]) + def descr_setstate(self, space, w_state): + state = space.unpackiterable(w_state) + if len(state) != 1: + raise OperationError(space.w_ValueError, + space.wrap("invalid arguments")) + obj_list_w = space.unpackiterable(state[0]) + node = self + for w_obj in obj_list_w: + node.w_obj = w_obj + node.w_next = W_TeeChainedListNode(self.space) + node = node.w_next + +def W_TeeChainedListNode___new__(space, w_subtype): + r = space.allocate_instance(W_TeeChainedListNode, w_subtype) + r.__init__(space) + return space.wrap(r) + +W_TeeChainedListNode.typedef = TypeDef( + 'itertools._tee_dataobject', + __new__ = interp2app(W_TeeChainedListNode___new__), + __weakref__ = make_weakref_descr(W_TeeChainedListNode), + __reduce__ = interp2app(W_TeeChainedListNode.reduce_w), + __setstate__ = interp2app(W_TeeChainedListNode.descr_setstate) +) + +W_TeeChainedListNode.typedef.acceptable_as_base_class = False class W_TeeIterable(W_Root): - def __init__(self, space, w_iterator, chained_list): + def __init__(self, space, w_iterator, w_chained_list=None): self.space = space self.w_iterator = w_iterator - assert chained_list is not None - self.chained_list = chained_list + self.w_chained_list = w_chained_list def iter_w(self): return self.space.wrap(self) def next_w(self): - chained_list = self.chained_list - w_obj = chained_list.w_obj + w_chained_list = self.w_chained_list + if w_chained_list is None: + raise OperationError(self.space.w_StopIteration, self.space.w_None) + w_obj = w_chained_list.w_obj if w_obj is None: - w_obj = self.space.next(self.w_iterator) - chained_list.next = TeeChainedListNode() - chained_list.w_obj = w_obj - self.chained_list = chained_list.next + try: + w_obj = self.space.next(self.w_iterator) + except OperationError, e: + if e.match(self.space, self.space.w_StopIteration): + self.w_chained_list = None + raise + w_chained_list.w_next = W_TeeChainedListNode(self.space) + w_chained_list.w_obj = w_obj + self.w_chained_list = w_chained_list.w_next return w_obj + def reduce_w(self): + return self.space.newtuple([self.space.gettypefor(W_TeeIterable), + self.space.newtuple([self.space.newtuple([])]), + self.space.newtuple([ + self.w_iterator, + self.w_chained_list]) + ]) + def setstate_w(self, w_state): + state = self.space.unpackiterable(w_state) + num_args = len(state) + if num_args != 2: + raise oefmt(self.space.w_TypeError, + "function takes exactly 2 arguments (%d given)", + num_args) + w_iterator, w_chained_list = state + if not isinstance(w_chained_list, W_TeeChainedListNode): + raise oefmt(self.space.w_TypeError, + "must be itertools._tee_dataobject, not %s", + self.space.type(w_chained_list).name) + + self.w_iterator = w_iterator + self.w_chained_list = w_chained_list + def W_TeeIterable___new__(space, w_subtype, w_iterable): - # Obscure and undocumented function. PyPy only supports w_iterable - # being a W_TeeIterable, because the case where it is a general - # iterable is useless and confusing as far as I can tell (as the - # semantics are then slightly different; see the XXX in lib-python's - # test_itertools). - myiter = space.interp_w(W_TeeIterable, w_iterable) - return space.wrap(W_TeeIterable(space, myiter.w_iterator, - myiter.chained_list)) + if isinstance(w_iterable, W_TeeIterable): + myiter = space.interp_w(W_TeeIterable, w_iterable) + w_iterator = myiter.w_iterator + w_chained_list = myiter.w_chained_list + else: + w_iterator = space.iter(w_iterable) + w_chained_list = W_TeeChainedListNode(space) + return W_TeeIterable(space, w_iterator, w_chained_list) W_TeeIterable.typedef = TypeDef( 'itertools._tee', @@ -863,6 +951,8 @@ __iter__ = interp2app(W_TeeIterable.iter_w), __next__ = interp2app(W_TeeIterable.next_w), __weakref__ = make_weakref_descr(W_TeeIterable), + __reduce__ = interp2app(W_TeeIterable.reduce_w), + __setstate__ = interp2app(W_TeeIterable.setstate_w) ) W_TeeIterable.typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -14,7 +14,7 @@ self.index = index def getlength(self, space): - if self.w_seq is None: + if space.is_none(self.w_seq): return space.wrap(0) index = self.index w_length = space.len(self.w_seq) @@ -60,7 +60,7 @@ """Sequence iterator implementation for general sequences.""" def descr_next(self, space): - if self.w_seq is None: + if space.is_none(self.w_seq): raise OperationError(space.w_StopIteration, space.w_None) try: w_item = space.getitem(self.w_seq, space.wrap(self.index)) @@ -79,7 +79,7 @@ def descr_next(self, space): from pypy.objspace.std.listobject import W_ListObject w_seq = self.w_seq - if w_seq is None: + if space.is_none(w_seq): raise OperationError(space.w_StopIteration, space.w_None) assert isinstance(w_seq, W_ListObject) index = self.index @@ -129,7 +129,7 @@ return space.newtuple([new_inst, space.newtuple(tup)]) def descr_length_hint(self, space): - if self.w_seq is None: + if space.is_none(self.w_seq): return space.wrap(0) index = self.index + 1 w_length = space.len(self.w_seq) @@ -147,7 +147,7 @@ return self def descr_next(self, space): - if self.w_seq is None or self.index < 0: + if space.is_none(self.w_seq) or self.index < 0: raise OperationError(space.w_StopIteration, space.w_None) try: w_item = space.getitem(self.w_seq, space.wrap(self.index)) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit