[Python-checkins] cpython (merge 3.5 -> default): Merge #27782 fix from 3.5
nick.coghlan
python-checkins at python.org
Sun Aug 21 03:44:12 EDT 2016
https://hg.python.org/cpython/rev/fb509792dffc
changeset: 102821:fb509792dffc
parent: 102819:fccd733aa78b
parent: 102820:913268337886
user: Nick Coghlan <ncoghlan at gmail.com>
date: Sun Aug 21 17:43:58 2016 +1000
summary:
Merge #27782 fix from 3.5
files:
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 +++++----
7 files changed, 83 insertions(+), 32 deletions(-)
diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst
--- a/Doc/c-api/module.rst
+++ b/Doc/c-api/module.rst
@@ -324,7 +324,7 @@
: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-*NULL* ``m_methods``, ``m_traverse``, ``m_clear``,
+ ``PyModuleDef`` has non-*NULL* ``m_traverse``, ``m_clear``,
``m_free``; non-zero ``m_size``; or slots other than ``Py_mod_create``.
.. c:var:: Py_mod_exec
diff --git a/Include/moduleobject.h b/Include/moduleobject.h
--- a/Include/moduleobject.h
+++ b/Include/moduleobject.h
@@ -77,7 +77,7 @@
traverseproc m_traverse;
inquiry m_clear;
freefunc m_free;
-}PyModuleDef;
+} PyModuleDef;
#ifdef __cplusplus
}
diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py
--- a/Lib/test/test_importlib/extension/test_loader.py
+++ b/Lib/test/test_importlib/extension/test_loader.py
@@ -212,6 +212,15 @@
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'''
+ name = self.name + '_nonmodule_with_methods'
+ mod = self.load_module_by_name(name)
+ self.assertNotEqual(type(mod), type(unittest))
+ self.assertEqual(mod.three, 3)
+ self.assertEqual(mod.bar(10, 1), 9)
+
def test_null_slots(self):
'''Test that NULL slots aren't a problem'''
name = self.name + '_null_slots'
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1679,6 +1679,7 @@
Yuxiao Zeng
Uwe Zessin
Cheng Zhang
+Xiang Zhang
Kai Zhu
Tarek Ziadé
Jelle Zijlstra
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@
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.
diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c
--- a/Modules/_testmultiphase.c
+++ b/Modules/_testmultiphase.c
@@ -248,6 +248,7 @@
/**** 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 @@
{
PyObject *dct, *ns, *three;
- if (def != &def_nonmodule) {
+ if (def != &def_nonmodule && def != &def_nonmodule_with_methods) {
PyErr_SetString(PyExc_SystemError, "def does not match");
return NULL;
}
@@ -291,6 +292,36 @@
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 = { \
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -130,6 +130,34 @@
return 1;
}
+static int
+_add_methods_to_object(PyObject *module, PyObject *name, PyMethodDef *functions)
+{
+ PyObject *func;
+ PyMethodDef *fdef;
+
+ for (fdef = functions; fdef->ml_name != NULL; fdef++) {
+ if ((fdef->ml_flags & METH_CLASS) ||
+ (fdef->ml_flags & METH_STATIC)) {
+ PyErr_SetString(PyExc_ValueError,
+ "module functions cannot set"
+ " METH_CLASS or METH_STATIC");
+ return -1;
+ }
+ func = PyCFunction_NewEx(fdef, (PyObject*)module, name);
+ if (func == NULL) {
+ return -1;
+ }
+ if (PyObject_SetAttrString(module, fdef->ml_name, func) != 0) {
+ Py_DECREF(func);
+ return -1;
+ }
+ Py_DECREF(func);
+ }
+
+ return 0;
+}
+
PyObject *
PyModule_Create2(struct PyModuleDef* module, int module_api_version)
{
@@ -269,7 +297,7 @@
}
}
} else {
- m = PyModule_New(name);
+ m = PyModule_NewObject(nameobj);
if (m == NULL) {
goto error;
}
@@ -297,7 +325,7 @@
}
if (def->m_methods != NULL) {
- ret = PyModule_AddFunctions(m, def->m_methods);
+ ret = _add_methods_to_object(m, nameobj, def->m_methods);
if (ret != 0) {
goto error;
}
@@ -331,7 +359,7 @@
return -1;
}
- if (PyModule_Check(module) && def->m_size >= 0) {
+ 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 @@
int
PyModule_AddFunctions(PyObject *m, PyMethodDef *functions)
{
- PyObject *name, *func;
- PyMethodDef *fdef;
-
- name = PyModule_GetNameObject(m);
+ int res;
+ PyObject *name = PyModule_GetNameObject(m);
if (name == NULL) {
return -1;
}
- for (fdef = functions; fdef->ml_name != NULL; fdef++) {
- if ((fdef->ml_flags & METH_CLASS) ||
- (fdef->ml_flags & METH_STATIC)) {
- PyErr_SetString(PyExc_ValueError,
- "module functions cannot set"
- " METH_CLASS or METH_STATIC");
- Py_DECREF(name);
- return -1;
- }
- func = PyCFunction_NewEx(fdef, (PyObject*)m, name);
- if (func == NULL) {
- Py_DECREF(name);
- return -1;
- }
- if (PyObject_SetAttrString(m, fdef->ml_name, func) != 0) {
- Py_DECREF(func);
- Py_DECREF(name);
- return -1;
- }
- Py_DECREF(func);
- }
+ res = _add_methods_to_object(m, name, functions);
Py_DECREF(name);
- return 0;
+ return res;
}
int
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list