Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: multiphase
Changeset: r91597:8831a8a415be
Date: 2017-06-12 21:29 +0100
http://bitbucket.org/pypy/pypy/changeset/8831a8a415be/

Log:    Begin implementing PyType_FromSpec()

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -624,6 +624,8 @@
     'PyObject_CallFinalizerFromDealloc',
     '_PyTraceMalloc_Track', '_PyTraceMalloc_Untrack',
     'PyBytes_FromFormat', 'PyBytes_FromFormatV',
+
+    'PyType_FromSpec',
 ]
 TYPES = {}
 FORWARD_DECLS = []
@@ -1348,6 +1350,7 @@
                          source_dir / "_warnings.c",
                          source_dir / "pylifecycle.c",
                          source_dir / "object.c",
+                         source_dir / "typeobject.c",
                          ]
 
 def build_eci(code, use_micronumpy=False, translating=False):
diff --git a/pypy/module/cpyext/include/object.h 
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -113,6 +113,10 @@
 #define PyBUF_SHADOW 0x400
 /* end Py3k buffer interface */
 
+
+PyAPI_FUNC(PyObject*) PyType_FromSpec(PyType_Spec*);
+
+
 /* Flag bits for printing: */
 #define Py_PRINT_RAW    1       /* No string quotes etc. */
 
diff --git a/pypy/module/cpyext/parse/cpyext_object.h 
b/pypy/module/cpyext/parse/cpyext_object.h
--- a/pypy/module/cpyext/parse/cpyext_object.h
+++ b/pypy/module/cpyext/parse/cpyext_object.h
@@ -304,9 +304,10 @@
 
 typedef struct _heaptypeobject {
     PyTypeObject ht_type;
+    PyAsyncMethods as_async;
     PyNumberMethods as_number;
     PyMappingMethods as_mapping;
     PySequenceMethods as_sequence;
     PyBufferProcs as_buffer;
-    PyObject *ht_name, *ht_slots;
+    PyObject *ht_name, *ht_slots, *ht_qualname;
 } PyHeapTypeObject;
diff --git a/pypy/module/cpyext/src/typeobject.c 
b/pypy/module/cpyext/src/typeobject.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/src/typeobject.c
@@ -0,0 +1,7 @@
+#include "Python.h"
+
+PyObject *
+PyType_FromSpec(PyType_Spec *spec)
+{
+    return PyType_FromSpecWithBases(spec, NULL);
+}
diff --git a/pypy/module/cpyext/test/_testmultiphase.c 
b/pypy/module/cpyext/test/_testmultiphase.c
--- a/pypy/module/cpyext/test/_testmultiphase.c
+++ b/pypy/module/cpyext/test/_testmultiphase.c
@@ -6,98 +6,98 @@
 
 #include "Python.h"
 
-///* Example objects */
-//typedef struct {
-//    PyObject_HEAD
-//    PyObject            *x_attr;        /* Attributes dictionary */
-//} ExampleObject;
-//
-///* Example methods */
-//
-//static int
-//Example_traverse(ExampleObject *self, visitproc visit, void *arg)
-//{
-//    Py_VISIT(self->x_attr);
-//    return 0;
-//}
-//
-//static int
-//Example_finalize(ExampleObject *self)
-//{
-//    Py_CLEAR(self->x_attr);
-//    return 0;
-//}
-//
-//static PyObject *
-//Example_demo(ExampleObject *self, PyObject *args)
-//{
-//    PyObject *o = NULL;
-//    if (!PyArg_ParseTuple(args, "|O:demo", &o))
-//        return NULL;
-//    if (o != NULL && PyUnicode_Check(o)) {
-//        Py_INCREF(o);
-//        return o;
-//    }
-//    Py_INCREF(Py_None);
-//    return Py_None;
-//}
-//
-//
-//static PyMethodDef Example_methods[] = {
-//    {"demo",            (PyCFunction)Example_demo,  METH_VARARGS,
-//        PyDoc_STR("demo() -> None")},
-//    {NULL,              NULL}           /* sentinel */
-//};
-//
-//static PyObject *
-//Example_getattro(ExampleObject *self, PyObject *name)
-//{
-//    if (self->x_attr != NULL) {
-//        PyObject *v = PyDict_GetItem(self->x_attr, name);
-//        if (v != NULL) {
-//            Py_INCREF(v);
-//            return v;
-//        }
-//    }
-//    return PyObject_GenericGetAttr((PyObject *)self, name);
-//}
-//
-//static int
-//Example_setattr(ExampleObject *self, char *name, PyObject *v)
-//{
-//    if (self->x_attr == NULL) {
-//        self->x_attr = PyDict_New();
-//        if (self->x_attr == NULL)
-//            return -1;
-//    }
-//    if (v == NULL) {
-//        int rv = PyDict_DelItemString(self->x_attr, name);
-//        if (rv < 0)
-//            PyErr_SetString(PyExc_AttributeError,
-//                "delete non-existing Example attribute");
-//        return rv;
-//    }
-//    else
-//        return PyDict_SetItemString(self->x_attr, name, v);
-//}
-//
-//static PyType_Slot Example_Type_slots[] = {
-//    {Py_tp_doc, "The Example type"},
-//    {Py_tp_finalize, Example_finalize},
-//    {Py_tp_traverse, Example_traverse},
-//    {Py_tp_getattro, Example_getattro},
-//    {Py_tp_setattr, Example_setattr},
-//    {Py_tp_methods, Example_methods},
-//    {0, 0},
-//};
-//
-//static PyType_Spec Example_Type_spec = {
-//    "_testimportexec.Example",
-//    sizeof(ExampleObject),
-//    0,
-//    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,
-//    Example_Type_slots
-//};
+/* Example objects */
+typedef struct {
+    PyObject_HEAD
+    PyObject            *x_attr;        /* Attributes dictionary */
+} ExampleObject;
+
+/* Example methods */
+
+static int
+Example_traverse(ExampleObject *self, visitproc visit, void *arg)
+{
+    Py_VISIT(self->x_attr);
+    return 0;
+}
+
+static int
+Example_finalize(ExampleObject *self)
+{
+    Py_CLEAR(self->x_attr);
+    return 0;
+}
+
+static PyObject *
+Example_demo(ExampleObject *self, PyObject *args)
+{
+    PyObject *o = NULL;
+    if (!PyArg_ParseTuple(args, "|O:demo", &o))
+        return NULL;
+    if (o != NULL && PyUnicode_Check(o)) {
+        Py_INCREF(o);
+        return o;
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+static PyMethodDef Example_methods[] = {
+    {"demo",            (PyCFunction)Example_demo,  METH_VARARGS,
+        PyDoc_STR("demo() -> None")},
+    {NULL,              NULL}           /* sentinel */
+};
+
+static PyObject *
+Example_getattro(ExampleObject *self, PyObject *name)
+{
+    if (self->x_attr != NULL) {
+        PyObject *v = PyDict_GetItem(self->x_attr, name);
+        if (v != NULL) {
+            Py_INCREF(v);
+            return v;
+        }
+    }
+    return PyObject_GenericGetAttr((PyObject *)self, name);
+}
+
+static int
+Example_setattr(ExampleObject *self, char *name, PyObject *v)
+{
+    if (self->x_attr == NULL) {
+        self->x_attr = PyDict_New();
+        if (self->x_attr == NULL)
+            return -1;
+    }
+    if (v == NULL) {
+        int rv = PyDict_DelItemString(self->x_attr, name);
+        if (rv < 0)
+            PyErr_SetString(PyExc_AttributeError,
+                "delete non-existing Example attribute");
+        return rv;
+    }
+    else
+        return PyDict_SetItemString(self->x_attr, name, v);
+}
+
+static PyType_Slot Example_Type_slots[] = {
+    {Py_tp_doc, "The Example type"},
+    {Py_tp_finalize, Example_finalize},
+    {Py_tp_traverse, Example_traverse},
+    {Py_tp_getattro, Example_getattro},
+    {Py_tp_setattr, Example_setattr},
+    {Py_tp_methods, Example_methods},
+    {0, 0},
+};
+
+static PyType_Spec Example_Type_spec = {
+    "_testimportexec.Example",
+    sizeof(ExampleObject),
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,
+    Example_Type_slots
+};
 
 /* Function of two integers returning integer */
 
@@ -158,18 +158,18 @@
 }
 */
 
-//static PyType_Slot Str_Type_slots[] = {
-//    {Py_tp_base, NULL}, /* filled out in module exec function */
-//    {0, 0},
-//};
-//
-//static PyType_Spec Str_Type_spec = {
-//    "_testimportexec.Str",
-//    0,
-//    0,
-//    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-//    Str_Type_slots
-//};
+static PyType_Slot Str_Type_slots[] = {
+    {Py_tp_base, NULL}, /* filled out in module exec function */
+    {0, 0},
+};
+
+static PyType_Spec Str_Type_spec = {
+    "_testimportexec.Str",
+    0,
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    Str_Type_slots
+};
 
 static PyMethodDef testexport_methods[] = {
     {"foo",             testexport_foo,         METH_VARARGS,
@@ -179,46 +179,46 @@
     {NULL,              NULL}           /* sentinel */
 };
 
-//static int execfunc(PyObject *m)
-//{
-//    PyObject *temp = NULL;
-//
-//    /* Due to cross platform compiler issues the slots must be filled
-//     * here. It's required for portability to Windows without requiring
-//     * C++. */
-//    Str_Type_slots[0].pfunc = &PyUnicode_Type;
-//
-//    /* Add a custom type */
-//    temp = PyType_FromSpec(&Example_Type_spec);
-//    if (temp == NULL)
-//        goto fail;
-//    if (PyModule_AddObject(m, "Example", temp) != 0)
-//        goto fail;
-//
-//    /* Add an exception type */
-//    temp = PyErr_NewException("_testimportexec.error", NULL, NULL);
-//    if (temp == NULL)
-//        goto fail;
-//    if (PyModule_AddObject(m, "error", temp) != 0)
-//        goto fail;
-//
-//    /* Add Str */
-//    temp = PyType_FromSpec(&Str_Type_spec);
-//    if (temp == NULL)
-//        goto fail;
-//    if (PyModule_AddObject(m, "Str", temp) != 0)
-//        goto fail;
-//
-//    if (PyModule_AddIntConstant(m, "int_const", 1969) != 0)
-//        goto fail;
-//
-//    if (PyModule_AddStringConstant(m, "str_const", "something different") != 
0)
-//        goto fail;
-//
-//    return 0;
-// fail:
-//    return -1;
-//}
+static int execfunc(PyObject *m)
+{
+    PyObject *temp = NULL;
+
+    /* Due to cross platform compiler issues the slots must be filled
+     * here. It's required for portability to Windows without requiring
+     * C++. */
+    Str_Type_slots[0].pfunc = &PyUnicode_Type;
+
+    /* Add a custom type */
+    temp = PyType_FromSpec(&Example_Type_spec);
+    if (temp == NULL)
+        goto fail;
+    if (PyModule_AddObject(m, "Example", temp) != 0)
+        goto fail;
+
+    /* Add an exception type */
+    temp = PyErr_NewException("_testimportexec.error", NULL, NULL);
+    if (temp == NULL)
+        goto fail;
+    if (PyModule_AddObject(m, "error", temp) != 0)
+        goto fail;
+
+    /* Add Str */
+    temp = PyType_FromSpec(&Str_Type_spec);
+    if (temp == NULL)
+        goto fail;
+    if (PyModule_AddObject(m, "Str", temp) != 0)
+        goto fail;
+
+    if (PyModule_AddIntConstant(m, "int_const", 1969) != 0)
+        goto fail;
+
+    if (PyModule_AddStringConstant(m, "str_const", "something different") != 0)
+        goto fail;
+
+    return 0;
+ fail:
+    return -1;
+}
 
 /* Helper for module definitions; there'll be a lot of them */
 #define TEST_MODULE_DEF(name, slots, methods) { \
@@ -234,7 +234,7 @@
 }
 
 PyModuleDef_Slot main_slots[] = {
-    //{Py_mod_exec, execfunc},
+    {Py_mod_exec, execfunc},
     {0, NULL},
 };
 
diff --git a/pypy/module/cpyext/test/test_module.py 
b/pypy/module/cpyext/test/test_module.py
--- a/pypy/module/cpyext/test/test_module.py
+++ b/pypy/module/cpyext/test/test_module.py
@@ -145,3 +145,17 @@
         raises(AttributeError, 'module.__path__')
         assert module is sys.modules[NAME]
         assert isinstance(module.__loader__, machinery.ExtensionFileLoader)
+
+    def test_functionality(self):
+        import types
+        NAME = '_testmultiphase'
+        module = self.import_module(name=NAME)
+        assert isinstance(module, types.ModuleType)
+        ex = module.Example()
+        assert ex.demo('abcd') == 'abcd'
+        assert ex.demo() is None
+        raises(AttributeError, ex.abc)
+        ex.abc = 0
+        assert ex.abc == 0
+        assert module.foo(9, 9) == 18
+
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
@@ -14,7 +14,7 @@
     cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
     slot_function, generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING, 
Py_buffer,
     Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
-    build_type_checkers,
+    build_type_checkers, Py_TPFLAGS_BASETYPE,
     PyObjectFields, PyTypeObject, PyTypeObjectPtr,
     cts, parse_dir)
 from pypy.module.cpyext.cparser import parse_source
@@ -24,7 +24,7 @@
 from pypy.module.cpyext.modsupport import convert_method_defs
 from pypy.module.cpyext.pyobject import (
     PyObject, make_ref, from_ref, get_typedescr, make_typedescr,
-    track_reference, Py_DecRef, as_pyobj)
+    track_reference, Py_DecRef, as_pyobj, incref)
 from pypy.module.cpyext.slotdefs import (
     slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function,
     llslot)
@@ -867,6 +867,78 @@
     return generic_cpy_call(
         space, type.c_tp_alloc, type, 0)
 
+@cts.decl("""PyObject *
+    PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)""",
+    result_is_ll=True)
+def PyType_FromSpecWithBases(space, spec, bases):
+    res = PyType_GenericAlloc(space, space.w_type, 0)
+    res = cts.cast('PyHeapTypeObject *', res)
+    typ = res.c_ht_type
+    typ.c_tp_flags = rffi.cast(lltype.Signed, spec.c_flags)
+    typ.c_tp_flags |= Py_TPFLAGS_HEAPTYPE
+    #s = 'foo'
+    #res.c_ht_name = PyUnicode_FromString(s)
+    #res.c_ht_qualname = res.c_ht_name
+    incref(space, res.c_ht_qualname)
+    typ.c_tp_name = spec.c_name
+    slotdefs = rffi.cast(rffi.CArrayPtr(cts.gettype('PyType_Slot')), 
spec.c_slots)
+    if not bases:
+        w_base = space.w_object
+        bases_w = []
+        i = 0
+        while True:
+            slotdef = slotdefs[i]
+            if slotdef.c_slot == 0:
+                break
+            if slotdef.c_slot == cts.macros['Py_tp_base']:
+                w_base = from_ref(space, cts.cast('PyObject*', 
slotdef.c_pfunc))
+            elif slotdef.c_slot == cts.macros['Py_tp_bases']:
+                bases = cts.cast('PyObject*', slotdef.c_pfunc)
+                bases_w = space.fixedview(from_ref(space, bases))
+            i += 1
+        if not bases_w:
+            bases_w = [w_base]
+    else:
+        bases_w = space.fixed_view(from_ref(space, bases))
+    w_base = best_base(space, bases_w)
+    base = cts.cast('PyTypeObject*', make_ref(space, w_base))
+    if False:  # not base.c_tp_flags & Py_TPFLAGS_BASETYPE:
+        raise oefmt(space.w_TypeError,
+            "type '%s' is not an acceptable base type",
+            rffi.charp2str(base.c_tp_name))
+
+    typ.c_tp_as_async = res.c_as_async
+    typ.c_tp_as_number = res.c_as_number
+    typ.c_tp_as_sequence = res.c_as_sequence
+    typ.c_tp_as_mapping = res.c_as_mapping
+    typ.c_tp_as_buffer = res.c_as_buffer
+    typ.c_tp_bases = bases
+    typ.c_tp_base = base
+    typ.c_tp_basicsize = cts.cast('Py_ssize_t', spec.c_basicsize)
+    typ.c_tp_itemsize = cts.cast('Py_ssize_t', spec.c_itemsize)
+
+    i = 0
+    while True:
+        slotdef = slotdefs[i]
+        if slotdef.c_slot == 0:
+            break
+        slot = slotdef.c_slot
+        if slot < 0:  # or slot > len(slotoffsets):
+            raise oefmt(space.w_RuntimeError, "invalid slot offset")
+        if slot in (cts.macros['Py_tp_base'], cts.macros['Py_tp_bases']):
+            # Processed above
+            i += 1
+            continue
+        #fill_slot(res, slot, slotdef.c_pfunc)
+        # XXX: need to make a copy of the docstring slot, which usually
+        # points to a static string literal
+        i += 1
+
+    if not typ.c_tp_dealloc:
+        typ.c_tp_dealloc = llslot(space, subtype_dealloc)
+    py_type_ready(space, typ)
+    return cts.cast('PyObject*', res)
+
 @cpython_api([PyTypeObjectPtr, PyObject], PyObject, error=CANNOT_FAIL,
              result_borrowed=True)
 def _PyType_Lookup(space, type, w_name):
@@ -894,4 +966,3 @@
         return
     if w_obj.is_cpytype():
         w_obj.mutated(None)
-
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to