Author: Armin Rigo <[email protected]>
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
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit