Issue #15651: PEP 3121 refactoring for _elementtree
Patch by Antoine Pitrou (based on Robin Schreiber's original patch)
This commit is contained in:
parent
c7c953adfe
commit
532d03e547
|
@ -66,10 +66,51 @@ static PyTypeObject TreeBuilder_Type;
|
||||||
static PyTypeObject XMLParser_Type;
|
static PyTypeObject XMLParser_Type;
|
||||||
|
|
||||||
|
|
||||||
/* glue functions (see the init function for details) */
|
/* Per-module state; PEP 3121 */
|
||||||
static PyObject* elementtree_parseerror_obj;
|
typedef struct {
|
||||||
static PyObject* elementtree_deepcopy_obj;
|
PyObject *parseerror_obj;
|
||||||
static PyObject* elementpath_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 */
|
/* helpers */
|
||||||
|
|
||||||
|
@ -77,11 +118,11 @@ LOCAL(PyObject*)
|
||||||
deepcopy(PyObject* object, PyObject* memo)
|
deepcopy(PyObject* object, PyObject* memo)
|
||||||
{
|
{
|
||||||
/* do a deep copy of the given object */
|
/* do a deep copy of the given object */
|
||||||
|
|
||||||
PyObject* args;
|
PyObject* args;
|
||||||
PyObject* result;
|
PyObject* result;
|
||||||
|
elementtreestate *st = ET_STATE_GLOBAL;
|
||||||
|
|
||||||
if (!elementtree_deepcopy_obj) {
|
if (!st->deepcopy_obj) {
|
||||||
PyErr_SetString(
|
PyErr_SetString(
|
||||||
PyExc_RuntimeError,
|
PyExc_RuntimeError,
|
||||||
"deepcopy helper not found"
|
"deepcopy helper not found"
|
||||||
|
@ -92,7 +133,7 @@ deepcopy(PyObject* object, PyObject* memo)
|
||||||
args = PyTuple_Pack(2, object, memo);
|
args = PyTuple_Pack(2, object, memo);
|
||||||
if (!args)
|
if (!args)
|
||||||
return NULL;
|
return NULL;
|
||||||
result = PyObject_CallObject(elementtree_deepcopy_obj, args);
|
result = PyObject_CallObject(st->deepcopy_obj, args);
|
||||||
Py_DECREF(args);
|
Py_DECREF(args);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1047,6 +1088,7 @@ element_find(ElementObject *self, PyObject *args, PyObject *kwds)
|
||||||
PyObject* tag;
|
PyObject* tag;
|
||||||
PyObject* namespaces = Py_None;
|
PyObject* namespaces = Py_None;
|
||||||
static char *kwlist[] = {"path", "namespaces", 0};
|
static char *kwlist[] = {"path", "namespaces", 0};
|
||||||
|
elementtreestate *st = ET_STATE_GLOBAL;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:find", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:find", kwlist,
|
||||||
&tag, &namespaces))
|
&tag, &namespaces))
|
||||||
|
@ -1055,7 +1097,7 @@ element_find(ElementObject *self, PyObject *args, PyObject *kwds)
|
||||||
if (checkpath(tag) || namespaces != Py_None) {
|
if (checkpath(tag) || namespaces != Py_None) {
|
||||||
_Py_IDENTIFIER(find);
|
_Py_IDENTIFIER(find);
|
||||||
return _PyObject_CallMethodId(
|
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;
|
PyObject* namespaces = Py_None;
|
||||||
_Py_IDENTIFIER(findtext);
|
_Py_IDENTIFIER(findtext);
|
||||||
static char *kwlist[] = {"path", "default", "namespaces", 0};
|
static char *kwlist[] = {"path", "default", "namespaces", 0};
|
||||||
|
elementtreestate *st = ET_STATE_GLOBAL;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO:findtext", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO:findtext", kwlist,
|
||||||
&tag, &default_value, &namespaces))
|
&tag, &default_value, &namespaces))
|
||||||
|
@ -1090,7 +1133,7 @@ element_findtext(ElementObject *self, PyObject *args, PyObject *kwds)
|
||||||
|
|
||||||
if (checkpath(tag) || namespaces != Py_None)
|
if (checkpath(tag) || namespaces != Py_None)
|
||||||
return _PyObject_CallMethodId(
|
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) {
|
if (!self->extra) {
|
||||||
|
@ -1122,6 +1165,7 @@ element_findall(ElementObject *self, PyObject *args, PyObject *kwds)
|
||||||
PyObject* tag;
|
PyObject* tag;
|
||||||
PyObject* namespaces = Py_None;
|
PyObject* namespaces = Py_None;
|
||||||
static char *kwlist[] = {"path", "namespaces", 0};
|
static char *kwlist[] = {"path", "namespaces", 0};
|
||||||
|
elementtreestate *st = ET_STATE_GLOBAL;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:findall", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:findall", kwlist,
|
||||||
&tag, &namespaces))
|
&tag, &namespaces))
|
||||||
|
@ -1130,7 +1174,7 @@ element_findall(ElementObject *self, PyObject *args, PyObject *kwds)
|
||||||
if (checkpath(tag) || namespaces != Py_None) {
|
if (checkpath(tag) || namespaces != Py_None) {
|
||||||
_Py_IDENTIFIER(findall);
|
_Py_IDENTIFIER(findall);
|
||||||
return _PyObject_CallMethodId(
|
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;
|
PyObject* namespaces = Py_None;
|
||||||
_Py_IDENTIFIER(iterfind);
|
_Py_IDENTIFIER(iterfind);
|
||||||
static char *kwlist[] = {"path", "namespaces", 0};
|
static char *kwlist[] = {"path", "namespaces", 0};
|
||||||
|
elementtreestate *st = ET_STATE_GLOBAL;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:iterfind", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:iterfind", kwlist,
|
||||||
&tag, &namespaces))
|
&tag, &namespaces))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return _PyObject_CallMethodId(
|
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* node;
|
||||||
PyObject* this;
|
PyObject* this;
|
||||||
|
elementtreestate *st = ET_STATE_GLOBAL;
|
||||||
|
|
||||||
if (self->data) {
|
if (self->data) {
|
||||||
if (self->this == self->last) {
|
if (self->this == self->last) {
|
||||||
|
@ -2381,7 +2427,7 @@ treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag,
|
||||||
} else {
|
} else {
|
||||||
if (self->root) {
|
if (self->root) {
|
||||||
PyErr_SetString(
|
PyErr_SetString(
|
||||||
elementtree_parseerror_obj,
|
st->parseerror_obj,
|
||||||
"multiple elements on top level"
|
"multiple elements on top level"
|
||||||
);
|
);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -2670,6 +2716,10 @@ static PyTypeObject TreeBuilder_Type = {
|
||||||
|
|
||||||
#include "expat.h"
|
#include "expat.h"
|
||||||
#include "pyexpat.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;
|
static struct PyExpat_CAPI *expat_capi;
|
||||||
#define EXPAT(func) (expat_capi->func)
|
#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)
|
expat_set_error(enum XML_Error error_code, int line, int column, char *message)
|
||||||
{
|
{
|
||||||
PyObject *errmsg, *error, *position, *code;
|
PyObject *errmsg, *error, *position, *code;
|
||||||
|
elementtreestate *st = ET_STATE_GLOBAL;
|
||||||
|
|
||||||
errmsg = PyUnicode_FromFormat("%s: line %d, column %d",
|
errmsg = PyUnicode_FromFormat("%s: line %d, column %d",
|
||||||
message ? message : EXPAT(ErrorString)(error_code),
|
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)
|
if (errmsg == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error = PyObject_CallFunction(elementtree_parseerror_obj, "O", errmsg);
|
error = PyObject_CallFunction(st->parseerror_obj, "O", errmsg);
|
||||||
Py_DECREF(errmsg);
|
Py_DECREF(errmsg);
|
||||||
if (!error)
|
if (!error)
|
||||||
return;
|
return;
|
||||||
|
@ -2816,7 +2867,7 @@ expat_set_error(enum XML_Error error_code, int line, int column, char *message)
|
||||||
}
|
}
|
||||||
Py_DECREF(position);
|
Py_DECREF(position);
|
||||||
|
|
||||||
PyErr_SetObject(elementtree_parseerror_obj, error);
|
PyErr_SetObject(st->parseerror_obj, error);
|
||||||
Py_DECREF(error);
|
Py_DECREF(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3639,22 +3690,29 @@ static PyMethodDef _functions[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static struct PyModuleDef _elementtreemodule = {
|
static struct PyModuleDef elementtreemodule = {
|
||||||
PyModuleDef_HEAD_INIT,
|
PyModuleDef_HEAD_INIT,
|
||||||
"_elementtree",
|
"_elementtree",
|
||||||
NULL,
|
NULL,
|
||||||
-1,
|
sizeof(elementtreestate),
|
||||||
_functions,
|
_functions,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
elementtree_traverse,
|
||||||
NULL,
|
elementtree_clear,
|
||||||
NULL
|
elementtree_free
|
||||||
};
|
};
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
PyInit__elementtree(void)
|
PyInit__elementtree(void)
|
||||||
{
|
{
|
||||||
PyObject *m, *temp;
|
PyObject *m, *temp;
|
||||||
|
elementtreestate *st;
|
||||||
|
|
||||||
|
m = PyState_FindModule(&elementtreemodule);
|
||||||
|
if (m) {
|
||||||
|
Py_INCREF(m);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize object types */
|
/* Initialize object types */
|
||||||
if (PyType_Ready(&ElementIter_Type) < 0)
|
if (PyType_Ready(&ElementIter_Type) < 0)
|
||||||
|
@ -3666,16 +3724,17 @@ PyInit__elementtree(void)
|
||||||
if (PyType_Ready(&XMLParser_Type) < 0)
|
if (PyType_Ready(&XMLParser_Type) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
m = PyModule_Create(&_elementtreemodule);
|
m = PyModule_Create(&elementtreemodule);
|
||||||
if (!m)
|
if (!m)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
st = ET_STATE(m);
|
||||||
|
|
||||||
if (!(temp = PyImport_ImportModule("copy")))
|
if (!(temp = PyImport_ImportModule("copy")))
|
||||||
return NULL;
|
return NULL;
|
||||||
elementtree_deepcopy_obj = PyObject_GetAttrString(temp, "deepcopy");
|
st->deepcopy_obj = PyObject_GetAttrString(temp, "deepcopy");
|
||||||
Py_XDECREF(temp);
|
Py_XDECREF(temp);
|
||||||
|
|
||||||
if (!(elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath")))
|
if (!(st->elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath")))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* link against pyexpat */
|
/* link against pyexpat */
|
||||||
|
@ -3695,11 +3754,11 @@ PyInit__elementtree(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
elementtree_parseerror_obj = PyErr_NewException(
|
st->parseerror_obj = PyErr_NewException(
|
||||||
"xml.etree.ElementTree.ParseError", PyExc_SyntaxError, NULL
|
"xml.etree.ElementTree.ParseError", PyExc_SyntaxError, NULL
|
||||||
);
|
);
|
||||||
Py_INCREF(elementtree_parseerror_obj);
|
Py_INCREF(st->parseerror_obj);
|
||||||
PyModule_AddObject(m, "ParseError", elementtree_parseerror_obj);
|
PyModule_AddObject(m, "ParseError", st->parseerror_obj);
|
||||||
|
|
||||||
Py_INCREF((PyObject *)&Element_Type);
|
Py_INCREF((PyObject *)&Element_Type);
|
||||||
PyModule_AddObject(m, "Element", (PyObject *)&Element_Type);
|
PyModule_AddObject(m, "Element", (PyObject *)&Element_Type);
|
||||||
|
|
Loading…
Reference in New Issue