[pypy-commit] pypy py3.5-async: merged py3k changes, generatorentry_driver was used twice, that is now allowed

plan_rich pypy.commits at gmail.com
Thu Aug 11 10:18:54 EDT 2016


Author: Richard Plangger <planrichi at gmail.com>
Branch: py3.5-async
Changeset: r86141:ce8bb88f9458
Date: 2016-08-11 16:18 +0200
http://bitbucket.org/pypy/pypy/changeset/ce8bb88f9458/

Log:	merged py3k changes, generatorentry_driver was used twice, that is
	now allowed

diff --git a/lib-python/3/test/test_hash.py b/lib-python/3/test/test_hash.py
--- a/lib-python/3/test/test_hash.py
+++ b/lib-python/3/test/test_hash.py
@@ -198,7 +198,7 @@
 
 class StringlikeHashRandomizationTests(HashRandomizationTests):
     if check_impl_detail(pypy=True):
-        EMPTY_STRING_HASH = -1
+        EMPTY_STRING_HASH = -2
     else:
         EMPTY_STRING_HASH = 0
     repr_ = None
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -326,6 +326,12 @@
                         "of type '%T'", res)
         return res
 
+def get_printable_coroutine_location_genentry(bytecode):
+    return '%s <coroutine>' % (bytecode.get_repr(),)
+coroutineentry_driver = jit.JitDriver(greens=['pycode'],
+                                      reds=['gen', 'w_arg', 'operr'],
+                                      get_printable_location = get_printable_coroutine_location_genentry,
+                                      name='coroutineentry')
 
 class Coroutine(W_Root):
     "A coroutine object."
@@ -511,8 +517,8 @@
         pycode = self.pycode
         if pycode is not None:
             if jit.we_are_jitted() and should_not_inline(pycode):
-                generatorentry_driver.jit_merge_point(gen=self, w_arg=w_arg,
-                                                    operr=operr, pycode=pycode)
+                coroutineentry_driver.jit_merge_point(gen=self, w_arg=w_arg,
+                                                      operr=operr, pycode=pycode)
         return self._send_ex(w_arg, operr)
 
     def _send_ex(self, w_arg, operr):
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
--- a/pypy/module/cppyy/pythonify.py
+++ b/pypy/module/cppyy/pythonify.py
@@ -175,7 +175,7 @@
          "__new__"      : make_new(class_name),
          }
     pycppclass = metacpp(class_name, _drop_cycles(bases), d)
- 
+
     # cache result early so that the class methods can find the class itself
     setattr(scope, final_class_name, pycppclass)
 
@@ -192,13 +192,10 @@
     for dm_name in cppclass.get_datamember_names():
         cppdm = cppclass.get_datamember(dm_name)
 
-        # here, setattr() can not be used, because a data member can shadow one in
-        # its base class, resulting in the __set__() of its base class being called
-        # by setattr(); so, store directly on the dictionary
-        pycppclass.__dict__[dm_name] = cppdm
+        setattr(pycppclass, dm_name, cppdm)
         import cppyy
         if cppyy._is_static(cppdm):     # TODO: make this a method of cppdm
-            metacpp.__dict__[dm_name] = cppdm
+            setattr(metacpp, dm_name, cppdm)
 
     # the call to register will add back-end specific pythonizations and thus
     # needs to run first, so that the generic pythonizations can use them
@@ -413,7 +410,7 @@
         lib = cppyy._load_dictionary(name)
         _loaded_dictionaries[name] = lib
         return lib
-    
+
 def _init_pythonify():
     # cppyy should not be loaded at the module level, as that will trigger a
     # call to space.getbuiltinmodule(), which will cause cppyy to be loaded
diff --git a/pypy/module/cpyext/dictproxyobject.py b/pypy/module/cpyext/dictproxyobject.py
--- a/pypy/module/cpyext/dictproxyobject.py
+++ b/pypy/module/cpyext/dictproxyobject.py
@@ -1,67 +1,7 @@
-# Read-only proxy for mappings. PyPy does not have a separate type for
-# type.__dict__, so PyDictProxy_New has to use a custom read-only mapping.
-
-from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
-from pypy.interpreter.typedef import TypeDef, interp2app
+from pypy.objspace.std.dictproxyobject import W_DictProxyObject
 from pypy.module.cpyext.api import cpython_api, build_type_checkers
 from pypy.module.cpyext.pyobject import PyObject
 
-class W_DictProxyObject(W_Root):
-    "Read-only proxy for mappings."
-
-    def __init__(self, w_mapping):
-        self.w_mapping = w_mapping
-
-    def descr_len(self, space):
-        return space.len(self.w_mapping)
-
-    def descr_getitem(self, space, w_key):
-        return space.getitem(self.w_mapping, w_key)
-
-    def descr_contains(self, space, w_key):
-        return space.contains(self.w_mapping, w_key)
-
-    def descr_iter(self, space):
-        return space.iter(self.w_mapping)
-
-    def descr_str(self, space):
-        return space.str(self.w_mapping)
-
-    def descr_repr(self, space):
-        return space.repr(self.w_mapping)
-
-    @unwrap_spec(w_default=WrappedDefault(None))
-    def get_w(self, space, w_key, w_default):
-        return space.call_method(self.w_mapping, "get", w_key, w_default)
-
-    def keys_w(self, space):
-        return space.call_method(self.w_mapping, "keys")
-
-    def values_w(self, space):
-        return space.call_method(self.w_mapping, "values")
-
-    def items_w(self, space):
-        return space.call_method(self.w_mapping, "items")
-
-    def copy_w(self, space):
-        return space.call_method(self.w_mapping, "copy")
-
-W_DictProxyObject.typedef = TypeDef(
-    'mappingproxy',
-    __len__=interp2app(W_DictProxyObject.descr_len),
-    __getitem__=interp2app(W_DictProxyObject.descr_getitem),
-    __contains__=interp2app(W_DictProxyObject.descr_contains),
-    __iter__=interp2app(W_DictProxyObject.descr_iter),
-    __str__=interp2app(W_DictProxyObject.descr_str),
-    __repr__=interp2app(W_DictProxyObject.descr_repr),
-    get=interp2app(W_DictProxyObject.get_w),
-    keys=interp2app(W_DictProxyObject.keys_w),
-    values=interp2app(W_DictProxyObject.values_w),
-    items=interp2app(W_DictProxyObject.items_w),
-    copy=interp2app(W_DictProxyObject.copy_w)
-)
-
 PyDictProxy_Check, PyDictProxy_CheckExact = build_type_checkers(
     "DictProxy", W_DictProxyObject)
 
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -417,8 +417,7 @@
             init = """PyObject *mod = PyModule_Create(&moduledef);"""
             if more_init:
                 init += more_init
-            else:
-                init += "\nreturn mod;"
+            init += "\nreturn mod;"
             return import_module(space, name=modname, init=init, body=body,
                                  w_include_dirs=w_include_dirs,
                                  PY_SSIZE_T_CLEAN=PY_SSIZE_T_CLEAN)
diff --git a/pypy/module/cpyext/test/test_import_module.c b/pypy/module/cpyext/test/test_import_module.c
--- a/pypy/module/cpyext/test/test_import_module.c
+++ b/pypy/module/cpyext/test/test_import_module.c
@@ -1,17 +1,20 @@
 #include "Python.h"
 /* Initialize this module. */
 
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    "test_import_module",
+    NULL,
+    -1,
+    NULL, NULL, NULL, NULL, NULL
+};
+
 PyMODINIT_FUNC
-inittest_import_module(void)
+PyInit_test_import_module(void)
 {
-	PyObject *m, *d;
-
-	m = Py_InitModule("test_import_module", NULL);
-	if (m == NULL)
-	    return;
-	d = PyModule_GetDict(m);
-	if (d) {
-        PyDict_SetItemString(d, "TEST", (PyObject *) Py_None);
-    }
-   	/* No need to check the error here, the caller will do that */
+    PyObject* m = PyModule_Create(&moduledef);
+    if (m == NULL)
+	    return NULL;
+    PyModule_AddObject(m, "TEST", (PyObject *) Py_None);
+    return m;
 }
diff --git a/pypy/module/cpyext/test/test_number.py b/pypy/module/cpyext/test/test_number.py
--- a/pypy/module/cpyext/test/test_number.py
+++ b/pypy/module/cpyext/test/test_number.py
@@ -1,5 +1,6 @@
 from rpython.rtyper.lltypesystem import lltype
 from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
 
 class TestIterator(BaseApiTest):
     def test_check(self, space, api):
@@ -63,7 +64,9 @@
         assert 9 == space.unwrap(
             api.PyNumber_InPlacePower(space.wrap(3), space.wrap(2), space.w_None))
 
-    def test_PyNumber_Check(self):        
+
+class AppTestCNumber(AppTestCpythonExtensionBase):
+    def test_PyNumber_Check(self):
         mod = self.import_extension('foo', [
             ("test_PyNumber_Check", "METH_VARARGS",
              '''
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -277,9 +277,41 @@
                      args->ob_type->tp_dict, "copy");
                  Py_INCREF(method);
                  return method;
-             ''')])
+             '''),
+            ("get_type_dict", "METH_O",
+             '''
+                PyObject* value = args->ob_type->tp_dict;
+                if (value == NULL) value = Py_None;
+                Py_INCREF(value);
+                return value;
+             '''),
+            ])
         obj = foo.new()
         assert module.read_tp_dict(obj) == foo.fooType.copy
+        d = module.get_type_dict(obj)
+        assert type(d) is dict
+        d["_some_attribute"] = 1
+        assert type(obj)._some_attribute == 1
+        del d["_some_attribute"]
+
+        class A(object):
+            pass
+        obj = A()
+        d = module.get_type_dict(obj)
+        assert type(d) is dict
+        d["_some_attribute"] = 1
+        assert type(obj)._some_attribute == 1
+        del d["_some_attribute"]
+
+        d = module.get_type_dict(1)
+        assert type(d) is dict
+        try:
+            d["_some_attribute"] = 1
+        except TypeError:  # on PyPy, int.__dict__ is really immutable
+            pass
+        else:
+            assert int._some_attribute == 1
+            del d["_some_attribute"]
 
     def test_custom_allocation(self):
         foo = self.import_module("foo")
@@ -348,6 +380,21 @@
 
         api.Py_DecRef(ref)
 
+    def test_type_dict(self, space, api):
+        w_class = space.appexec([], """():
+            class A(object):
+                pass
+            return A
+            """)
+        ref = make_ref(space, w_class)
+
+        py_type = rffi.cast(PyTypeObjectPtr, ref)
+        w_dict = from_ref(space, py_type.c_tp_dict)
+        w_name = space.newunicode(u'a')
+        space.setitem(w_dict, w_name, space.wrap(1))
+        assert space.int_w(space.getattr(w_class, w_name)) == 1
+        space.delitem(w_dict, w_name)
+
     def test_multiple_inheritance(self, space, api):
         w_class = space.appexec([], """():
             class A(object):
@@ -779,7 +826,7 @@
             """, more_init="""
             IntLike_Type.tp_flags |= Py_TPFLAGS_DEFAULT;
             IntLike_Type.tp_as_number = &intlike_as_number;
-            intlike_as_number.nb_bool = intlike_nb_nonzero;
+            intlike_as_number.nb_bool = intlike_nb_bool;
             intlike_as_number.nb_int = intlike_nb_int;
             PyType_Ready(&IntLike_Type);
             """)
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -192,7 +192,7 @@
     py_methoddescr.c_d_method = w_obj.ml
 
 def classmethoddescr_realize(space, obj):
-    # XXX NOT TESTED When is this ever called? 
+    # XXX NOT TESTED When is this ever called?
     method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
     w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
     w_obj = space.allocate_instance(W_PyCClassMethodObject, w_type)
@@ -201,7 +201,7 @@
     return w_obj
 
 def methoddescr_realize(space, obj):
-    # XXX NOT TESTED When is this ever called? 
+    # XXX NOT TESTED When is this ever called?
     method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
     w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
     w_obj = space.allocate_instance(W_PyCMethodObject, w_type)
@@ -272,12 +272,12 @@
         if len(slot_names) == 1:
             if not getattr(pto, slot_names[0]):
                 setattr(pto, slot_names[0], slot_func_helper)
-        elif (w_type.getname(space) in ('list', 'tuple') and 
+        elif (w_type.getname(space) in ('list', 'tuple') and
               slot_names[0] == 'c_tp_as_number'):
             # XXX hack - hwo can we generalize this? The problem is method
             # names like __mul__ map to more than one slot, and we have no
             # convenient way to indicate which slots CPython have filled
-            # 
+            #
             # We need at least this special case since Numpy checks that
             # (list, tuple) do __not__ fill tp_as_number
             pass
@@ -767,8 +767,8 @@
 
     if w_obj.is_cpytype():
         Py_DecRef(space, pto.c_tp_dict)
-        w_dict = w_obj.getdict(space)
-        pto.c_tp_dict = make_ref(space, w_dict)
+    w_dict = w_obj.getdict(space)
+    pto.c_tp_dict = make_ref(space, w_dict)
 
 @cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
 def PyType_IsSubtype(space, a, b):
diff --git a/pypy/module/time/interp_time.py b/pypy/module/time/interp_time.py
--- a/pypy/module/time/interp_time.py
+++ b/pypy/module/time/interp_time.py
@@ -541,6 +541,8 @@
         t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw')
         t_ref[0] = tt
         pbuf = c_localtime(t_ref)
+        rffi.setintfield(pbuf, "c_tm_year",
+                         rffi.getintfield(pbuf, "c_tm_year") + 1900)
         lltype.free(t_ref, flavor='raw')
         if not pbuf:
             raise OperationError(space.w_ValueError,
@@ -584,7 +586,7 @@
     if rffi.getintfield(glob_buf, 'c_tm_wday') < -1:
         raise oefmt(space.w_ValueError, "day of week out of range")
 
-    rffi.setintfield(glob_buf, 'c_tm_year', y - 1900)
+    rffi.setintfield(glob_buf, 'c_tm_year', y)
     rffi.setintfield(glob_buf, 'c_tm_mon',
                      rffi.getintfield(glob_buf, 'c_tm_mon') - 1)
     rffi.setintfield(glob_buf, 'c_tm_wday',
@@ -648,7 +650,8 @@
         t_ref[0] = seconds
         p = c_localtime(t_ref)
     if not p:
-        raise oefmt(space.w_ValueError, "unconvertible time")
+        raise oefmt(space.w_OSError, "unconvertible time")
+    rffi.setintfield(p, "c_tm_year", rffi.getintfield(p, "c_tm_year") + 1900)
     return _asctime(space, p)
 
 # by now w_tup is an optional argument (and not *args)
@@ -677,7 +680,7 @@
             w(getif(t_ref, 'c_tm_hour')),
             w(getif(t_ref, 'c_tm_min')),
             w(getif(t_ref, 'c_tm_sec')),
-            w(getif(t_ref, 'c_tm_year') + 1900)]
+            w(getif(t_ref, 'c_tm_year'))]
     return space.mod(w("%.3s %.3s%3d %.2d:%.2d:%.2d %d"),
                      space.newtuple(args))
 
@@ -715,7 +718,7 @@
     lltype.free(t_ref, flavor='raw')
 
     if not p:
-        raise OperationError(space.w_ValueError, space.wrap(_get_error_msg()))
+        raise OperationError(space.w_OSError, space.wrap(_get_error_msg()))
     return _tm_to_tuple(space, p)
 
 def mktime(space, w_tup):
@@ -725,6 +728,7 @@
 
     buf = _gettmarg(space, w_tup, allowNone=False)
     rffi.setintfield(buf, "c_tm_wday", -1)
+    rffi.setintfield(buf, "c_tm_year", rffi.getintfield(buf, "c_tm_year") - 1900)
     tt = c_mktime(buf)
     # A return value of -1 does not necessarily mean an error, but tm_wday
     # cannot remain set to -1 if mktime succeeds.
@@ -801,6 +805,8 @@
         rffi.setintfield(buf_value, 'c_tm_isdst', -1)
     elif rffi.getintfield(buf_value, 'c_tm_isdst') > 1:
         rffi.setintfield(buf_value, 'c_tm_isdst', 1)
+    rffi.setintfield(buf_value, "c_tm_year",
+                     rffi.getintfield(buf_value, "c_tm_year") - 1900)
 
     if _WIN:
         # check that the format string contains only valid directives
diff --git a/pypy/objspace/std/classdict.py b/pypy/objspace/std/classdict.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/classdict.py
@@ -0,0 +1,119 @@
+from rpython.rlib import rerased
+from rpython.rlib.objectmodel import iteritems_with_hash
+
+from pypy.interpreter.error import OperationError, oefmt
+from pypy.objspace.std.dictmultiobject import (
+    DictStrategy, create_iterator_classes)
+from pypy.objspace.std.typeobject import unwrap_cell
+
+
+class ClassDictStrategy(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 getitem(self, w_dict, w_key):
+        space = self.space
+        w_lookup_type = space.type(w_key)
+        if space.issubtype_w(w_lookup_type, space.w_unicode):
+            return self.getitem_str(w_dict, space.str_w(w_key))
+        else:
+            return None
+
+    def getitem_str(self, w_dict, key):
+        return self.unerase(w_dict.dstorage).getdictvalue(self.space, key)
+
+    def setitem(self, w_dict, w_key, w_value):
+        space = self.space
+        if space.is_w(space.type(w_key), space.w_unicode):
+            self.setitem_str(w_dict, self.space.str_w(w_key), w_value)
+        else:
+            raise oefmt(space.w_TypeError,
+                        "cannot add non-string keys to dict of a type")
+
+    def setitem_str(self, w_dict, key, w_value):
+        w_type = self.unerase(w_dict.dstorage)
+        try:
+            w_type.setdictvalue(self.space, key, w_value)
+        except OperationError as e:
+            if not e.match(self.space, self.space.w_TypeError):
+                raise
+            if not w_type.is_cpytype():
+                raise
+            # Allow cpyext to write to type->tp_dict even in the case
+            # of a builtin type.
+            # Like CPython, we assume that this is only done early
+            # after the type is created, and we don't invalidate any
+            # cache.  User code shoud call PyType_Modified().
+            w_type.dict_w[key] = w_value
+
+    def setdefault(self, w_dict, w_key, w_default):
+        w_result = self.getitem(w_dict, w_key)
+        if w_result is not None:
+            return w_result
+        self.setitem(w_dict, w_key, w_default)
+        return w_default
+
+    def delitem(self, w_dict, w_key):
+        space = self.space
+        w_key_type = space.type(w_key)
+        if space.is_w(w_key_type, space.w_unicode):
+            key = self.space.str_w(w_key)
+            if not self.unerase(w_dict.dstorage).deldictvalue(space, key):
+                raise KeyError
+        else:
+            raise KeyError
+
+    def length(self, w_dict):
+        return len(self.unerase(w_dict.dstorage).dict_w)
+
+    def w_keys(self, w_dict):
+        space = self.space
+        w_type = self.unerase(w_dict.dstorage)
+        return space.newlist([_wrapkey(space, key)
+                              for key in w_type.dict_w.iterkeys()])
+
+    def values(self, w_dict):
+        return [unwrap_cell(self.space, w_value) for w_value in
+                self.unerase(w_dict.dstorage).dict_w.itervalues()]
+
+    def items(self, w_dict):
+        space = self.space
+        w_type = self.unerase(w_dict.dstorage)
+        return [space.newtuple([_wrapkey(space, key),
+                                unwrap_cell(space, w_value)])
+                for (key, w_value) in w_type.dict_w.iteritems()]
+
+    def clear(self, w_dict):
+        space = self.space
+        w_type = self.unerase(w_dict.dstorage)
+        if not w_type.is_heaptype():
+            raise oefmt(space.w_TypeError,
+                        "can't clear dictionary of type '%N'", w_type)
+        w_type.dict_w.clear()
+        w_type.mutated(None)
+
+    def getiterkeys(self, w_dict):
+        return self.unerase(w_dict.dstorage).dict_w.iterkeys()
+
+    def getitervalues(self, w_dict):
+        return self.unerase(w_dict.dstorage).dict_w.itervalues()
+
+    def getiteritems_with_hash(self, w_dict):
+        return iteritems_with_hash(self.unerase(w_dict.dstorage).dict_w)
+
+    def wrapkey(space, key):
+        return _wrapkey(space, key)
+
+    def wrapvalue(space, value):
+        return unwrap_cell(space, value)
+
+def _wrapkey(space, key):
+    # keys are utf-8 encoded identifiers from type's dict_w
+    return space.wrap(key.decode('utf-8'))
+
+create_iterator_classes(ClassDictStrategy)
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,212 +1,95 @@
-from rpython.rlib import rerased
-from rpython.rlib.objectmodel import iteritems_with_hash
+"""
+Read-only proxy for mappings.
 
-from pypy.interpreter.error import OperationError, oefmt
-from pypy.interpreter.gateway import interp2app
-from pypy.interpreter.typedef import TypeDef
-from pypy.objspace.std.dictmultiobject import (
-    DictStrategy, W_DictObject, create_iterator_classes)
-from pypy.objspace.std.typeobject import unwrap_cell
+Its main use is as the return type of cls.__dict__.
+"""
 
+from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.error import oefmt
+from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
+from pypy.interpreter.typedef import TypeDef, interp2app
 
-class W_DictProxyObject(W_DictObject):
+class W_DictProxyObject(W_Root):
+    "Read-only proxy for mappings."
+
+    def __init__(self, w_mapping):
+        self.w_mapping = w_mapping
+
     @staticmethod
     def descr_new(space, w_type, w_mapping):
         if (not space.lookup(w_mapping, "__getitem__") or
-            space.isinstance_w(w_mapping, space.w_list) or
-            space.isinstance_w(w_mapping, space.w_tuple)):
+                space.isinstance_w(w_mapping, space.w_list) or
+                space.isinstance_w(w_mapping, space.w_tuple)):
             raise oefmt(space.w_TypeError,
-                        "mappingproxy() argument must be a mapping, not %T", 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
+                        "mappingproxy() argument must be a mapping, not %T",
+                        w_mapping)
+        return W_DictProxyObject(w_mapping)
 
     def descr_init(self, space, __args__):
         pass
 
+    def descr_len(self, space):
+        return space.len(self.w_mapping)
+
+    def descr_getitem(self, space, w_key):
+        return space.getitem(self.w_mapping, w_key)
+
+    def descr_contains(self, space, w_key):
+        return space.contains(self.w_mapping, w_key)
+
+    def descr_iter(self, space):
+        return space.iter(self.w_mapping)
+
+    def descr_str(self, space):
+        return space.str(self.w_mapping)
+
     def descr_repr(self, space):
-        return space.wrap(u"mappingproxy(%s)" % (
-            space.unicode_w(W_DictObject.descr_repr(self, space))))
+        return space.newunicode(u"mappingproxy(%s)" %
+                                (space.unicode_w(space.repr(self.w_mapping)),))
+
+    @unwrap_spec(w_default=WrappedDefault(None))
+    def get_w(self, space, w_key, w_default):
+        return space.call_method(self.w_mapping, "get", w_key, w_default)
+
+    def keys_w(self, space):
+        return space.call_method(self.w_mapping, "keys")
+
+    def values_w(self, space):
+        return space.call_method(self.w_mapping, "values")
+
+    def items_w(self, space):
+        return space.call_method(self.w_mapping, "items")
+
+    def copy_w(self, space):
+        return space.call_method(self.w_mapping, "copy")
+
+cmp_methods = {}
+def make_cmp_method(op):
+    def descr_op(self, space, w_other):
+        return getattr(space, op)(self.w_mapping, w_other)
+    descr_name = 'descr_' + op
+    descr_op.__name__ = descr_name
+    setattr(W_DictProxyObject, descr_name, descr_op)
+    cmp_methods['__%s__' % op] = interp2app(getattr(W_DictProxyObject, descr_name))
+
+for op in ['eq', 'ne', 'gt', 'ge', 'lt', 'le']:
+    make_cmp_method(op)
+
 
 W_DictProxyObject.typedef = TypeDef(
-    "mappingproxy", W_DictObject.typedef,
-    __new__ = interp2app(W_DictProxyObject.descr_new),
-    __init__ = interp2app(W_DictProxyObject.descr_init),
-    __repr__ = interp2app(W_DictProxyObject.descr_repr),
+    'mappingproxy',
+    __new__=interp2app(W_DictProxyObject.descr_new),
+    __init__=interp2app(W_DictProxyObject.descr_init),
+    __len__=interp2app(W_DictProxyObject.descr_len),
+    __getitem__=interp2app(W_DictProxyObject.descr_getitem),
+    __contains__=interp2app(W_DictProxyObject.descr_contains),
+    __iter__=interp2app(W_DictProxyObject.descr_iter),
+    __str__=interp2app(W_DictProxyObject.descr_str),
+    __repr__=interp2app(W_DictProxyObject.descr_repr),
+    get=interp2app(W_DictProxyObject.get_w),
+    keys=interp2app(W_DictProxyObject.keys_w),
+    values=interp2app(W_DictProxyObject.values_w),
+    items=interp2app(W_DictProxyObject.items_w),
+    copy=interp2app(W_DictProxyObject.copy_w),
+    **cmp_methods
 )
-
-
-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 getitem(self, w_dict, w_key):
-        space = self.space
-        w_lookup_type = space.type(w_key)
-        if space.issubtype_w(w_lookup_type, space.w_unicode):
-            return self.getitem_str(w_dict, space.str_w(w_key))
-        else:
-            return None
-
-    def getitem_str(self, w_dict, key):
-        return self.unerase(w_dict.dstorage).getdictvalue(self.space, key)
-
-    def setitem(self, w_dict, w_key, w_value):
-        space = self.space
-        if space.is_w(space.type(w_key), space.w_unicode):
-            self.setitem_str(w_dict, self.space.str_w(w_key), w_value)
-        else:
-            raise oefmt(space.w_TypeError,
-                        "cannot add non-string keys to dict of a type")
-
-    def setitem_str(self, w_dict, key, w_value):
-        w_type = self.unerase(w_dict.dstorage)
-        try:
-            w_type.setdictvalue(self.space, key, w_value)
-        except OperationError as e:
-            if not e.match(self.space, self.space.w_TypeError):
-                raise
-            if not w_type.is_cpytype():
-                raise
-            # Allow cpyext to write to type->tp_dict even in the case
-            # of a builtin type.
-            # Like CPython, we assume that this is only done early
-            # after the type is created, and we don't invalidate any
-            # cache.  User code shoud call PyType_Modified().
-            w_type.dict_w[key] = w_value
-
-    def setdefault(self, w_dict, w_key, w_default):
-        w_result = self.getitem(w_dict, w_key)
-        if w_result is not None:
-            return w_result
-        self.setitem(w_dict, w_key, w_default)
-        return w_default
-
-    def delitem(self, w_dict, w_key):
-        space = self.space
-        w_key_type = space.type(w_key)
-        if space.is_w(w_key_type, space.w_unicode):
-            key = self.space.str_w(w_key)
-            if not self.unerase(w_dict.dstorage).deldictvalue(space, key):
-                raise KeyError
-        else:
-            raise KeyError
-
-    def length(self, w_dict):
-        return len(self.unerase(w_dict.dstorage).dict_w)
-
-    def w_keys(self, w_dict):
-        space = self.space
-        w_type = self.unerase(w_dict.dstorage)
-        return space.newlist([_wrapkey(space, key)
-                              for key in w_type.dict_w.iterkeys()])
-
-    def values(self, w_dict):
-        return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()]
-
-    def items(self, w_dict):
-        space = self.space
-        w_type = self.unerase(w_dict.dstorage)
-        return [space.newtuple([_wrapkey(space, key),
-                                unwrap_cell(space, w_value)])
-                for (key, w_value) in w_type.dict_w.iteritems()]
-
-    def clear(self, w_dict):
-        space = self.space
-        w_type = self.unerase(w_dict.dstorage)
-        if not w_type.is_heaptype():
-            raise oefmt(space.w_TypeError,
-                        "can't clear dictionary of type '%N'", w_type)
-        w_type.dict_w.clear()
-        w_type.mutated(None)
-
-    def getiterkeys(self, w_dict):
-        return self.unerase(w_dict.dstorage).dict_w.iterkeys()
-    def getitervalues(self, w_dict):
-        return self.unerase(w_dict.dstorage).dict_w.itervalues()
-    def getiteritems_with_hash(self, w_dict):
-        return iteritems_with_hash(self.unerase(w_dict.dstorage).dict_w)
-    def wrapkey(space, key):
-        return _wrapkey(space, key)
-    def wrapvalue(space, value):
-        return unwrap_cell(space, value)
-
-def _wrapkey(space, key):
-    # keys are utf-8 encoded identifiers from type's dict_w
-    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):
-        try:
-            return self.space.getitem(self.unerase(w_dict.dstorage), w_key)
-        except OperationError as e:
-            if not e.match(self.space, self.space.w_KeyError):
-                raise
-            return None
-
-    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_with_hash(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")
-
-    def copy(self, w_dict):
-        return self.space.call_method(self.unerase(w_dict.dstorage), "copy")
-
-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
@@ -9,42 +9,20 @@
         assert 'a' in NotEmpty.__dict__
         assert 'a' in NotEmpty.__dict__.keys()
         assert 'b' not in NotEmpty.__dict__
-        NotEmpty.__dict__['b'] = 4
-        assert NotEmpty.b == 4
-        del NotEmpty.__dict__['b']
         assert NotEmpty.__dict__.get("b") is None
+        raises(TypeError, "NotEmpty.__dict__['b'] = 4")
         raises(TypeError, 'NotEmpty.__dict__[15] = "y"')
-        raises(KeyError, 'del NotEmpty.__dict__[15]')
+        raises(TypeError, 'del NotEmpty.__dict__[15]')
 
-        assert NotEmpty.__dict__.setdefault("string", 1) == 1
-        assert NotEmpty.__dict__.setdefault("string", 2) == 1
-        assert NotEmpty.string == 1
-        raises(TypeError, 'NotEmpty.__dict__.setdefault(15, 1)')
-
-    def test_dictproxy_popitem(self):
-        class A(object):
-            a = 42
-        seen = 0
-        try:
-            while True:
-                key, value = A.__dict__.popitem()
-                if key == 'a':
-                    assert value == 42
-                    seen += 1
-        except KeyError:
-            pass
-        assert seen == 1
+        raises(AttributeError, 'NotEmpty.__dict__.setdefault')
 
     def test_dictproxy_getitem(self):
         class NotEmpty(object):
             a = 1
         assert 'a' in NotEmpty.__dict__
-        class substr(str): pass
+        class substr(str):
+            pass
         assert substr('a') in NotEmpty.__dict__
-        # the following are only for py2
-        ## assert u'a' in NotEmpty.__dict__
-        ## assert NotEmpty.__dict__[u'a'] == 1
-        ## assert u'\xe9' not in NotEmpty.__dict__
 
     def test_dictproxyeq(self):
         class a(object):
@@ -63,9 +41,9 @@
         class a(object):
             pass
         s1 = repr(a.__dict__)
+        assert s1.startswith('mappingproxy({') and s1.endswith('})')
         s2 = str(a.__dict__)
-        assert s1 == s2
-        assert s1.startswith('mappingproxy({') and s1.endswith('})')
+        assert s1 == 'mappingproxy(%s)' % s2
 
     def test_immutable_dict_on_builtin_type(self):
         raises(TypeError, "int.__dict__['a'] = 1")
@@ -100,4 +78,3 @@
 
 class AppTestUserObjectMethodCache(AppTestUserObject):
     spaceconfig = {"objspace.std.withmethodcachecounter": True}
-
diff --git a/pypy/objspace/std/test/test_obj.py b/pypy/objspace/std/test/test_obj.py
--- a/pypy/objspace/std/test/test_obj.py
+++ b/pypy/objspace/std/test/test_obj.py
@@ -185,12 +185,12 @@
             skip("cannot run this test as apptest")
         for u in [u"", u"a", u"aa"]:
             assert id(self.unwrap_wrap_unicode(u)) == id(u)
-            s = str(u)
-            assert id(self.unwrap_wrap_str(s)) == id(s)
+            s = u.encode()
+            assert id(self.unwrap_wrap_bytes(s)) == id(s)
         #
-        assert id('') == (256 << 4) | 11     # always
+        assert id(b'') == (256 << 4) | 11     # always
         assert id(u'') == (257 << 4) | 11
-        assert id('a') == (ord('a') << 4) | 11
+        assert id(b'a') == (ord('a') << 4) | 11
         assert id(u'\u1234') == ((~0x1234) << 4) | 11
 
     def test_id_of_tuples(self):
@@ -243,13 +243,13 @@
         l = []
         def add(s, u):
             l.append(s)
-            l.append(self.unwrap_wrap_str(s))
+            l.append(self.unwrap_wrap_bytes(s))
             l.append(s[:1] + s[1:])
             l.append(u)
             l.append(self.unwrap_wrap_unicode(u))
             l.append(u[:1] + u[1:])
         for i in range(3, 18):
-            add(str(i), unicode(i))
+            add(str(i).encode(), str(i))
         add(b"s", u"s")
         add(b"", u"")
 
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
@@ -970,7 +970,6 @@
         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:
@@ -1028,10 +1027,9 @@
             pass
 
         a = A()
+        d = A.__dict__
         A.x = 1
-        assert A.__dict__["x"] == 1
-        A.__dict__['x'] = 5
-        assert A.x == 5
+        assert d["x"] == 1
 
     def test_we_already_got_one_1(self):
         # Issue #2079: highly obscure: CPython complains if we say
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
@@ -4,8 +4,8 @@
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.function import (
     Function, StaticMethod, ClassMethod, FunctionWithFixedCode)
-from pypy.interpreter.typedef import weakref_descr, GetSetProperty,\
-     descr_get_dict, dict_descr, Member, TypeDef
+from pypy.interpreter.typedef import (
+    weakref_descr, GetSetProperty, dict_descr, Member, TypeDef)
 from pypy.interpreter.astcompiler.misc import mangle
 from pypy.module.__builtin__ import abstractinst
 
@@ -344,7 +344,7 @@
     def deldictvalue(self, space, key):
         if self.lazyloaders:
             self._cleanup_()    # force un-lazification
-        if not self.is_heaptype():
+        if not (self.is_heaptype() or self.is_cpytype()):
             raise oefmt(space.w_TypeError,
                         "can't delete attributes on type object '%N'", self)
         try:
@@ -483,14 +483,14 @@
                 self.getdictvalue(self.space, attr)
             del self.lazyloaders
 
-    def getdict(self, space): # returning a dict-proxy!
-        from pypy.objspace.std.dictproxyobject import DictProxyStrategy
-        from pypy.objspace.std.dictproxyobject import W_DictProxyObject
+    def getdict(self, space):
+        from pypy.objspace.std.classdict import ClassDictStrategy
+        from pypy.objspace.std.dictmultiobject import W_DictObject
         if self.lazyloaders:
             self._cleanup_()    # force un-lazification
-        strategy = space.fromcache(DictProxyStrategy)
+        strategy = space.fromcache(ClassDictStrategy)
         storage = strategy.erase(self)
-        return W_DictProxyObject(space, strategy, storage)
+        return W_DictObject(space, strategy, storage)
 
     def is_heaptype(self):
         return self.flag_heaptype
@@ -929,6 +929,13 @@
     return space.newbool(
         abstractinst.p_recursive_isinstance_type_w(space, w_inst, w_obj))
 
+def type_get_dict(space, w_cls):
+    from pypy.objspace.std.dictproxyobject import W_DictProxyObject
+    w_dict = w_cls.getdict(space)
+    if w_dict is None:
+        return space.w_None
+    return W_DictProxyObject(w_dict)
+
 W_TypeObject.typedef = TypeDef("type",
     __new__ = gateway.interp2app(descr__new__),
     __name__ = GetSetProperty(descr_get__name__, descr_set__name__),
@@ -936,7 +943,7 @@
     __bases__ = GetSetProperty(descr_get__bases__, descr_set__bases__),
     __base__ = GetSetProperty(descr__base),
     __mro__ = GetSetProperty(descr_get__mro__),
-    __dict__ = GetSetProperty(descr_get_dict),
+    __dict__=GetSetProperty(type_get_dict),
     __doc__ = GetSetProperty(descr__doc, descr_set__doc),
     __dir__ = gateway.interp2app(descr__dir),
     mro = gateway.interp2app(descr_mro),


More information about the pypy-commit mailing list