mirror of
https://github.com/python/cpython.git
synced 2025-12-10 02:50:09 +00:00
Implement PEP 3121: new module initialization and finalization API.
This commit is contained in:
parent
cdf94635d7
commit
1a21451b1d
113 changed files with 2230 additions and 855 deletions
|
|
@ -4,9 +4,13 @@
|
|||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
static Py_ssize_t max_module_number;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *md_dict;
|
||||
struct PyModuleDef *md_def;
|
||||
void *md_state;
|
||||
} PyModuleObject;
|
||||
|
||||
static PyMemberDef module_members[] = {
|
||||
|
|
@ -14,6 +18,14 @@ static PyMemberDef module_members[] = {
|
|||
{0}
|
||||
};
|
||||
|
||||
static PyTypeObject moduledef_type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"moduledef", /* tp_name */
|
||||
sizeof(struct PyModuleDef), /* tp_size */
|
||||
0, /* tp_itemsize */
|
||||
};
|
||||
|
||||
|
||||
PyObject *
|
||||
PyModule_New(const char *name)
|
||||
{
|
||||
|
|
@ -22,6 +34,8 @@ PyModule_New(const char *name)
|
|||
m = PyObject_GC_New(PyModuleObject, &PyModule_Type);
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
m->md_def = NULL;
|
||||
m->md_state = NULL;
|
||||
nameobj = PyUnicode_FromString(name);
|
||||
m->md_dict = PyDict_New();
|
||||
if (m->md_dict == NULL || nameobj == NULL)
|
||||
|
|
@ -42,6 +56,106 @@ PyModule_New(const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static char api_version_warning[] =
|
||||
"Python C API version mismatch for module %.100s:\
|
||||
This Python has API version %d, module %.100s has version %d.";
|
||||
|
||||
PyObject *
|
||||
PyModule_Create2(struct PyModuleDef* module, int module_api_version)
|
||||
{
|
||||
PyObject *d, *v, *n;
|
||||
PyMethodDef *ml;
|
||||
const char* name;
|
||||
PyModuleObject *m;
|
||||
if (!Py_IsInitialized())
|
||||
Py_FatalError("Interpreter not initialized (version mismatch?)");
|
||||
if (PyType_Ready(&moduledef_type) < 0)
|
||||
return NULL;
|
||||
if (module->m_base.m_index == 0) {
|
||||
max_module_number++;
|
||||
Py_REFCNT(module) = 1;
|
||||
Py_TYPE(module) = &moduledef_type;
|
||||
module->m_base.m_index = max_module_number;
|
||||
}
|
||||
name = module->m_name;
|
||||
if (module_api_version != PYTHON_API_VERSION) {
|
||||
char message[512];
|
||||
PyOS_snprintf(message, sizeof(message),
|
||||
api_version_warning, name,
|
||||
PYTHON_API_VERSION, name,
|
||||
module_api_version);
|
||||
if (PyErr_WarnEx(PyExc_RuntimeWarning, message, 1))
|
||||
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(module->m_name, p+1) == 0) {
|
||||
name = _Py_PackageContext;
|
||||
_Py_PackageContext = NULL;
|
||||
}
|
||||
}
|
||||
if ((m = (PyModuleObject*)PyModule_New(name)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (module->m_size > 0) {
|
||||
m->md_state = PyMem_MALLOC(module->m_size);
|
||||
if (!m->md_state) {
|
||||
PyErr_NoMemory();
|
||||
Py_DECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
d = PyModule_GetDict((PyObject*)m);
|
||||
if (module->m_methods != NULL) {
|
||||
n = PyUnicode_FromString(name);
|
||||
if (n == NULL)
|
||||
return NULL;
|
||||
for (ml = module->m_methods; ml->ml_name != NULL; ml++) {
|
||||
if ((ml->ml_flags & METH_CLASS) ||
|
||||
(ml->ml_flags & METH_STATIC)) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"module functions cannot set"
|
||||
" METH_CLASS or METH_STATIC");
|
||||
Py_DECREF(n);
|
||||
return NULL;
|
||||
}
|
||||
v = PyCFunction_NewEx(ml, (PyObject*)m, n);
|
||||
if (v == NULL) {
|
||||
Py_DECREF(n);
|
||||
return NULL;
|
||||
}
|
||||
if (PyDict_SetItemString(d, ml->ml_name, v) != 0) {
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(n);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(v);
|
||||
}
|
||||
Py_DECREF(n);
|
||||
}
|
||||
if (module->m_doc != NULL) {
|
||||
v = PyUnicode_FromString(module->m_doc);
|
||||
if (v == NULL || PyDict_SetItemString(d, "__doc__", v) != 0) {
|
||||
Py_XDECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(v);
|
||||
}
|
||||
m->md_def = module;
|
||||
return (PyObject*)m;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
PyModule_GetDict(PyObject *m)
|
||||
{
|
||||
|
|
@ -96,6 +210,26 @@ PyModule_GetFilename(PyObject *m)
|
|||
return PyUnicode_AsString(fileobj);
|
||||
}
|
||||
|
||||
PyModuleDef*
|
||||
PyModule_GetDef(PyObject* m)
|
||||
{
|
||||
if (!PyModule_Check(m)) {
|
||||
PyErr_BadArgument();
|
||||
return NULL;
|
||||
}
|
||||
return ((PyModuleObject *)m)->md_def;
|
||||
}
|
||||
|
||||
void*
|
||||
PyModule_GetState(PyObject* m)
|
||||
{
|
||||
if (!PyModule_Check(m)) {
|
||||
PyErr_BadArgument();
|
||||
return NULL;
|
||||
}
|
||||
return ((PyModuleObject *)m)->md_state;
|
||||
}
|
||||
|
||||
void
|
||||
_PyModule_Clear(PyObject *m)
|
||||
{
|
||||
|
|
@ -174,6 +308,8 @@ static void
|
|||
module_dealloc(PyModuleObject *m)
|
||||
{
|
||||
PyObject_GC_UnTrack(m);
|
||||
if (m->md_def && m->md_def->m_free)
|
||||
m->md_def->m_free(m);
|
||||
if (m->md_dict != NULL) {
|
||||
_PyModule_Clear((PyObject *)m);
|
||||
Py_DECREF(m->md_dict);
|
||||
|
|
@ -200,16 +336,31 @@ module_repr(PyModuleObject *m)
|
|||
return PyUnicode_FromFormat("<module '%s' from '%s'>", name, filename);
|
||||
}
|
||||
|
||||
/* We only need a traverse function, no clear function: If the module
|
||||
is in a cycle, md_dict will be cleared as well, which will break
|
||||
the cycle. */
|
||||
static int
|
||||
module_traverse(PyModuleObject *m, visitproc visit, void *arg)
|
||||
{
|
||||
if (m->md_def && m->md_def->m_traverse) {
|
||||
int res = m->md_def->m_traverse((PyObject*)m, visit, arg);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
Py_VISIT(m->md_dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
module_clear(PyModuleObject *m)
|
||||
{
|
||||
if (m->md_def && m->md_def->m_clear) {
|
||||
int res = m->md_def->m_clear((PyObject*)m);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
Py_CLEAR(m->md_dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"module(name[, doc])\n\
|
||||
\n\
|
||||
|
|
@ -240,7 +391,7 @@ PyTypeObject PyModule_Type = {
|
|||
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
module_doc, /* tp_doc */
|
||||
(traverseproc)module_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
(inquiry)module_clear, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue