summaryrefslogtreecommitdiffstats
path: root/Modules/_elementtree.c
diff options
context:
space:
mode:
authorEli Bendersky <eliben@gmail.com>2013-08-10 15:00:39 (GMT)
committerEli Bendersky <eliben@gmail.com>2013-08-10 15:00:39 (GMT)
commit532d03e5479d1ef94e311e370ff711b7bc2566c8 (patch)
tree188852bfca082ef6c4a2746cd75e3952017c47f2 /Modules/_elementtree.c
parentc7c953adfe9914896442c424b2b073f7c8a863b0 (diff)
downloadcpython-532d03e5479d1ef94e311e370ff711b7bc2566c8.zip
cpython-532d03e5479d1ef94e311e370ff711b7bc2566c8.tar.gz
cpython-532d03e5479d1ef94e311e370ff711b7bc2566c8.tar.bz2
Issue #15651: PEP 3121 refactoring for _elementtree
Patch by Antoine Pitrou (based on Robin Schreiber's original patch)
Diffstat (limited to 'Modules/_elementtree.c')
-rw-r--r--Modules/_elementtree.c119
1 files changed, 89 insertions, 30 deletions
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index d488f01..3c1358c 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -66,10 +66,51 @@ static PyTypeObject TreeBuilder_Type;
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;
+/* Per-module state; PEP 3121 */
+typedef struct {
+ PyObject *parseerror_obj;
+ PyObject *deepcopy_obj;
+ PyObject *elementpath_obj;
+} elementtreestate;
+
+static struct PyModuleDef elementtreemodule;
+
+/* Given a module object (assumed to be _elementtree), get its per-module
+ * state.
+ */
+#define ET_STATE(mod) ((elementtreestate *) PyModule_GetState(mod))
+
+/* Find the module instance imported in the currently running sub-interpreter
+ * and get its state.
+ */
+#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 +118,11 @@ LOCAL(PyObject*)
deepcopy(PyObject* object, PyObject* memo)
{
/* do a deep copy of the given object */
-
PyObject* args;
PyObject* result;
+ elementtreestate *st = ET_STATE_GLOBAL;
- if (!elementtree_deepcopy_obj) {
+ if (!st->deepcopy_obj) {
PyErr_SetString(
PyExc_RuntimeError,
"deepcopy helper not found"
@@ -92,7 +133,7 @@ deepcopy(PyObject* object, PyObject* memo)
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 +1088,7 @@ element_find(ElementObject *self, PyObject *args, PyObject *kwds)
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 +1097,7 @@ element_find(ElementObject *self, PyObject *args, PyObject *kwds)
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 +1125,7 @@ element_findtext(ElementObject *self, PyObject *args, PyObject *kwds)
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 +1133,7 @@ element_findtext(ElementObject *self, PyObject *args, PyObject *kwds)
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 +1165,7 @@ element_findall(ElementObject *self, PyObject *args, PyObject *kwds)
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 +1174,7 @@ element_findall(ElementObject *self, PyObject *args, PyObject *kwds)
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 +1206,14 @@ element_iterfind(ElementObject *self, PyObject *args, PyObject *kwds)
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 +2396,7 @@ treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag,
{
PyObject* node;
PyObject* this;
+ elementtreestate *st = ET_STATE_GLOBAL;
if (self->data) {
if (self->this == self->last) {
@@ -2381,7 +2427,7 @@ treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag,
} else {
if (self->root) {
PyErr_SetString(
- elementtree_parseerror_obj,
+ st->parseerror_obj,
"multiple elements on top level"
);
goto error;
@@ -2670,6 +2716,10 @@ static PyTypeObject TreeBuilder_Type = {
#include "expat.h"
#include "pyexpat.h"
+
+/* The PyExpat_CAPI structure is an immutable dispatch table, so it can be
+ * cached globally without being in per-module state.
+ */
static struct PyExpat_CAPI *expat_capi;
#define EXPAT(func) (expat_capi->func)
@@ -2779,6 +2829,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 +2837,7 @@ expat_set_error(enum XML_Error error_code, int line, int column, char *message)
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 +2867,7 @@ expat_set_error(enum XML_Error error_code, int line, int column, char *message)
}
Py_DECREF(position);
- PyErr_SetObject(elementtree_parseerror_obj, error);
+ PyErr_SetObject(st->parseerror_obj, error);
Py_DECREF(error);
}
@@ -3639,22 +3690,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 +3724,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 +3754,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);