Author: Amaury Forgeot d'Arc <amaur...@gmail.com>
Branch: py3.3
Changeset: r81996:e4a76a0698fc
Date: 2016-01-27 09:35 +0100
http://bitbucket.org/pypy/pypy/changeset/e4a76a0698fc/

Log:    Add pickle support to itertools.combinations (and probably
        combinations_with_replacement as well)

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
@@ -1088,6 +1088,42 @@
         self.last_result_w = result_w
         return space.newtuple(result_w)
 
+    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:
+            import pdb;pdb.set_trace()
+            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.append(index)
+        self.last_result_w = [
+            self.pool_w[self.indices[i]]
+            for i in range(self.r)]
+
 @unwrap_spec(r=int)
 def W_Combinations__new__(space, w_subtype, w_iterable, r):
     pool_w = space.fixedview(w_iterable)
@@ -1095,7 +1131,7 @@
         raise OperationError(space.w_ValueError,
             space.wrap("r must be non-negative")
         )
-    indices = range(len(pool_w))
+    indices = range(r)
     res = space.allocate_instance(W_Combinations, w_subtype)
     res.__init__(space, pool_w, indices, r)
     return space.wrap(res)
@@ -1104,6 +1140,8 @@
     __new__ = interp2app(W_Combinations__new__),
     __iter__ = interp2app(W_Combinations.descr__iter__),
     __next__ = interp2app(W_Combinations.descr_next),
+    __reduce__ = interp2app(W_Combinations.descr_reduce),
+    __setstate__ = interp2app(W_Combinations.descr_setstate),
     __doc__ = """\
 combinations(iterable, r) --> combinations object
 
diff --git a/pypy/module/itertools/test/test_itertools.py 
b/pypy/module/itertools/test/test_itertools.py
--- a/pypy/module/itertools/test/test_itertools.py
+++ b/pypy/module/itertools/test/test_itertools.py
@@ -975,6 +975,25 @@
         islice = itertools.islice(myiter, 5, 8)
         raises(StopIteration, islice.__next__)
 
+    def test_combinations_pickle(self):
+        from itertools import combinations
+        import pickle
+        for op in (lambda a:a, lambda a:pickle.loads(pickle.dumps(a))):
+            assert list(op(combinations('abc', 32))) == []     # r > n
+            assert list(op(combinations('ABCD', 2))) == [
+                ('A','B'), ('A','C'), ('A','D'), ('B','C'), ('B','D'), 
('C','D')]
+            testIntermediate = combinations('ABCD', 2)
+            next(testIntermediate)
+            assert list(op(testIntermediate)) == [
+                ('A','C'), ('A','D'), ('B','C'), ('B','D'), ('C','D')]
+
+            assert list(op(combinations(range(4), 3))) == [
+                (0,1,2), (0,1,3), (0,2,3), (1,2,3)]
+            testIntermediate = combinations(range(4), 3)
+            next(testIntermediate)
+            assert list(op(testIntermediate)) == [
+                (0,1,3), (0,2,3), (1,2,3)]
+
 
 class AppTestItertools32:
     spaceconfig = dict(usemodules=['itertools'])
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to