diff options
author | Martin v. Löwis <martin@v.loewis.de> | 2008-06-11 05:26:20 (GMT) |
---|---|---|
committer | Martin v. Löwis <martin@v.loewis.de> | 2008-06-11 05:26:20 (GMT) |
commit | 1a21451b1d73b65af949193208372e86bf308411 (patch) | |
tree | 8e98d7be9e249b011ae9380479656e5284ec0234 /Objects/moduleobject.c | |
parent | cdf94635d7e364f9ce1905bafa5b540f4d16147c (diff) | |
download | cpython-1a21451b1d73b65af949193208372e86bf308411.zip cpython-1a21451b1d73b65af949193208372e86bf308411.tar.gz cpython-1a21451b1d73b65af949193208372e86bf308411.tar.bz2 |
Implement PEP 3121: new module initialization and finalization API.
Diffstat (limited to 'Objects/moduleobject.c')
-rw-r--r-- | Objects/moduleobject.c | 159 |
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 */ |