[pypy-commit] pypy py3.3: Change classes .__dict__ to be a distinct "mappingproxy" object.
amauryfa
noreply at buildbot.pypy.org
Wed Oct 29 23:54:38 CET 2014
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3.3
Changeset: r74292:759a9ee11989
Date: 2014-10-29 23:52 +0100
http://bitbucket.org/pypy/pypy/changeset/759a9ee11989/
Log: Change classes .__dict__ to be a distinct "mappingproxy" object.
It's a subclass of dict and behaves like before.
But its type can be used to wrap any mapping, and acts as a read-
only proxy to this mapping. For example,
type(int.__dict__)(OrderedDict(...)) is a read-only ordered dict,
and inspect.signature() uses it this way.
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -453,11 +453,8 @@
self._value = value
self.setup(w_type)
- def get_w_value(self, space):
- w_value = self._w_value
- if w_value is None:
- self._w_value = w_value = space.wrap(self._value)
- return w_value
+ def _compute_value(self, space):
+ return self._value.decode('utf-8')
@specialize.memo()
def get_operr_class(valuefmt):
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
@@ -626,7 +626,10 @@
next_item = _new_next('item')
-def create_iterator_classes(dictimpl, override_next_item=None):
+def create_iterator_classes(dictimpl,
+ override_next_key=None,
+ override_next_value=None,
+ override_next_item=None):
if not hasattr(dictimpl, 'wrapkey'):
wrapkey = lambda space, key: key
else:
@@ -647,22 +650,28 @@
self.iterator = strategy.getiterkeys(impl)
BaseIteratorImplementation.__init__(self, space, strategy, impl)
- def next_key_entry(self):
- for key in self.iterator:
- return wrapkey(self.space, key)
- else:
- return None
+ if override_next_key is not None:
+ next_key_entry = override_next_key
+ else:
+ def next_key_entry(self):
+ for key in self.iterator:
+ return wrapkey(self.space, key)
+ else:
+ return None
class IterClassValues(BaseValueIterator):
def __init__(self, space, strategy, impl):
self.iterator = strategy.getitervalues(impl)
BaseIteratorImplementation.__init__(self, space, strategy, impl)
- def next_value_entry(self):
- for value in self.iterator:
- return wrapvalue(self.space, value)
- else:
- return None
+ if override_next_value is not None:
+ next_value_entry = override_next_value
+ else:
+ def next_value_entry(self):
+ for value in self.iterator:
+ return wrapvalue(self.space, value)
+ else:
+ return None
class IterClassItems(BaseItemIterator):
def __init__(self, space, strategy, impl):
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
@@ -1,18 +1,46 @@
-from pypy.objspace.std.dictmultiobject import DictStrategy, create_iterator_classes
+from pypy.objspace.std.dictmultiobject import (
+ W_DictMultiObject, DictStrategy, create_iterator_classes)
from pypy.objspace.std.typeobject import unwrap_cell
+from pypy.objspace.std.stdtypedef import StdTypeDef
from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.gateway import interp2app
from rpython.rlib import rerased
+class W_DictProxyObject(W_DictMultiObject):
+ @staticmethod
+ def descr_new(space, w_type, w_mapping):
+ strategy = space.fromcache(MappingProxyStrategy)
+ storage = strategy.erase(w_mapping)
+ w_obj = space.allocate_instance(W_DictProxyObject, w_type)
+ W_DictProxyObject.__init__(w_obj, space, strategy, storage)
+ return w_obj
+
+ def descr_init(self, space, __args__):
+ pass
+
+ def descr_repr(self, space):
+ return space.wrap(u"mappingproxy(%s)" % (
+ space.unicode_w(W_DictMultiObject.descr_repr(self, space))))
+
+W_DictProxyObject.typedef = StdTypeDef(
+ "mappingproxy", W_DictMultiObject.typedef,
+ __new__ = interp2app(W_DictProxyObject.descr_new),
+ __init__ = interp2app(W_DictProxyObject.descr_init),
+ __repr__ = interp2app(W_DictProxyObject.descr_repr),
+)
+
+
class DictProxyStrategy(DictStrategy):
+ """Exposes a W_TypeObject.dict_w at app-level.
+
+ Uses getdictvalue() and setdictvalue() to access items.
+ """
erase, unerase = rerased.new_erasing_pair("dictproxy")
erase = staticmethod(erase)
unerase = staticmethod(unerase)
- def __init__(w_self, space):
- DictStrategy.__init__(w_self, space)
-
def getitem(self, w_dict, w_key):
space = self.space
w_lookup_type = space.type(w_key)
@@ -108,3 +136,62 @@
return space.wrap(key.decode('utf-8'))
create_iterator_classes(DictProxyStrategy)
+
+
+class MappingProxyStrategy(DictStrategy):
+ """Wraps an applevel mapping in a read-only dictionary."""
+ erase, unerase = rerased.new_erasing_pair("mappingproxy")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def getitem(self, w_dict, w_key):
+ return self.space.getitem(self.unerase(w_dict.dstorage), w_key)
+
+ def setitem(self, w_dict, w_key, w_value):
+ raise oefmt(self.space.w_TypeError,
+ "'%T' object does not support item assignment", w_dict)
+
+ def delitem(self, w_dict, w_key):
+ raise oefmt(self.space.w_TypeError,
+ "'%T' object does not support item deletion", w_dict)
+
+ def length(self, w_dict):
+ return self.space.len_w(self.unerase(w_dict.dstorage))
+
+ def getiterkeys(self, w_dict):
+ return self.space.iter(
+ self.space.call_method(self.unerase(w_dict.dstorage), "keys"))
+
+ def getitervalues(self, w_dict):
+ return self.space.iter(
+ self.space.call_method(self.unerase(w_dict.dstorage), "values"))
+
+ def getiteritems(self, w_dict):
+ return self.space.iter(
+ self.space.call_method(self.unerase(w_dict.dstorage), "items"))
+
+ @staticmethod
+ def override_next_key(iterkeys):
+ w_keys = iterkeys.iterator
+ return iterkeys.space.next(w_keys)
+
+ @staticmethod
+ def override_next_value(itervalues):
+ w_values = itervalues.iterator
+ return itervalues.space.next(w_values)
+
+ @staticmethod
+ def override_next_item(iteritems):
+ w_items = iteritems.iterator
+ w_item = iteritems.space.next(w_items)
+ w_key, w_value = iteritems.space.unpackiterable(w_item, 2)
+ return w_key, w_value
+
+ def clear(self, w_dict):
+ raise oefmt(self.space.w_AttributeError, "clear")
+
+create_iterator_classes(
+ MappingProxyStrategy,
+ override_next_key=MappingProxyStrategy.override_next_key,
+ override_next_value=MappingProxyStrategy.override_next_value,
+ override_next_item=MappingProxyStrategy.override_next_item)
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
@@ -53,12 +53,26 @@
s1 = repr(a.__dict__)
s2 = str(a.__dict__)
assert s1 == s2
- assert s1.startswith('{') and s1.endswith('}')
+ assert s1.startswith('mappingproxy({') 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)
+ raises((AttributeError, TypeError), "int.__dict__.popitem()")
+ raises((AttributeError, TypeError), "int.__dict__.clear()")
+
+ def test_mappingproxy(self):
+ dictproxy = type(int.__dict__)
+ assert dictproxy is not dict
+ assert dictproxy.__name__ == 'mappingproxy'
+ raises(TypeError, dictproxy)
+ mapping = dict(a=1, b=2, c=3)
+ proxy = dictproxy(mapping)
+ assert proxy['a'] == 1
+ assert repr(proxy) == 'mappingproxy(%r)' % mapping
+ assert proxy.keys() == mapping.keys()
+ raises(TypeError, "proxy['a'] = 4")
+ raises(TypeError, "del proxy['a']")
+ raises(AttributeError, "proxy.clear()")
class AppTestUserObjectMethodCache(AppTestUserObject):
spaceconfig = {"objspace.std.withmethodcachecounter": True}
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -438,12 +438,12 @@
def getdict(w_self, space): # returning a dict-proxy!
from pypy.objspace.std.dictproxyobject import DictProxyStrategy
- from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+ from pypy.objspace.std.dictproxyobject import W_DictProxyObject
if w_self.lazyloaders:
w_self._cleanup_() # force un-lazification
strategy = space.fromcache(DictProxyStrategy)
storage = strategy.erase(w_self)
- return W_DictMultiObject(space, strategy, storage)
+ return W_DictProxyObject(space, strategy, storage)
def unwrap(w_self, space):
from pypy.objspace.std.model import UnwrapError
More information about the pypy-commit
mailing list