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