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