diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -67,9 +67,45 @@ static PyTypeObject XMLParser_Type; /* glue functions (see the init function for details) */ -static PyObject* elementtree_parseerror_obj; -static PyObject* elementtree_deepcopy_obj; -static PyObject* elementpath_obj; + +typedef struct { + PyObject *parseerror_obj; + PyObject *deepcopy_obj; + PyObject *elementpath_obj; +} elementtreestate; + +static struct PyModuleDef elementtreemodule; + +#define ET_STATE(mod) ((elementtreestate *) PyModule_GetState(mod)) + +#define ET_STATE_GLOBAL \ + ((elementtreestate *) PyModule_GetState(PyState_FindModule(&elementtreemodule))) + +static int +elementtree_clear(PyObject *m) +{ + elementtreestate *st = ET_STATE(m); + Py_CLEAR(st->parseerror_obj); + Py_CLEAR(st->deepcopy_obj); + Py_CLEAR(st->elementpath_obj); + return 0; +} + +static int +elementtree_traverse(PyObject *m, visitproc visit, void *arg) +{ + elementtreestate *st = ET_STATE(m); + Py_VISIT(st->parseerror_obj); + Py_VISIT(st->deepcopy_obj); + Py_VISIT(st->elementpath_obj); + return 0; +} + +static void +elementtree_free(void *m) +{ + elementtree_clear((PyObject *)m); +} /* helpers */ @@ -77,11 +113,11 @@ LOCAL(PyObject*) deepcopy(PyObject* object, PyObject* memo) { /* do a deep copy of the given object */ - PyObject* args; PyObject* result; - - if (!elementtree_deepcopy_obj) { + elementtreestate *st = ET_STATE_GLOBAL; + + if (!st->deepcopy_obj) { PyErr_SetString( PyExc_RuntimeError, "deepcopy helper not found" @@ -92,7 +128,7 @@ deepcopy(PyObject* object, PyObject* mem args = PyTuple_Pack(2, object, memo); if (!args) return NULL; - result = PyObject_CallObject(elementtree_deepcopy_obj, args); + result = PyObject_CallObject(st->deepcopy_obj, args); Py_DECREF(args); return result; } @@ -1047,6 +1083,7 @@ element_find(ElementObject *self, PyObje PyObject* tag; PyObject* namespaces = Py_None; static char *kwlist[] = {"path", "namespaces", 0}; + elementtreestate *st = ET_STATE_GLOBAL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:find", kwlist, &tag, &namespaces)) @@ -1055,7 +1092,7 @@ element_find(ElementObject *self, PyObje if (checkpath(tag) || namespaces != Py_None) { _Py_IDENTIFIER(find); return _PyObject_CallMethodId( - elementpath_obj, &PyId_find, "OOO", self, tag, namespaces + st->elementpath_obj, &PyId_find, "OOO", self, tag, namespaces ); } @@ -1083,6 +1120,7 @@ element_findtext(ElementObject *self, Py PyObject* namespaces = Py_None; _Py_IDENTIFIER(findtext); static char *kwlist[] = {"path", "default", "namespaces", 0}; + elementtreestate *st = ET_STATE_GLOBAL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO:findtext", kwlist, &tag, &default_value, &namespaces)) @@ -1090,7 +1128,7 @@ element_findtext(ElementObject *self, Py if (checkpath(tag) || namespaces != Py_None) return _PyObject_CallMethodId( - elementpath_obj, &PyId_findtext, "OOOO", self, tag, default_value, namespaces + st->elementpath_obj, &PyId_findtext, "OOOO", self, tag, default_value, namespaces ); if (!self->extra) { @@ -1122,6 +1160,7 @@ element_findall(ElementObject *self, PyO PyObject* tag; PyObject* namespaces = Py_None; static char *kwlist[] = {"path", "namespaces", 0}; + elementtreestate *st = ET_STATE_GLOBAL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:findall", kwlist, &tag, &namespaces)) @@ -1130,7 +1169,7 @@ element_findall(ElementObject *self, PyO if (checkpath(tag) || namespaces != Py_None) { _Py_IDENTIFIER(findall); return _PyObject_CallMethodId( - elementpath_obj, &PyId_findall, "OOO", self, tag, namespaces + st->elementpath_obj, &PyId_findall, "OOO", self, tag, namespaces ); } @@ -1162,13 +1201,14 @@ element_iterfind(ElementObject *self, Py PyObject* namespaces = Py_None; _Py_IDENTIFIER(iterfind); static char *kwlist[] = {"path", "namespaces", 0}; + elementtreestate *st = ET_STATE_GLOBAL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:iterfind", kwlist, &tag, &namespaces)) return NULL; return _PyObject_CallMethodId( - elementpath_obj, &PyId_iterfind, "OOO", self, tag, namespaces + st->elementpath_obj, &PyId_iterfind, "OOO", self, tag, namespaces ); } @@ -2351,6 +2391,7 @@ treebuilder_handle_start(TreeBuilderObje { PyObject* node; PyObject* this; + elementtreestate *st = ET_STATE_GLOBAL; if (self->data) { if (self->this == self->last) { @@ -2381,7 +2422,7 @@ treebuilder_handle_start(TreeBuilderObje } else { if (self->root) { PyErr_SetString( - elementtree_parseerror_obj, + st->parseerror_obj, "multiple elements on top level" ); goto error; @@ -2779,6 +2820,7 @@ static void expat_set_error(enum XML_Error error_code, int line, int column, char *message) { PyObject *errmsg, *error, *position, *code; + elementtreestate *st = ET_STATE_GLOBAL; errmsg = PyUnicode_FromFormat("%s: line %d, column %d", message ? message : EXPAT(ErrorString)(error_code), @@ -2786,7 +2828,7 @@ expat_set_error(enum XML_Error error_cod if (errmsg == NULL) return; - error = PyObject_CallFunction(elementtree_parseerror_obj, "O", errmsg); + error = PyObject_CallFunction(st->parseerror_obj, "O", errmsg); Py_DECREF(errmsg); if (!error) return; @@ -2816,7 +2858,7 @@ expat_set_error(enum XML_Error error_cod } Py_DECREF(position); - PyErr_SetObject(elementtree_parseerror_obj, error); + PyErr_SetObject(st->parseerror_obj, error); Py_DECREF(error); } @@ -3639,22 +3681,29 @@ static PyMethodDef _functions[] = { }; -static struct PyModuleDef _elementtreemodule = { - PyModuleDef_HEAD_INIT, - "_elementtree", - NULL, - -1, - _functions, - NULL, - NULL, - NULL, - NULL +static struct PyModuleDef elementtreemodule = { + PyModuleDef_HEAD_INIT, + "_elementtree", + NULL, + sizeof(elementtreestate), + _functions, + NULL, + elementtree_traverse, + elementtree_clear, + elementtree_free }; PyMODINIT_FUNC PyInit__elementtree(void) { PyObject *m, *temp; + elementtreestate *st; + + m = PyState_FindModule(&elementtreemodule); + if (m) { + Py_INCREF(m); + return m; + } /* Initialize object types */ if (PyType_Ready(&ElementIter_Type) < 0) @@ -3666,16 +3715,17 @@ PyInit__elementtree(void) if (PyType_Ready(&XMLParser_Type) < 0) return NULL; - m = PyModule_Create(&_elementtreemodule); + m = PyModule_Create(&elementtreemodule); if (!m) return NULL; + st = ET_STATE(m); if (!(temp = PyImport_ImportModule("copy"))) return NULL; - elementtree_deepcopy_obj = PyObject_GetAttrString(temp, "deepcopy"); + st->deepcopy_obj = PyObject_GetAttrString(temp, "deepcopy"); Py_XDECREF(temp); - if (!(elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath"))) + if (!(st->elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath"))) return NULL; /* link against pyexpat */ @@ -3695,11 +3745,11 @@ PyInit__elementtree(void) return NULL; } - elementtree_parseerror_obj = PyErr_NewException( + st->parseerror_obj = PyErr_NewException( "xml.etree.ElementTree.ParseError", PyExc_SyntaxError, NULL ); - Py_INCREF(elementtree_parseerror_obj); - PyModule_AddObject(m, "ParseError", elementtree_parseerror_obj); + Py_INCREF(st->parseerror_obj); + PyModule_AddObject(m, "ParseError", st->parseerror_obj); Py_INCREF((PyObject *)&Element_Type); PyModule_AddObject(m, "Element", (PyObject *)&Element_Type);