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