cpython: 913268337886 (original) (raw)
Mercurial > cpython
changeset 102820:913268337886 3.5
Issue #27782: Fix m_methods handling in multiphase init Multi-phase extension module import now correctly allows the ``m_methods`` field to be used to add module level functions to instances of non-module types returned from ``Py_create_mod``. Patch by Xiang Zhang. [#27782]
Nick Coghlan ncoghlan@gmail.com | |
---|---|
date | Sun, 21 Aug 2016 17:41:56 +1000 |
parents | 43ae044eaccc |
children | fb509792dffc 45ef062734d6 |
files | Doc/c-api/module.rst Include/moduleobject.h Lib/test/test_importlib/extension/test_loader.py Misc/ACKS Misc/NEWS Modules/_testmultiphase.c Objects/moduleobject.c |
diffstat | 7 files changed, 83 insertions(+), 32 deletions(-)[+] [-] Doc/c-api/module.rst 2 Include/moduleobject.h 2 Lib/test/test_importlib/extension/test_loader.py 9 Misc/ACKS 1 Misc/NEWS 4 Modules/_testmultiphase.c 33 Objects/moduleobject.c 64 |
line wrap: on
line diff
--- a/Doc/c-api/module.rst
+++ b/Doc/c-api/module.rst
@@ -324,7 +324,7 @@ The available slot types are:
:c:type:PyModule_Type
. Any type can be used, as long as it supports
setting and getting import-related attributes.
However, only PyModule_Type
instances may be returned if the
PyModuleDef
has non-NULLm_traverse
,m_clear
,m_free
; non-zerom_size
; or slots other thanPy_mod_create
.
--- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -77,7 +77,7 @@ typedef struct PyModuleDef{ traverseproc m_traverse; inquiry m_clear; freefunc m_free; -}PyModuleDef; +} PyModuleDef; #ifdef __cplusplus }
--- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -212,6 +212,15 @@ class MultiPhaseExtensionModuleTests(abc self.assertNotEqual(type(mod), type(unittest)) self.assertEqual(mod.three, 3)
issue 27782
- def test_nonmodule_with_methods(self):
'''Test creating a non-module object with methods defined'''[](#l3.9)
name = self.name + '_nonmodule_with_methods'[](#l3.10)
mod = self.load_module_by_name(name)[](#l3.11)
self.assertNotEqual(type(mod), type(unittest))[](#l3.12)
self.assertEqual(mod.three, 3)[](#l3.13)
self.assertEqual(mod.bar(10, 1), 9)[](#l3.14)
+ def test_null_slots(self): '''Test that NULL slots aren't a problem''' name = self.name + '_null_slots'
--- a/Misc/ACKS +++ b/Misc/ACKS @@ -1657,6 +1657,7 @@ Nickolai Zeldovich Yuxiao Zeng Uwe Zessin Cheng Zhang +Xiang Zhang Kai Zhu Tarek Ziadé Jelle Zijlstra
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Release date: TBA Core and Builtins ----------------- +- Issue #27782: Multi-phase extension module import now correctly allows the
m_methods
field to be used to add module level functions to instances- of non-module types returned from
Py_create_mod
. Patch by Xiang Zhang. +
- Issue #27487: Warn if a submodule argument to "python -m" or runpy.run_module() is found in sys.modules after parent packages are imported, but before the submodule is executed.
--- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -248,6 +248,7 @@ PyInit__testmultiphase(PyObject spec) /*** Importing a non-module object ****/ static PyModuleDef def_nonmodule; +static PyModuleDef def_nonmodule_with_methods; /* Create a SimpleNamespace(three=3) / static PyObject @@ -255,7 +256,7 @@ createfunc_nonmodule(PyObject *spec, PyM { PyObject *dct, *ns, *three;
- if (def != &def_nonmodule && def != &def_nonmodule_with_methods) { PyErr_SetString(PyExc_SystemError, "def does not match"); return NULL; } @@ -291,6 +292,36 @@ PyInit__testmultiphase_nonmodule(PyObjec return PyModuleDef_Init(&def_nonmodule); }
+PyDoc_STRVAR(nonmodule_bar_doc, +"bar(i,j)\n[](#l6.25) +\n[](#l6.26) +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;[](#l6.35)
- res = i - j;
- return PyLong_FromLong(res);
+} + +static PyMethodDef nonmodule_methods[] = {
+}; + +static PyModuleDef def_nonmodule_with_methods = TEST_MODULE_DEF(
+ +PyMODINIT_FUNC +PyInit__testmultiphase_nonmodule_with_methods(PyObject *spec) +{
+} + /**** Non-ASCII-named modules ****/ static PyModuleDef def_nonascii_latin = { [](#l6.56)
--- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -130,6 +130,34 @@ check_api_version(const char *name, int return 1; } +static int +_add_methods_to_object(PyObject *module, PyObject *name, PyMethodDef *functions) +{
- for (fdef = functions; fdef->ml_name != NULL; fdef++) {
if ((fdef->ml_flags & METH_CLASS) ||[](#l7.14)
(fdef->ml_flags & METH_STATIC)) {[](#l7.15)
PyErr_SetString(PyExc_ValueError,[](#l7.16)
"module functions cannot set"[](#l7.17)
" METH_CLASS or METH_STATIC");[](#l7.18)
return -1;[](#l7.19)
}[](#l7.20)
func = PyCFunction_NewEx(fdef, (PyObject*)module, name);[](#l7.21)
if (func == NULL) {[](#l7.22)
return -1;[](#l7.23)
}[](#l7.24)
if (PyObject_SetAttrString(module, fdef->ml_name, func) != 0) {[](#l7.25)
Py_DECREF(func);[](#l7.26)
return -1;[](#l7.27)
}[](#l7.28)
Py_DECREF(func);[](#l7.29)
- }
+} + PyObject PyModule_Create2(struct PyModuleDef module, int module_api_version) { @@ -269,7 +297,7 @@ PyModule_FromDefAndSpec2(struct PyModule } } } else {
m = PyModule_New(name);[](#l7.42)
m = PyModule_NewObject(nameobj);[](#l7.43) if (m == NULL) {[](#l7.44) goto error;[](#l7.45) }[](#l7.46)
@@ -297,7 +325,7 @@ PyModule_FromDefAndSpec2(struct PyModule } if (def->m_methods != NULL) {
ret = PyModule_AddFunctions(m, def->m_methods);[](#l7.51)
ret = _add_methods_to_object(m, nameobj, def->m_methods);[](#l7.52) if (ret != 0) {[](#l7.53) goto error;[](#l7.54) }[](#l7.55)
@@ -331,7 +359,7 @@ PyModule_ExecDef(PyObject *module, PyMod return -1; }
- if (def->m_size >= 0) { PyModuleObject md = (PyModuleObject)module; if (md->md_state == NULL) { /* Always set a state pointer; this serves as a marker to skip
@@ -387,37 +415,15 @@ PyModule_ExecDef(PyObject *module, PyMod int PyModule_AddFunctions(PyObject *m, PyMethodDef *functions) {
- for (fdef = functions; fdef->ml_name != NULL; fdef++) {
if ((fdef->ml_flags & METH_CLASS) ||[](#l7.80)
(fdef->ml_flags & METH_STATIC)) {[](#l7.81)
PyErr_SetString(PyExc_ValueError,[](#l7.82)
"module functions cannot set"[](#l7.83)
" METH_CLASS or METH_STATIC");[](#l7.84)
Py_DECREF(name);[](#l7.85)
return -1;[](#l7.86)
}[](#l7.87)
func = PyCFunction_NewEx(fdef, (PyObject*)m, name);[](#l7.88)
if (func == NULL) {[](#l7.89)
Py_DECREF(name);[](#l7.90)
return -1;[](#l7.91)
}[](#l7.92)
if (PyObject_SetAttrString(m, fdef->ml_name, func) != 0) {[](#l7.93)
Py_DECREF(func);[](#l7.94)
Py_DECREF(name);[](#l7.95)
return -1;[](#l7.96)
}[](#l7.97)
Py_DECREF(func);[](#l7.98)
- }