Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r78329:f35f84a382a9
Date: 2015-06-27 15:19 +0200
http://bitbucket.org/pypy/pypy/changeset/f35f84a382a9/

Log:    Test and fix for a case of mutating kwargs dictionaries. Thanks
        Mitsuhiko

diff --git a/pypy/objspace/std/dictmultiobject.py 
b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -711,7 +711,7 @@
     next_item = _new_next('item')
 
 
-def create_iterator_classes(dictimpl, override_next_item=None):
+def create_iterator_classes(dictimpl):
     if not hasattr(dictimpl, 'wrapkey'):
         wrapkey = lambda space, key: key
     else:
@@ -754,15 +754,12 @@
             self.iterator = strategy.getiteritems(impl)
             BaseIteratorImplementation.__init__(self, space, strategy, impl)
 
-        if override_next_item is not None:
-            next_item_entry = override_next_item
-        else:
-            def next_item_entry(self):
-                for key, value in self.iterator:
-                    return (wrapkey(self.space, key),
-                            wrapvalue(self.space, value))
-                else:
-                    return None, None
+        def next_item_entry(self):
+            for key, value in self.iterator:
+                return (wrapkey(self.space, key),
+                        wrapvalue(self.space, value))
+            else:
+                return None, None
 
     class IterClassReversed(BaseKeyIterator):
         def __init__(self, space, strategy, impl):
@@ -795,22 +792,7 @@
     def rev_update1_dict_dict(self, w_dict, w_updatedict):
         # the logic is to call prepare_dict_update() after the first setitem():
         # it gives the w_updatedict a chance to switch its strategy.
-        if override_next_item is not None:
-            # this is very similar to the general version, but the difference
-            # is that it is specialized to call a specific next_item()
-            iteritems = IterClassItems(self.space, self, w_dict)
-            w_key, w_value = iteritems.next_item()
-            if w_key is None:
-                return
-            w_updatedict.setitem(w_key, w_value)
-            w_updatedict.strategy.prepare_update(w_updatedict,
-                                                 w_dict.length() - 1)
-            while True:
-                w_key, w_value = iteritems.next_item()
-                if w_key is None:
-                    return
-                w_updatedict.setitem(w_key, w_value)
-        else:
+        if 1:     # (preserve indentation)
             iteritems = self.getiteritems(w_dict)
             if not same_strategy(self, w_updatedict):
                 # Different strategy.  Try to copy one item of w_dict
diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py
--- a/pypy/objspace/std/kwargsdict.py
+++ b/pypy/objspace/std/kwargsdict.py
@@ -166,19 +166,26 @@
         return iter(self.unerase(w_dict.dstorage)[1])
 
     def getiteritems(self, w_dict):
-        keys = self.unerase(w_dict.dstorage)[0]
-        return iter(range(len(keys)))
+        return Zip(*self.unerase(w_dict.dstorage))
 
     wrapkey = _wrapkey
 
 
-def next_item(self):
-    strategy = self.strategy
-    assert isinstance(strategy, KwargsDictStrategy)
-    for i in self.iterator:
-        keys, values_w = strategy.unerase(self.dictimplementation.dstorage)
-        return _wrapkey(self.space, keys[i]), values_w[i]
-    else:
-        return None, None
+class Zip(object):
+    def __init__(self, list1, list2):
+        assert len(list1) == len(list2)
+        self.list1 = list1
+        self.list2 = list2
+        self.i = 0
 
-create_iterator_classes(KwargsDictStrategy, override_next_item=next_item)
+    def __iter__(self):
+        return self
+
+    def next(self):
+        i = self.i
+        if i >= len(self.list1):
+            raise StopIteration
+        self.i = i + 1
+        return (self.list1[i], self.list2[i])
+
+create_iterator_classes(KwargsDictStrategy)
diff --git a/pypy/objspace/std/test/test_kwargsdict.py 
b/pypy/objspace/std/test/test_kwargsdict.py
--- a/pypy/objspace/std/test/test_kwargsdict.py
+++ b/pypy/objspace/std/test/test_kwargsdict.py
@@ -159,3 +159,10 @@
         assert a == 3
         assert "KwargsDictStrategy" in self.get_strategy(d)
 
+    def test_iteritems_bug(self):
+        def f(**args):
+            return args
+
+        d = f(a=2, b=3, c=4)
+        for key, value in d.iteritems():
+            None in d
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to