Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r54154:7e37a82840df
Date: 2012-04-02 18:14 +0200
http://bitbucket.org/pypy/pypy/changeset/7e37a82840df/

Log:    Another case: iterating should work if the dict strategy changed
        "just" because of a __getitem__. It's workaroundesque but enough, I
        hope.

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
@@ -273,8 +273,7 @@
     def next(self):
         if self.dictimplementation is None:
             return None, None
-        if (self.len != self.dictimplementation.length()
-              or self.strategy is not self.dictimplementation.strategy):
+        if self.len != self.dictimplementation.length():
             self.len = -1   # Make this error state sticky
             raise OperationError(self.space.w_RuntimeError,
                      self.space.wrap("dictionary changed size during 
iteration"))
@@ -282,7 +281,20 @@
         if self.pos < self.len:
             result = self.next_entry()
             self.pos += 1
-            return result
+            if self.strategy is self.dictimplementation.strategy:
+                return result      # common case
+            else:
+                # waaa, obscure case: the strategy changed, but not the
+                # length of the dict.  The (key, value) pair in 'result'
+                # might be out-of-date.  We try to explicitly look up
+                # the key in the dict.
+                w_key = result[0]
+                w_value = self.dictimplementation.getitem(w_key)
+                if w_value is None:
+                    self.len = -1   # Make this error state sticky
+                    raise OperationError(self.space.w_RuntimeError,
+                        self.space.wrap("dictionary changed during iteration"))
+                return (w_key, w_value)
         # no more entries
         self.dictimplementation = None
         return None, None
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py 
b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -811,7 +811,17 @@
         # 'd' is now length 4
         raises(RuntimeError, it.next)
 
-    def test_iter_dict_strategy_only_change(self):
+    def test_iter_dict_strategy_only_change_1(self):
+        d = {1: 2, 3: 4, 5: 6}
+        it = d.iteritems()
+        class Foo(object):
+            def __eq__(self, other):
+                return False
+        d.get(Foo())    # this changes the strategy of 'd'
+        lst = list(it)  # but iterating still works
+        assert sorted(lst) == [(1, 2), (3, 4), (5, 6)]
+
+    def test_iter_dict_strategy_only_change_2(self):
         d = {1: 2, 3: 4, 5: 6}
         it = d.iteritems()
         d['foo'] = 'bar'
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to