summaryrefslogtreecommitdiffstats
path: root/Objects/moduleobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/moduleobject.c')
-rw-r--r--Objects/moduleobject.c159
1 files changed, 155 insertions, 4 deletions
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index e13233a..228ffee 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -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 */