mirror of
https://github.com/python/cpython.git
synced 2025-09-11 19:27:07 +00:00
Issue #14007: make TreeBuilder an actual type exposed from _elementtree, and subclassable.
This commit is contained in:
parent
d3f0882dfb
commit
58d548dff1
2 changed files with 91 additions and 74 deletions
|
@ -1979,6 +1979,20 @@ class TreeBuilderTest(unittest.TestCase):
|
||||||
parser.feed(self.sample1)
|
parser.feed(self.sample1)
|
||||||
self.assertIsNone(parser.close())
|
self.assertIsNone(parser.close())
|
||||||
|
|
||||||
|
def test_subclass(self):
|
||||||
|
class MyTreeBuilder(ET.TreeBuilder):
|
||||||
|
def foobar(self, x):
|
||||||
|
return x * 2
|
||||||
|
|
||||||
|
tb = MyTreeBuilder()
|
||||||
|
self.assertEqual(tb.foobar(10), 20)
|
||||||
|
|
||||||
|
parser = ET.XMLParser(target=tb)
|
||||||
|
parser.feed(self.sample1)
|
||||||
|
|
||||||
|
e = parser.close()
|
||||||
|
self.assertEqual(e.tag, 'html')
|
||||||
|
|
||||||
# XXX in _elementtree, the constructor of TreeBuilder expects no
|
# XXX in _elementtree, the constructor of TreeBuilder expects no
|
||||||
# arguments
|
# arguments
|
||||||
@unittest.expectedFailure
|
@unittest.expectedFailure
|
||||||
|
|
|
@ -1811,7 +1811,7 @@ typedef struct {
|
||||||
PyObject *data; /* data collector (string or list), or NULL */
|
PyObject *data; /* data collector (string or list), or NULL */
|
||||||
|
|
||||||
PyObject *stack; /* element stack */
|
PyObject *stack; /* element stack */
|
||||||
Py_ssize_t index; /* current stack size (0=empty) */
|
Py_ssize_t index; /* current stack size (0 means empty) */
|
||||||
|
|
||||||
/* element tracing */
|
/* element tracing */
|
||||||
PyObject *events; /* list of events, or NULL if not collecting */
|
PyObject *events; /* list of events, or NULL if not collecting */
|
||||||
|
@ -1819,7 +1819,6 @@ typedef struct {
|
||||||
PyObject *end_event_obj;
|
PyObject *end_event_obj;
|
||||||
PyObject *start_ns_event_obj;
|
PyObject *start_ns_event_obj;
|
||||||
PyObject *end_ns_event_obj;
|
PyObject *end_ns_event_obj;
|
||||||
|
|
||||||
} TreeBuilderObject;
|
} TreeBuilderObject;
|
||||||
|
|
||||||
static PyTypeObject TreeBuilder_Type;
|
static PyTypeObject TreeBuilder_Type;
|
||||||
|
@ -1829,44 +1828,38 @@ static PyTypeObject TreeBuilder_Type;
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* constructor and destructor */
|
/* constructor and destructor */
|
||||||
|
|
||||||
LOCAL(PyObject*)
|
static PyObject *
|
||||||
treebuilder_new(void)
|
treebuilder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
TreeBuilderObject* self;
|
TreeBuilderObject *t = (TreeBuilderObject *)type->tp_alloc(type, 0);
|
||||||
|
if (t != NULL) {
|
||||||
|
t->root = NULL;
|
||||||
|
|
||||||
self = PyObject_New(TreeBuilderObject, &TreeBuilder_Type);
|
Py_INCREF(Py_None);
|
||||||
if (self == NULL)
|
t->this = (ElementObject *)Py_None;
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
t->last = (ElementObject *)Py_None;
|
||||||
|
|
||||||
|
t->data = NULL;
|
||||||
|
t->stack = PyList_New(20);
|
||||||
|
if (!t->stack) {
|
||||||
|
Py_DECREF(t->this);
|
||||||
|
Py_DECREF(t->last);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
t->index = 0;
|
||||||
|
|
||||||
self->root = NULL;
|
t->events = NULL;
|
||||||
|
t->start_event_obj = t->end_event_obj = NULL;
|
||||||
Py_INCREF(Py_None);
|
t->start_ns_event_obj = t->end_ns_event_obj = NULL;
|
||||||
self->this = (ElementObject*) Py_None;
|
}
|
||||||
|
return (PyObject *)t;
|
||||||
Py_INCREF(Py_None);
|
|
||||||
self->last = (ElementObject*) Py_None;
|
|
||||||
|
|
||||||
self->data = NULL;
|
|
||||||
|
|
||||||
self->stack = PyList_New(20);
|
|
||||||
self->index = 0;
|
|
||||||
|
|
||||||
self->events = NULL;
|
|
||||||
self->start_event_obj = self->end_event_obj = NULL;
|
|
||||||
self->start_ns_event_obj = self->end_ns_event_obj = NULL;
|
|
||||||
|
|
||||||
ALLOC(sizeof(TreeBuilderObject), "create treebuilder");
|
|
||||||
|
|
||||||
return (PyObject*) self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static int
|
||||||
treebuilder(PyObject* self_, PyObject* args)
|
treebuilder_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
if (!PyArg_ParseTuple(args, ":TreeBuilder"))
|
return 0;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return treebuilder_new();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1883,9 +1876,7 @@ treebuilder_dealloc(TreeBuilderObject* self)
|
||||||
Py_DECREF(self->this);
|
Py_DECREF(self->this);
|
||||||
Py_XDECREF(self->root);
|
Py_XDECREF(self->root);
|
||||||
|
|
||||||
RELEASE(sizeof(TreeBuilderObject), "destroy treebuilder");
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||||
|
|
||||||
PyObject_Del(self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@ -2189,7 +2180,7 @@ static PyTypeObject TreeBuilder_Type = {
|
||||||
0, /* tp_getattro */
|
0, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
0, /* tp_doc */
|
0, /* tp_doc */
|
||||||
0, /* tp_traverse */
|
0, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
|
@ -2199,6 +2190,16 @@ static PyTypeObject TreeBuilder_Type = {
|
||||||
0, /* tp_iternext */
|
0, /* tp_iternext */
|
||||||
treebuilder_methods, /* tp_methods */
|
treebuilder_methods, /* tp_methods */
|
||||||
0, /* tp_members */
|
0, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
(initproc)treebuilder_init, /* tp_init */
|
||||||
|
PyType_GenericAlloc, /* tp_alloc */
|
||||||
|
treebuilder_new, /* tp_new */
|
||||||
|
0, /* tp_free */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
|
@ -2684,7 +2685,7 @@ xmlparser(PyObject* self_, PyObject* args, PyObject* kw)
|
||||||
|
|
||||||
/* setup target handlers */
|
/* setup target handlers */
|
||||||
if (!target) {
|
if (!target) {
|
||||||
target = treebuilder_new();
|
target = treebuilder_new(&TreeBuilder_Type, NULL, NULL);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
EXPAT(ParserFree)(self->parser);
|
EXPAT(ParserFree)(self->parser);
|
||||||
PyObject_Del(self->names);
|
PyObject_Del(self->names);
|
||||||
|
@ -3073,7 +3074,6 @@ static PyTypeObject XMLParser_Type = {
|
||||||
|
|
||||||
static PyMethodDef _functions[] = {
|
static PyMethodDef _functions[] = {
|
||||||
{"SubElement", (PyCFunction) subelement, METH_VARARGS|METH_KEYWORDS},
|
{"SubElement", (PyCFunction) subelement, METH_VARARGS|METH_KEYWORDS},
|
||||||
{"TreeBuilder", (PyCFunction) treebuilder, METH_VARARGS},
|
|
||||||
#if defined(USE_EXPAT)
|
#if defined(USE_EXPAT)
|
||||||
{"XMLParser", (PyCFunction) xmlparser, METH_VARARGS|METH_KEYWORDS},
|
{"XMLParser", (PyCFunction) xmlparser, METH_VARARGS|METH_KEYWORDS},
|
||||||
#endif
|
#endif
|
||||||
|
@ -3185,5 +3185,8 @@ PyInit__elementtree(void)
|
||||||
Py_INCREF((PyObject *)&Element_Type);
|
Py_INCREF((PyObject *)&Element_Type);
|
||||||
PyModule_AddObject(m, "Element", (PyObject *)&Element_Type);
|
PyModule_AddObject(m, "Element", (PyObject *)&Element_Type);
|
||||||
|
|
||||||
|
Py_INCREF((PyObject *)&TreeBuilder_Type);
|
||||||
|
PyModule_AddObject(m, "TreeBuilder", (PyObject *)&TreeBuilder_Type);
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue