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