mirror of
https://github.com/python/cpython.git
synced 2025-07-19 17:25:54 +00:00
Provide __module__ attributes for functions defined in C and Python.
__module__ is the string name of the module the function was defined in, just like __module__ of classes. In some cases, particularly for C functions, the __module__ may be None. Change PyCFunction_New() from a function to a macro, but keep an unused copy of the function around so that we don't change the binary API. Change pickle's save_global() to use whichmodule() if __module__ is None, but add the __module__ logic to whichmodule() since it might be used outside of pickle.
This commit is contained in:
parent
8f24cdc0d5
commit
4f0dcc9a9a
8 changed files with 114 additions and 18 deletions
|
@ -126,22 +126,27 @@ Exception\n\
|
|||
static int
|
||||
populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods)
|
||||
{
|
||||
PyObject *module;
|
||||
int status = -1;
|
||||
|
||||
if (!methods)
|
||||
return 0;
|
||||
|
||||
module = PyString_FromString("exceptions");
|
||||
if (!module)
|
||||
return 0;
|
||||
while (methods->ml_name) {
|
||||
/* get a wrapper for the built-in function */
|
||||
PyObject *func = PyCFunction_New(methods, NULL);
|
||||
PyObject *func = PyCFunction_NewEx(methods, NULL, module);
|
||||
PyObject *meth;
|
||||
int status;
|
||||
|
||||
if (!func)
|
||||
return -1;
|
||||
goto status;
|
||||
|
||||
/* turn the function into an unbound method */
|
||||
if (!(meth = PyMethod_New(func, NULL, klass))) {
|
||||
Py_DECREF(func);
|
||||
return -1;
|
||||
goto status;
|
||||
}
|
||||
|
||||
/* add method to dictionary */
|
||||
|
@ -151,11 +156,14 @@ populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods)
|
|||
|
||||
/* stop now if an error occurred, otherwise do the next method */
|
||||
if (status)
|
||||
return status;
|
||||
goto status;
|
||||
|
||||
methods++;
|
||||
}
|
||||
return 0;
|
||||
status = 0;
|
||||
status:
|
||||
Py_DECREF(module);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ PyObject *
|
|||
Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
|
||||
PyObject *passthrough, int module_api_version)
|
||||
{
|
||||
PyObject *m, *d, *v;
|
||||
PyObject *m, *d, *v, *n;
|
||||
PyMethodDef *ml;
|
||||
if (!Py_IsInitialized())
|
||||
Py_FatalError("Interpreter not initialized (version mismatch?)");
|
||||
|
@ -46,6 +46,15 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
|
|||
if (PyErr_Warn(PyExc_RuntimeWarning, message))
|
||||
return NULL;
|
||||
}
|
||||
/* Make sure name is fully qualified.
|
||||
|
||||
This is a bit of a hack: when the shared library is loaded,
|
||||
the module name is "package.module", but the module calls
|
||||
Py_InitModule*() with just "module" for the name. The shared
|
||||
library loader squirrels away the true name of the module in
|
||||
_Py_PackageContext, and Py_InitModule*() will substitute this
|
||||
(if the name actually matches).
|
||||
*/
|
||||
if (_Py_PackageContext != NULL) {
|
||||
char *p = strrchr(_Py_PackageContext, '.');
|
||||
if (p != NULL && strcmp(name, p+1) == 0) {
|
||||
|
@ -57,6 +66,9 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
|
|||
return NULL;
|
||||
d = PyModule_GetDict(m);
|
||||
if (methods != NULL) {
|
||||
n = PyString_FromString(name);
|
||||
if (n == NULL)
|
||||
return NULL;
|
||||
for (ml = methods; ml->ml_name != NULL; ml++) {
|
||||
if ((ml->ml_flags & METH_CLASS) ||
|
||||
(ml->ml_flags & METH_STATIC)) {
|
||||
|
@ -65,7 +77,7 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
|
|||
" METH_CLASS or METH_STATIC");
|
||||
return NULL;
|
||||
}
|
||||
v = PyCFunction_New(ml, passthrough);
|
||||
v = PyCFunction_NewEx(ml, passthrough, n);
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
if (PyDict_SetItemString(d, ml->ml_name, v) != 0) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue