Kaydet (Commit) 4f0dcc9a authored tarafından Jeremy Hylton's avatar Jeremy Hylton

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.
üst 8f24cdc0
...@@ -17,6 +17,7 @@ typedef struct { ...@@ -17,6 +17,7 @@ typedef struct {
PyObject *func_name; PyObject *func_name;
PyObject *func_dict; PyObject *func_dict;
PyObject *func_weakreflist; PyObject *func_weakreflist;
PyObject *func_module;
} PyFunctionObject; } PyFunctionObject;
PyAPI_DATA(PyTypeObject) PyFunction_Type; PyAPI_DATA(PyTypeObject) PyFunction_Type;
...@@ -26,6 +27,7 @@ PyAPI_DATA(PyTypeObject) PyFunction_Type; ...@@ -26,6 +27,7 @@ PyAPI_DATA(PyTypeObject) PyFunction_Type;
PyAPI_FUNC(PyObject *) PyFunction_New(PyObject *, PyObject *); PyAPI_FUNC(PyObject *) PyFunction_New(PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) PyFunction_GetCode(PyObject *); PyAPI_FUNC(PyObject *) PyFunction_GetCode(PyObject *);
PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *); PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *);
PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *);
PyAPI_FUNC(PyObject *) PyFunction_GetDefaults(PyObject *); PyAPI_FUNC(PyObject *) PyFunction_GetDefaults(PyObject *);
PyAPI_FUNC(int) PyFunction_SetDefaults(PyObject *, PyObject *); PyAPI_FUNC(int) PyFunction_SetDefaults(PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) PyFunction_GetClosure(PyObject *); PyAPI_FUNC(PyObject *) PyFunction_GetClosure(PyObject *);
...@@ -37,6 +39,8 @@ PyAPI_FUNC(int) PyFunction_SetClosure(PyObject *, PyObject *); ...@@ -37,6 +39,8 @@ PyAPI_FUNC(int) PyFunction_SetClosure(PyObject *, PyObject *);
(((PyFunctionObject *)func) -> func_code) (((PyFunctionObject *)func) -> func_code)
#define PyFunction_GET_GLOBALS(func) \ #define PyFunction_GET_GLOBALS(func) \
(((PyFunctionObject *)func) -> func_globals) (((PyFunctionObject *)func) -> func_globals)
#define PyFunction_GET_MODULE(func) \
(((PyFunctionObject *)func) -> func_module)
#define PyFunction_GET_DEFAULTS(func) \ #define PyFunction_GET_DEFAULTS(func) \
(((PyFunctionObject *)func) -> func_defaults) (((PyFunctionObject *)func) -> func_defaults)
#define PyFunction_GET_CLOSURE(func) \ #define PyFunction_GET_CLOSURE(func) \
......
...@@ -40,7 +40,9 @@ typedef struct PyMethodDef PyMethodDef; ...@@ -40,7 +40,9 @@ typedef struct PyMethodDef PyMethodDef;
PyAPI_FUNC(PyObject *) Py_FindMethod(PyMethodDef[], PyObject *, char *); PyAPI_FUNC(PyObject *) Py_FindMethod(PyMethodDef[], PyObject *, char *);
PyAPI_FUNC(PyObject *) PyCFunction_New(PyMethodDef *, PyObject *); #define PyCFunction_New(ML, SELF) PyCFunction_NewEx((ML), (SELF), NULL)
PyAPI_FUNC(PyObject *) PyCFunction_NewEx(PyMethodDef *, PyObject *,
PyObject *);
/* Flag passed to newmethodobject */ /* Flag passed to newmethodobject */
#define METH_OLDARGS 0x0000 #define METH_OLDARGS 0x0000
...@@ -68,6 +70,7 @@ typedef struct { ...@@ -68,6 +70,7 @@ typedef struct {
PyObject_HEAD PyObject_HEAD
PyMethodDef *m_ml; PyMethodDef *m_ml;
PyObject *m_self; PyObject *m_self;
PyObject *m_module;
} PyCFunctionObject; } PyCFunctionObject;
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -787,9 +787,8 @@ class Pickler: ...@@ -787,9 +787,8 @@ class Pickler:
if name is None: if name is None:
name = obj.__name__ name = obj.__name__
try: module = getattr(obj, "__module__", None)
module = obj.__module__ if module is None:
except AttributeError:
module = whichmodule(obj, name) module = whichmodule(obj, name)
try: try:
...@@ -876,6 +875,10 @@ def whichmodule(func, funcname): ...@@ -876,6 +875,10 @@ def whichmodule(func, funcname):
Return a module name. Return a module name.
If the function cannot be found, return "__main__". If the function cannot be found, return "__main__".
""" """
# Python functions should always get an __module__ from their globals.
mod = getattr(func, "__module__", None)
if mod is not None:
return mod
if func in classmap: if func in classmap:
return classmap[func] return classmap[func]
......
...@@ -9,6 +9,10 @@ def b(): ...@@ -9,6 +9,10 @@ def b():
'my docstring' 'my docstring'
pass pass
# __module__ is a special attribute
verify(b.__module__ == __name__)
verify(verify.__module__ == "test.test_support")
# setting attributes on functions # setting attributes on functions
try: try:
b.publish b.publish
......
...@@ -14,6 +14,7 @@ PyFunction_New(PyObject *code, PyObject *globals) ...@@ -14,6 +14,7 @@ PyFunction_New(PyObject *code, PyObject *globals)
if (op != NULL) { if (op != NULL) {
PyObject *doc; PyObject *doc;
PyObject *consts; PyObject *consts;
PyObject *module;
op->func_weakreflist = NULL; op->func_weakreflist = NULL;
Py_INCREF(code); Py_INCREF(code);
op->func_code = code; op->func_code = code;
...@@ -34,6 +35,16 @@ PyFunction_New(PyObject *code, PyObject *globals) ...@@ -34,6 +35,16 @@ PyFunction_New(PyObject *code, PyObject *globals)
Py_INCREF(doc); Py_INCREF(doc);
op->func_doc = doc; op->func_doc = doc;
op->func_dict = NULL; op->func_dict = NULL;
op->func_module = NULL;
/* __module__: If module name is in globals, use it.
Otherwise, use None.
*/
module = PyDict_GetItemString(globals, "__name__");
if (module) {
Py_INCREF(module);
op->func_module = module;
}
} }
else else
return NULL; return NULL;
...@@ -61,6 +72,16 @@ PyFunction_GetGlobals(PyObject *op) ...@@ -61,6 +72,16 @@ PyFunction_GetGlobals(PyObject *op)
return ((PyFunctionObject *) op) -> func_globals; return ((PyFunctionObject *) op) -> func_globals;
} }
PyObject *
PyFunction_GetModule(PyObject *op)
{
if (!PyFunction_Check(op)) {
PyErr_BadInternalCall();
return NULL;
}
return ((PyFunctionObject *) op) -> func_module;
}
PyObject * PyObject *
PyFunction_GetDefaults(PyObject *op) PyFunction_GetDefaults(PyObject *op)
{ {
...@@ -138,6 +159,7 @@ static PyMemberDef func_memberlist[] = { ...@@ -138,6 +159,7 @@ static PyMemberDef func_memberlist[] = {
RESTRICTED|READONLY}, RESTRICTED|READONLY},
{"func_name", T_OBJECT, OFF(func_name), READONLY}, {"func_name", T_OBJECT, OFF(func_name), READONLY},
{"__name__", T_OBJECT, OFF(func_name), READONLY}, {"__name__", T_OBJECT, OFF(func_name), READONLY},
{"__module__", T_OBJECT, OFF(func_module), READONLY},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
...@@ -373,6 +395,7 @@ func_dealloc(PyFunctionObject *op) ...@@ -373,6 +395,7 @@ func_dealloc(PyFunctionObject *op)
PyObject_ClearWeakRefs((PyObject *) op); PyObject_ClearWeakRefs((PyObject *) op);
Py_DECREF(op->func_code); Py_DECREF(op->func_code);
Py_DECREF(op->func_globals); Py_DECREF(op->func_globals);
Py_XDECREF(op->func_module);
Py_DECREF(op->func_name); Py_DECREF(op->func_name);
Py_XDECREF(op->func_defaults); Py_XDECREF(op->func_defaults);
Py_XDECREF(op->func_doc); Py_XDECREF(op->func_doc);
...@@ -405,6 +428,11 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg) ...@@ -405,6 +428,11 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
if (err) if (err)
return err; return err;
} }
if (f->func_module) {
err = visit(f->func_module, arg);
if (err)
return err;
}
if (f->func_defaults) { if (f->func_defaults) {
err = visit(f->func_defaults, arg); err = visit(f->func_defaults, arg);
if (err) if (err)
......
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
/* Method object implementation */ /* Method object implementation */
#include "Python.h" #include "Python.h"
#include "structmember.h"
static PyCFunctionObject *free_list = NULL; static PyCFunctionObject *free_list = NULL;
PyObject * PyObject *
PyCFunction_New(PyMethodDef *ml, PyObject *self) PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
{ {
PyCFunctionObject *op; PyCFunctionObject *op;
op = free_list; op = free_list;
...@@ -22,6 +23,8 @@ PyCFunction_New(PyMethodDef *ml, PyObject *self) ...@@ -22,6 +23,8 @@ PyCFunction_New(PyMethodDef *ml, PyObject *self)
op->m_ml = ml; op->m_ml = ml;
Py_XINCREF(self); Py_XINCREF(self);
op->m_self = self; op->m_self = self;
Py_XINCREF(module);
op->m_module = module;
_PyObject_GC_TRACK(op); _PyObject_GC_TRACK(op);
return (PyObject *)op; return (PyObject *)op;
} }
...@@ -121,6 +124,7 @@ meth_dealloc(PyCFunctionObject *m) ...@@ -121,6 +124,7 @@ meth_dealloc(PyCFunctionObject *m)
{ {
_PyObject_GC_UNTRACK(m); _PyObject_GC_UNTRACK(m);
Py_XDECREF(m->m_self); Py_XDECREF(m->m_self);
Py_XDECREF(m->m_module);
m->m_self = (PyObject *)free_list; m->m_self = (PyObject *)free_list;
free_list = m; free_list = m;
} }
...@@ -145,10 +149,18 @@ meth_get__name__(PyCFunctionObject *m, void *closure) ...@@ -145,10 +149,18 @@ meth_get__name__(PyCFunctionObject *m, void *closure)
static int static int
meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg) meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
{ {
if (m->m_self != NULL) int err;
return visit(m->m_self, arg); if (m->m_self != NULL) {
else err = visit(m->m_self, arg);
return 0; if (err)
return err;
}
if (m->m_module != NULL) {
err = visit(m->m_module, arg);
if (err)
return err;
}
return 0;
} }
static PyObject * static PyObject *
...@@ -174,6 +186,13 @@ static PyGetSetDef meth_getsets [] = { ...@@ -174,6 +186,13 @@ static PyGetSetDef meth_getsets [] = {
{0} {0}
}; };
#define OFF(x) offsetof(PyCFunctionObject, x)
static PyMemberDef meth_members[] = {
{"__module__", T_OBJECT, OFF(m_module), READONLY},
{NULL}
};
static PyObject * static PyObject *
meth_repr(PyCFunctionObject *m) meth_repr(PyCFunctionObject *m)
{ {
...@@ -250,7 +269,7 @@ PyTypeObject PyCFunction_Type = { ...@@ -250,7 +269,7 @@ PyTypeObject PyCFunction_Type = {
0, /* tp_iter */ 0, /* tp_iter */
0, /* tp_iternext */ 0, /* tp_iternext */
0, /* tp_methods */ 0, /* tp_methods */
0, /* tp_members */ meth_members, /* tp_members */
meth_getsets, /* tp_getset */ meth_getsets, /* tp_getset */
0, /* tp_base */ 0, /* tp_base */
0, /* tp_dict */ 0, /* tp_dict */
...@@ -308,6 +327,7 @@ Py_FindMethodInChain(PyMethodChain *chain, PyObject *self, char *name) ...@@ -308,6 +327,7 @@ Py_FindMethodInChain(PyMethodChain *chain, PyObject *self, char *name)
for (; ml->ml_name != NULL; ml++) { for (; ml->ml_name != NULL; ml++) {
if (name[0] == ml->ml_name[0] && if (name[0] == ml->ml_name[0] &&
strcmp(name+1, ml->ml_name+1) == 0) strcmp(name+1, ml->ml_name+1) == 0)
/* XXX */
return PyCFunction_New(ml, self); return PyCFunction_New(ml, self);
} }
chain = chain->link; chain = chain->link;
...@@ -338,3 +358,17 @@ PyCFunction_Fini(void) ...@@ -338,3 +358,17 @@ PyCFunction_Fini(void)
PyObject_GC_Del(v); PyObject_GC_Del(v);
} }
} }
/* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(),
but it's part of the API so we need to keep a function around that
existing C extensions can call.
*/
#undef PyCFunction_New
PyAPI_FUNC(PyObject *) PyCFunction_New(PyMethodDef *, PyObject *);
PyObject *
PyCFunction_New(PyMethodDef *ml, PyObject *self)
{
return PyCFunction_NewEx(ml, self, NULL);
}
...@@ -126,22 +126,27 @@ Exception\n\ ...@@ -126,22 +126,27 @@ Exception\n\
static int static int
populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods) populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods)
{ {
PyObject *module;
int status = -1;
if (!methods) if (!methods)
return 0; return 0;
module = PyString_FromString("exceptions");
if (!module)
return 0;
while (methods->ml_name) { while (methods->ml_name) {
/* get a wrapper for the built-in function */ /* get a wrapper for the built-in function */
PyObject *func = PyCFunction_New(methods, NULL); PyObject *func = PyCFunction_NewEx(methods, NULL, module);
PyObject *meth; PyObject *meth;
int status;
if (!func) if (!func)
return -1; goto status;
/* turn the function into an unbound method */ /* turn the function into an unbound method */
if (!(meth = PyMethod_New(func, NULL, klass))) { if (!(meth = PyMethod_New(func, NULL, klass))) {
Py_DECREF(func); Py_DECREF(func);
return -1; goto status;
} }
/* add method to dictionary */ /* add method to dictionary */
...@@ -151,11 +156,14 @@ populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods) ...@@ -151,11 +156,14 @@ populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods)
/* stop now if an error occurred, otherwise do the next method */ /* stop now if an error occurred, otherwise do the next method */
if (status) if (status)
return status; goto status;
methods++; methods++;
} }
return 0; status = 0;
status:
Py_DECREF(module);
return status;
} }
......
...@@ -33,7 +33,7 @@ PyObject * ...@@ -33,7 +33,7 @@ PyObject *
Py_InitModule4(char *name, PyMethodDef *methods, char *doc, Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
PyObject *passthrough, int module_api_version) PyObject *passthrough, int module_api_version)
{ {
PyObject *m, *d, *v; PyObject *m, *d, *v, *n;
PyMethodDef *ml; PyMethodDef *ml;
if (!Py_IsInitialized()) if (!Py_IsInitialized())
Py_FatalError("Interpreter not initialized (version mismatch?)"); Py_FatalError("Interpreter not initialized (version mismatch?)");
...@@ -46,6 +46,15 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc, ...@@ -46,6 +46,15 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
if (PyErr_Warn(PyExc_RuntimeWarning, message)) if (PyErr_Warn(PyExc_RuntimeWarning, message))
return NULL; 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) { if (_Py_PackageContext != NULL) {
char *p = strrchr(_Py_PackageContext, '.'); char *p = strrchr(_Py_PackageContext, '.');
if (p != NULL && strcmp(name, p+1) == 0) { if (p != NULL && strcmp(name, p+1) == 0) {
...@@ -57,6 +66,9 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc, ...@@ -57,6 +66,9 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
return NULL; return NULL;
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
if (methods != NULL) { if (methods != NULL) {
n = PyString_FromString(name);
if (n == NULL)
return NULL;
for (ml = methods; ml->ml_name != NULL; ml++) { for (ml = methods; ml->ml_name != NULL; ml++) {
if ((ml->ml_flags & METH_CLASS) || if ((ml->ml_flags & METH_CLASS) ||
(ml->ml_flags & METH_STATIC)) { (ml->ml_flags & METH_STATIC)) {
...@@ -65,7 +77,7 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc, ...@@ -65,7 +77,7 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
" METH_CLASS or METH_STATIC"); " METH_CLASS or METH_STATIC");
return NULL; return NULL;
} }
v = PyCFunction_New(ml, passthrough); v = PyCFunction_NewEx(ml, passthrough, n);
if (v == NULL) if (v == NULL)
return NULL; return NULL;
if (PyDict_SetItemString(d, ml->ml_name, v) != 0) { if (PyDict_SetItemString(d, ml->ml_name, v) != 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment