[pypy-svn] r74822 - in pypy/trunk/pypy/module/cpyext: . test

afa at codespeak.net afa at codespeak.net
Thu May 27 18:43:52 CEST 2010


Author: afa
Date: Thu May 27 18:43:50 2010
New Revision: 74822

Modified:
   pypy/trunk/pypy/module/cpyext/test/foo.c
   pypy/trunk/pypy/module/cpyext/test/test_cpyext.py
   pypy/trunk/pypy/module/cpyext/test/test_typeobject.py
   pypy/trunk/pypy/module/cpyext/typeobject.py
Log:
Implement metatypes for cpyext.

The change seems simple, but was hard to get right...


Modified: pypy/trunk/pypy/module/cpyext/test/foo.c
==============================================================================
--- pypy/trunk/pypy/module/cpyext/test/foo.c	(original)
+++ pypy/trunk/pypy/module/cpyext/test/foo.c	Thu May 27 18:43:50 2010
@@ -166,6 +166,8 @@
     foo_getseters,           /*tp_getset*/
 };
 
+/* A type that inherits from 'unicode */
+
 typedef struct {
     PyUnicodeObject HEAD;
     int val;
@@ -312,6 +314,68 @@
 };
 
 
+/* A Metatype */
+
+PyTypeObject MetaType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "foo.Meta",
+    sizeof(PyTypeObject),          /*tp_basicsize*/
+    0,          /*tp_itemsize*/
+    0,          /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+
+    0,          /*tp_call*/
+    0,          /*tp_str*/
+    0,          /*tp_getattro*/
+    0,          /*tp_setattro*/
+    0,          /*tp_as_buffer*/
+
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+    0,          /*tp_doc*/
+
+    0,          /*tp_traverse*/
+    0,          /*tp_clear*/
+
+    0,          /*tp_richcompare*/
+    0,          /*tp_weaklistoffset*/
+
+    0,          /*tp_iter*/
+    0,          /*tp_iternext*/
+
+    /* Attribute descriptor and subclassing stuff */
+
+    0,          /*tp_methods*/
+    0,          /*tp_members*/
+    0,          /*tp_getset*/
+    0,          /*tp_base*/
+    0,          /*tp_dict*/
+
+    0,          /*tp_descr_get*/
+    0,          /*tp_descr_set*/
+    0,          /*tp_dictoffset*/
+
+    0,          /*tp_init*/
+    0,          /*tp_alloc*/
+    0,          /*tp_new*/
+    0,          /*tp_free*/
+    0,          /*tp_is_gc*/
+    0,          /*tp_bases*/
+    0,          /*tp_mro*/
+    0,          /*tp_cache*/
+    0,          /*tp_subclasses*/
+    0           /*tp_weaklist*/
+};
+
+
 /* foo functions */
 
 static PyObject *
@@ -344,6 +408,7 @@
 
     FuuType.tp_base = &PyUnicode_Type;
     Fuu2Type.tp_base = &FuuType;
+    MetaType.tp_base = &PyType_Type;
 
     if (PyType_Ready(&footype) < 0)
         return;
@@ -351,15 +416,20 @@
         return;
     if (PyType_Ready(&Fuu2Type) < 0)
         return;
+    if (PyType_Ready(&MetaType) < 0)
+        return;
     m = Py_InitModule("foo", foo_functions);
     if (m == NULL)
         return;
     d = PyModule_GetDict(m);
-    if (d) {
-        if (PyDict_SetItemString(d, "fooType", (PyObject *)&footype) < 0)
-            return;
-        PyDict_SetItemString(d, "FuuType", (PyObject *) &FuuType);
-        PyDict_SetItemString(d, "Fuu2Type", (PyObject *) &Fuu2Type);
-    }
-       /* No need to check the error here, the caller will do that */
+    if (d == NULL)
+        return;
+    if (PyDict_SetItemString(d, "fooType", (PyObject *)&footype) < 0)
+        return;
+    if (PyDict_SetItemString(d, "FuuType", (PyObject *) &FuuType) < 0)
+        return;
+    if(PyDict_SetItemString(d, "Fuu2Type", (PyObject *) &Fuu2Type) < 0)
+        return;
+    if (PyDict_SetItemString(d, "MetaType", (PyObject *) &MetaType) < 0)
+        return;
 }

Modified: pypy/trunk/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/test/test_cpyext.py	(original)
+++ pypy/trunk/pypy/module/cpyext/test/test_cpyext.py	Thu May 27 18:43:50 2010
@@ -90,6 +90,14 @@
         gc.collect()
         lost_objects_w = identity_dict()
         lost_objects_w.update((key, None) for key in self.frozen_refcounts.keys())
+
+        # Clear all lifelines, objects won't resurrect
+        for w_obj, obj in typeobject.lifeline_dict._dict.items():
+            if w_obj not in state.py_objects_w2r:
+                typeobject.lifeline_dict.set(w_obj, None)
+            del obj
+        gc.collect()
+
         for w_obj, obj in state.py_objects_w2r.iteritems():
             base_refcnt = self.frozen_refcounts.get(w_obj)
             delta = obj.c_ob_refcnt

Modified: pypy/trunk/pypy/module/cpyext/test/test_typeobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/test/test_typeobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/test/test_typeobject.py	Thu May 27 18:43:50 2010
@@ -135,6 +135,13 @@
         assert newobj.get_val() == 42
         assert newobj.foobar == 32
 
+    def test_metatype(self):
+        module = self.import_module(name='foo')
+        assert module.MetaType.__mro__ == (module.MetaType, type, object)
+        x = module.MetaType('name', (), {})
+        assert isinstance(x, type)
+        x()
+
     def test_sre(self):
         module = self.import_module(name='_sre')
         import sre_compile

Modified: pypy/trunk/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/typeobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/typeobject.py	Thu May 27 18:43:50 2010
@@ -120,10 +120,6 @@
                 slot_func.api_func.get_wrapper(space))
         # XXX special case wrapper-functions and use a "specific" slot func
 
-        # the special case of __new__ in CPython works a bit differently, hopefully
-        # this matches the semantics
-        if method_name == "__new__" and not pto.c_tp_new:
-            continue
         if len(slot_name) == 1:
             setattr(pto, slot_name[0], slot_func_helper)
         else:
@@ -439,6 +435,7 @@
         typedescr = get_typedescr(w_obj.typedef)
         py_obj = typedescr.allocate(space, w_type, itemcount=itemcount)
         lifeline_dict.set(w_obj, PyOLifeline(space, py_obj))
+        typedescr.attach(space, py_obj, w_obj)
     return py_obj
 
 @cpython_api([PyObject, rffi.INTP], lltype.Signed, external=False,
@@ -486,8 +483,9 @@
         rffi.free_charp(obj_pto.c_tp_name)
         obj_pto_voidp = rffi.cast(rffi.VOIDP_real, obj_pto)
         generic_cpy_call(space, type_pto.c_tp_free, obj_pto_voidp)
-        pto = rffi.cast(PyObject, type_pto)
-        Py_DecRef(space, pto)
+        if type_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
+            pto = rffi.cast(PyObject, type_pto)
+            Py_DecRef(space, pto)
 
 
 def type_attach(space, py_obj, w_type):



More information about the Pypy-commit mailing list