Unfortunately this commit has some bad effects. Going through an iterator in popitem() will result in O(N**2) behavior for repeated calls. If you look at the r_dict implementation of popitem() you can see the fix there.
Alex On Mon, Feb 20, 2012 at 6:18 AM, cfbolz <nore...@buildbot.pypy.org> wrote: > Author: Carl Friedrich Bolz <cfb...@gmx.de> > Branch: > Changeset: r52670:4b254e123047 > Date: 2012-02-20 12:17 +0100 > http://bitbucket.org/pypy/pypy/changeset/4b254e123047/ > > Log: issue1059 testing > > make the .__dict__.clear method of builtin types raise an error. Fix > popitem on dict proxies (builtin types raise an error, normal types > work normally). > > 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 > @@ -142,6 +142,13 @@ > else: > return result > > + def popitem(self, w_dict): > + space = self.space > + iterator = self.iter(w_dict) > + w_key, w_value = iterator.next() > + self.delitem(w_dict, w_key) > + return (w_key, w_value) > + > def clear(self, w_dict): > strategy = self.space.fromcache(EmptyDictStrategy) > storage = strategy.get_empty_storage() > diff --git a/pypy/objspace/std/dictproxyobject.py > b/pypy/objspace/std/dictproxyobject.py > --- a/pypy/objspace/std/dictproxyobject.py > +++ b/pypy/objspace/std/dictproxyobject.py > @@ -3,7 +3,7 @@ > from pypy.objspace.std.dictmultiobject import W_DictMultiObject, > IteratorImplementation > from pypy.objspace.std.dictmultiobject import DictStrategy > from pypy.objspace.std.typeobject import unwrap_cell > -from pypy.interpreter.error import OperationError > +from pypy.interpreter.error import OperationError, operationerrfmt > > from pypy.rlib import rerased > > @@ -44,7 +44,8 @@ > raise > if not w_type.is_cpytype(): > raise > - # xxx obscure workaround: allow cpyext to write to > type->tp_dict. > + # xxx obscure workaround: allow cpyext to write to > type->tp_dict > + # xxx even in the case of a builtin type. > # xxx like CPython, we assume that this is only done early > after > # xxx the type is created, and we don't invalidate any cache. > w_type.dict_w[key] = w_value > @@ -86,8 +87,14 @@ > for (key, w_value) in > self.unerase(w_dict.dstorage).dict_w.iteritems()] > > def clear(self, w_dict): > - self.unerase(w_dict.dstorage).dict_w.clear() > - self.unerase(w_dict.dstorage).mutated(None) > + space = self.space > + w_type = self.unerase(w_dict.dstorage) > + if (not space.config.objspace.std.mutable_builtintypes > + and not w_type.is_heaptype()): > + msg = "can't clear dictionary of type '%s'" > + raise operationerrfmt(space.w_TypeError, msg, w_type.name) > + w_type.dict_w.clear() > + w_type.mutated(None) > > class DictProxyIteratorImplementation(IteratorImplementation): > def __init__(self, space, strategy, dictimplementation): > diff --git a/pypy/objspace/std/test/test_dictproxy.py > b/pypy/objspace/std/test/test_dictproxy.py > --- a/pypy/objspace/std/test/test_dictproxy.py > +++ b/pypy/objspace/std/test/test_dictproxy.py > @@ -22,6 +22,9 @@ > assert NotEmpty.string == 1 > raises(TypeError, 'NotEmpty.__dict__.setdefault(15, 1)') > > + key, value = NotEmpty.__dict__.popitem() > + assert (key == 'a' and value == 1) or (key == 'b' and value == 4) > + > def test_dictproxyeq(self): > class a(object): > pass > @@ -43,6 +46,11 @@ > assert s1 == s2 > assert s1.startswith('{') and s1.endswith('}') > > + def test_immutable_dict_on_builtin_type(self): > + raises(TypeError, "int.__dict__['a'] = 1") > + raises(TypeError, int.__dict__.popitem) > + raises(TypeError, int.__dict__.clear) > + > class AppTestUserObjectMethodCache(AppTestUserObject): > def setup_class(cls): > cls.space = gettestobjspace( > diff --git a/pypy/objspace/std/test/test_typeobject.py > b/pypy/objspace/std/test/test_typeobject.py > --- a/pypy/objspace/std/test/test_typeobject.py > +++ b/pypy/objspace/std/test/test_typeobject.py > @@ -993,7 +993,9 @@ > raises(TypeError, setattr, list, 'append', 42) > raises(TypeError, setattr, list, 'foobar', 42) > raises(TypeError, delattr, dict, 'keys') > - > + raises(TypeError, 'int.__dict__["a"] = 1') > + raises(TypeError, 'int.__dict__.clear()') > + > def test_nontype_in_mro(self): > class OldStyle: > pass > _______________________________________________ > pypy-commit mailing list > pypy-com...@python.org > http://mail.python.org/mailman/listinfo/pypy-commit > -- "I disapprove of what you say, but I will defend to the death your right to say it." -- Evelyn Beatrice Hall (summarizing Voltaire) "The people's good is the highest law." -- Cicero
_______________________________________________ pypy-dev mailing list pypy-dev@python.org http://mail.python.org/mailman/listinfo/pypy-dev