Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: multiphase
Changeset: r91575:d2a5ce70ff79
Date: 2017-06-08 19:00 +0100
http://bitbucket.org/pypy/pypy/changeset/d2a5ce70ff79/

Log:    Add _testmultiphase.c to cpyext tests and get parts of it working

diff --git a/pypy/module/cpyext/include/Python.h 
b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -84,6 +84,7 @@
 #include "pyconfig.h"
 
 #include "object.h"
+#include "typeslots.h"
 #include "abstract.h"
 #include "pymath.h"
 #include "pyport.h"
diff --git a/pypy/module/cpyext/include/typeslots.h 
b/pypy/module/cpyext/include/typeslots.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/typeslots.h
@@ -0,0 +1,85 @@
+/* Do not renumber the file; these numbers are part of the stable ABI. */
+/* Disabled, see #10181 */
+#undef Py_bf_getbuffer
+#undef Py_bf_releasebuffer
+#define Py_mp_ass_subscript 3
+#define Py_mp_length 4
+#define Py_mp_subscript 5
+#define Py_nb_absolute 6
+#define Py_nb_add 7
+#define Py_nb_and 8
+#define Py_nb_bool 9
+#define Py_nb_divmod 10
+#define Py_nb_float 11
+#define Py_nb_floor_divide 12
+#define Py_nb_index 13
+#define Py_nb_inplace_add 14
+#define Py_nb_inplace_and 15
+#define Py_nb_inplace_floor_divide 16
+#define Py_nb_inplace_lshift 17
+#define Py_nb_inplace_multiply 18
+#define Py_nb_inplace_or 19
+#define Py_nb_inplace_power 20
+#define Py_nb_inplace_remainder 21
+#define Py_nb_inplace_rshift 22
+#define Py_nb_inplace_subtract 23
+#define Py_nb_inplace_true_divide 24
+#define Py_nb_inplace_xor 25
+#define Py_nb_int 26
+#define Py_nb_invert 27
+#define Py_nb_lshift 28
+#define Py_nb_multiply 29
+#define Py_nb_negative 30
+#define Py_nb_or 31
+#define Py_nb_positive 32
+#define Py_nb_power 33
+#define Py_nb_remainder 34
+#define Py_nb_rshift 35
+#define Py_nb_subtract 36
+#define Py_nb_true_divide 37
+#define Py_nb_xor 38
+#define Py_sq_ass_item 39
+#define Py_sq_concat 40
+#define Py_sq_contains 41
+#define Py_sq_inplace_concat 42
+#define Py_sq_inplace_repeat 43
+#define Py_sq_item 44
+#define Py_sq_length 45
+#define Py_sq_repeat 46
+#define Py_tp_alloc 47
+#define Py_tp_base 48
+#define Py_tp_bases 49
+#define Py_tp_call 50
+#define Py_tp_clear 51
+#define Py_tp_dealloc 52
+#define Py_tp_del 53
+#define Py_tp_descr_get 54
+#define Py_tp_descr_set 55
+#define Py_tp_doc 56
+#define Py_tp_getattr 57
+#define Py_tp_getattro 58
+#define Py_tp_hash 59
+#define Py_tp_init 60
+#define Py_tp_is_gc 61
+#define Py_tp_iter 62
+#define Py_tp_iternext 63
+#define Py_tp_methods 64
+#define Py_tp_new 65
+#define Py_tp_repr 66
+#define Py_tp_richcompare 67
+#define Py_tp_setattr 68
+#define Py_tp_setattro 69
+#define Py_tp_str 70
+#define Py_tp_traverse 71
+#define Py_tp_members 72
+#define Py_tp_getset 73
+#define Py_tp_free 74
+#define Py_nb_matrix_multiply 75
+#define Py_nb_inplace_matrix_multiply 76
+#define Py_am_await 77
+#define Py_am_aiter 78
+#define Py_am_anext 79
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000
+/* New in 3.5 */
+#define Py_tp_finalize 80
+#endif
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
@@ -289,6 +289,19 @@
     destructor tp_finalize;
 } PyTypeObject;
 
+typedef struct{
+    int slot;    /* slot id, see below */
+    void *pfunc; /* function pointer */
+} PyType_Slot;
+
+typedef struct{
+    const char* name;
+    int basicsize;
+    int itemsize;
+    unsigned int flags;
+    PyType_Slot *slots; /* terminated by slot==0. */
+} PyType_Spec;
+
 typedef struct _heaptypeobject {
     PyTypeObject ht_type;
     PyNumberMethods as_number;
diff --git a/pypy/module/cpyext/test/_testmultiphase.c 
b/pypy/module/cpyext/test/_testmultiphase.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/_testmultiphase.c
@@ -0,0 +1,627 @@
+/* Copied from CPython's Modules/_testmultiphase.c */
+/***************************************************/
+
+/* Testing module for multi-phase initialization of extension modules (PEP 489)
+ */
+
+#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
+//};
+
+/* Function of two integers returning integer */
+
+PyDoc_STRVAR(testexport_foo_doc,
+"foo(i,j)\n\
+\n\
+Return the sum of i and j.");
+
+static PyObject *
+testexport_foo(PyObject *self, PyObject *args)
+{
+    long i, j;
+    long res;
+    if (!PyArg_ParseTuple(args, "ll:foo", &i, &j))
+        return NULL;
+    res = i + j;
+    return PyLong_FromLong(res);
+}
+
+/* Test that PyState registration fails  */
+/*
+PyDoc_STRVAR(call_state_registration_func_doc,
+"register_state(0): call PyState_FindModule()\n\
+register_state(1): call PyState_AddModule()\n\
+register_state(2): call PyState_RemoveModule()");
+
+static PyObject *
+call_state_registration_func(PyObject *mod, PyObject *args)
+{
+    int i, ret;
+    PyModuleDef *def = PyModule_GetDef(mod);
+    if (def == NULL) {
+        return NULL;
+    }
+    if (!PyArg_ParseTuple(args, "i:call_state_registration_func", &i))
+        return NULL;
+    switch (i) {
+        case 0:
+            mod = PyState_FindModule(def);
+            if (mod == NULL) {
+                Py_RETURN_NONE;
+            }
+            return mod;
+        case 1:
+            ret = PyState_AddModule(mod, def);
+            if (ret != 0) {
+                return NULL;
+            }
+            break;
+        case 2:
+            ret = PyState_RemoveModule(def);
+            if (ret != 0) {
+                return NULL;
+            }
+            break;
+    }
+    Py_RETURN_NONE;
+}
+*/
+
+//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,
+        testexport_foo_doc},
+/*    {"call_state_registration_func",  call_state_registration_func,
+        METH_VARARGS, call_state_registration_func_doc},*/
+    {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;
+//}
+
+/* Helper for module definitions; there'll be a lot of them */
+#define TEST_MODULE_DEF(name, slots, methods) { \
+    PyModuleDef_HEAD_INIT,                      /* m_base */ \
+    name,                                       /* m_name */ \
+    PyDoc_STR("Test module " name),             /* m_doc */ \
+    0,                                          /* m_size */ \
+    methods,                                    /* m_methods */ \
+    slots,                                      /* m_slots */ \
+    NULL,                                       /* m_traverse */ \
+    NULL,                                       /* m_clear */ \
+    NULL,                                       /* m_free */ \
+}
+
+PyModuleDef_Slot main_slots[] = {
+    //{Py_mod_exec, execfunc},
+    {0, NULL},
+};
+
+static PyModuleDef main_def = TEST_MODULE_DEF("main", main_slots, 
testexport_methods);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase(PyObject *spec)
+{
+    return PyModuleDef_Init(&main_def);
+}
+
+
+/**** Importing a non-module object ****/
+
+//static PyModuleDef def_nonmodule;
+//static PyModuleDef def_nonmodule_with_methods;
+//
+///* Create a SimpleNamespace(three=3) */
+//static PyObject*
+//createfunc_nonmodule(PyObject *spec, PyModuleDef *def)
+//{
+//    PyObject *dct, *ns, *three;
+//
+//    if (def != &def_nonmodule && def != &def_nonmodule_with_methods) {
+//        PyErr_SetString(PyExc_SystemError, "def does not match");
+//        return NULL;
+//    }
+//
+//    dct = PyDict_New();
+//    if (dct == NULL)
+//        return NULL;
+//
+//    three = PyLong_FromLong(3);
+//    if (three == NULL) {
+//        Py_DECREF(dct);
+//        return NULL;
+//    }
+//    PyDict_SetItemString(dct, "three", three);
+//    Py_DECREF(three);
+//
+//    ns = _PyNamespace_New(dct);
+//    Py_DECREF(dct);
+//    return ns;
+//}
+//
+//static PyModuleDef_Slot slots_create_nonmodule[] = {
+//    {Py_mod_create, createfunc_nonmodule},
+//    {0, NULL},
+//};
+//
+//static PyModuleDef def_nonmodule = TEST_MODULE_DEF(
+//    "_testmultiphase_nonmodule", slots_create_nonmodule, NULL);
+//
+//PyMODINIT_FUNC
+//PyInit__testmultiphase_nonmodule(PyObject *spec)
+//{
+//    return PyModuleDef_Init(&def_nonmodule);
+//}
+/*
+PyDoc_STRVAR(nonmodule_bar_doc,
+"bar(i,j)\n\
+\n\
+Return the difference of i - j.");
+
+static PyObject *
+nonmodule_bar(PyObject *self, PyObject *args)
+{
+    long i, j;
+    long res;
+    if (!PyArg_ParseTuple(args, "ll:bar", &i, &j))
+        return NULL;
+    res = i - j;
+    return PyLong_FromLong(res);
+}
+*/
+//static PyMethodDef nonmodule_methods[] = {
+//    {"bar", nonmodule_bar, METH_VARARGS, nonmodule_bar_doc},
+//    {NULL, NULL}           /* sentinel */
+//};
+//
+//static PyModuleDef def_nonmodule_with_methods = TEST_MODULE_DEF(
+//    "_testmultiphase_nonmodule_with_methods", slots_create_nonmodule, 
nonmodule_methods);
+//
+//PyMODINIT_FUNC
+//PyInit__testmultiphase_nonmodule_with_methods(PyObject *spec)
+//{
+//    return PyModuleDef_Init(&def_nonmodule_with_methods);
+//}
+
+/**** Non-ASCII-named modules ****/
+
+static PyModuleDef def_nonascii_latin = { \
+    PyModuleDef_HEAD_INIT,                      /* m_base */
+    "_testmultiphase_nonascii_latin",           /* m_name */
+    PyDoc_STR("Module named in Czech"),         /* m_doc */
+    0,                                          /* m_size */
+    NULL,                                       /* m_methods */
+    NULL,                                       /* m_slots */
+    NULL,                                       /* m_traverse */
+    NULL,                                       /* m_clear */
+    NULL,                                       /* m_free */
+};
+
+PyMODINIT_FUNC
+PyInitU__testmultiphase_zkouka_naten_evc07gi8e(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_nonascii_latin);
+}
+
+static PyModuleDef def_nonascii_kana = { \
+    PyModuleDef_HEAD_INIT,                      /* m_base */
+    "_testmultiphase_nonascii_kana",            /* m_name */
+    PyDoc_STR("Module named in Japanese"),      /* m_doc */
+    0,                                          /* m_size */
+    NULL,                                       /* m_methods */
+    NULL,                                       /* m_slots */
+    NULL,                                       /* m_traverse */
+    NULL,                                       /* m_clear */
+    NULL,                                       /* m_free */
+};
+
+PyMODINIT_FUNC
+PyInitU_eckzbwbhc6jpgzcx415x(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_nonascii_kana);
+}
+
+/*** Module with a single-character name ***/
+
+PyMODINIT_FUNC
+PyInit_x(PyObject *spec)
+{
+    return PyModuleDef_Init(&main_def);
+}
+
+/**** Testing NULL slots ****/
+
+static PyModuleDef null_slots_def = TEST_MODULE_DEF(
+    "_testmultiphase_null_slots", NULL, NULL);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_null_slots(PyObject *spec)
+{
+    return PyModuleDef_Init(&null_slots_def);
+}
+
+/**** Problematic modules ****/
+
+static PyModuleDef_Slot slots_bad_large[] = {
+    {_Py_mod_LAST_SLOT + 1, NULL},
+    {0, NULL},
+};
+
+static PyModuleDef def_bad_large = TEST_MODULE_DEF(
+    "_testmultiphase_bad_slot_large", slots_bad_large, NULL);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_bad_slot_large(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_bad_large);
+}
+
+static PyModuleDef_Slot slots_bad_negative[] = {
+    {-1, NULL},
+    {0, NULL},
+};
+
+static PyModuleDef def_bad_negative = TEST_MODULE_DEF(
+    "_testmultiphase_bad_slot_negative", slots_bad_negative, NULL);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_bad_slot_negative(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_bad_negative);
+}
+
+static PyModuleDef def_create_int_with_state = { \
+    PyModuleDef_HEAD_INIT,                      /* m_base */
+    "create_with_state",                        /* m_name */
+    PyDoc_STR("Not a PyModuleObject object, but requests per-module state"),
+    10,                                         /* m_size */
+    NULL,                                       /* m_methods */
+    //slots_create_nonmodule,                     /* m_slots */
+    NULL,                                       /* m_traverse */
+    NULL,                                       /* m_clear */
+    NULL,                                       /* m_free */
+};
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_create_int_with_state(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_create_int_with_state);
+}
+
+
+static PyModuleDef def_negative_size = { \
+    PyModuleDef_HEAD_INIT,                      /* m_base */
+    "negative_size",                            /* m_name */
+    PyDoc_STR("PyModuleDef with negative m_size"),
+    -1,                                         /* m_size */
+    NULL,                                       /* m_methods */
+    NULL, //slots_create_nonmodule,                     /* m_slots */
+    NULL,                                       /* m_traverse */
+    NULL,                                       /* m_clear */
+    NULL,                                       /* m_free */
+};
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_negative_size(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_negative_size);
+}
+
+
+static PyModuleDef uninitialized_def = TEST_MODULE_DEF("main", main_slots, 
testexport_methods);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_export_uninitialized(PyObject *spec)
+{
+    return (PyObject*) &uninitialized_def;
+}
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_export_null(PyObject *spec)
+{
+    return NULL;
+}
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_export_raise(PyObject *spec)
+{
+    PyErr_SetString(PyExc_SystemError, "bad export function");
+    return NULL;
+}
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_export_unreported_exception(PyObject *spec)
+{
+    PyErr_SetString(PyExc_SystemError, "bad export function");
+    return PyModuleDef_Init(&main_def);
+}
+
+static PyObject*
+createfunc_null(PyObject *spec, PyModuleDef *def)
+{
+    return NULL;
+}
+
+PyModuleDef_Slot slots_create_null[] = {
+    {Py_mod_create, createfunc_null},
+    {0, NULL},
+};
+
+static PyModuleDef def_create_null = TEST_MODULE_DEF(
+    "_testmultiphase_create_null", slots_create_null, NULL);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_create_null(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_create_null);
+}
+
+static PyObject*
+createfunc_raise(PyObject *spec, PyModuleDef *def)
+{
+    PyErr_SetString(PyExc_SystemError, "bad create function");
+    return NULL;
+}
+
+static PyModuleDef_Slot slots_create_raise[] = {
+    {Py_mod_create, createfunc_raise},
+    {0, NULL},
+};
+
+static PyModuleDef def_create_raise = TEST_MODULE_DEF(
+    "_testmultiphase_create_null", slots_create_raise, NULL);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_create_raise(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_create_raise);
+}
+
+static PyObject*
+createfunc_unreported_exception(PyObject *spec, PyModuleDef *def)
+{
+    PyErr_SetString(PyExc_SystemError, "bad create function");
+    return PyModule_New("foo");
+}
+
+static PyModuleDef_Slot slots_create_unreported_exception[] = {
+    {Py_mod_create, createfunc_unreported_exception},
+    {0, NULL},
+};
+
+static PyModuleDef def_create_unreported_exception = TEST_MODULE_DEF(
+    "_testmultiphase_create_unreported_exception", 
slots_create_unreported_exception, NULL);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_create_unreported_exception(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_create_unreported_exception);
+}
+
+//static PyModuleDef_Slot slots_nonmodule_with_exec_slots[] = {
+//    {Py_mod_create, createfunc_nonmodule},
+//    {Py_mod_exec, execfunc},
+//    {0, NULL},
+//};
+//
+//static PyModuleDef def_nonmodule_with_exec_slots = TEST_MODULE_DEF(
+//    "_testmultiphase_nonmodule_with_exec_slots", 
slots_nonmodule_with_exec_slots, NULL);
+//
+//PyMODINIT_FUNC
+//PyInit__testmultiphase_nonmodule_with_exec_slots(PyObject *spec)
+//{
+//    return PyModuleDef_Init(&def_nonmodule_with_exec_slots);
+//}
+
+static int
+execfunc_err(PyObject *mod)
+{
+    return -1;
+}
+
+static PyModuleDef_Slot slots_exec_err[] = {
+    {Py_mod_exec, execfunc_err},
+    {0, NULL},
+};
+
+static PyModuleDef def_exec_err = TEST_MODULE_DEF(
+    "_testmultiphase_exec_err", slots_exec_err, NULL);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_exec_err(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_exec_err);
+}
+
+static int
+execfunc_raise(PyObject *spec)
+{
+    PyErr_SetString(PyExc_SystemError, "bad exec function");
+    return -1;
+}
+
+static PyModuleDef_Slot slots_exec_raise[] = {
+    {Py_mod_exec, execfunc_raise},
+    {0, NULL},
+};
+
+static PyModuleDef def_exec_raise = TEST_MODULE_DEF(
+    "_testmultiphase_exec_raise", slots_exec_raise, NULL);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_exec_raise(PyObject *mod)
+{
+    return PyModuleDef_Init(&def_exec_raise);
+}
+
+static int
+execfunc_unreported_exception(PyObject *mod)
+{
+    PyErr_SetString(PyExc_SystemError, "bad exec function");
+    return 0;
+}
+
+static PyModuleDef_Slot slots_exec_unreported_exception[] = {
+    {Py_mod_exec, execfunc_unreported_exception},
+    {0, NULL},
+};
+
+static PyModuleDef def_exec_unreported_exception = TEST_MODULE_DEF(
+    "_testmultiphase_exec_unreported_exception", 
slots_exec_unreported_exception, NULL);
+
+PyMODINIT_FUNC
+PyInit__testmultiphase_exec_unreported_exception(PyObject *spec)
+{
+    return PyModuleDef_Init(&def_exec_unreported_exception);
+}
+
+/*** Helper for imp test ***/
+
+static PyModuleDef imp_dummy_def = TEST_MODULE_DEF("imp_dummy", main_slots, 
testexport_methods);
+
+PyMODINIT_FUNC
+PyInit_imp_dummy(PyObject *spec)
+{
+    return PyModuleDef_Init(&imp_dummy_def);
+}
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
@@ -130,3 +130,18 @@
         """
         raises(SystemError, self.import_module, name='multiphase', body=body,
                init=init)
+
+    def test_module(self):
+        import sys
+        from importlib import machinery, util
+        NAME = '_testmultiphase'
+        module = self.import_module(name=NAME)
+        finder = machinery.FileFinder(None)
+        spec = util.find_spec(NAME)
+        assert spec
+        assert module.__name__ == NAME
+        #assert module.__file__ == spec.origin
+        assert module.__package__ == ''
+        raises(AttributeError, 'module.__path__')
+        assert module is sys.modules[NAME]
+        assert isinstance(module.__loader__, machinery.ExtensionFileLoader)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to