Commit 58d548df authored by Eli Bendersky's avatar Eli Bendersky

Issue #14007: make TreeBuilder an actual type exposed from _elementtree, and subclassable.

parent d3f0882d
...@@ -1979,6 +1979,20 @@ class TreeBuilderTest(unittest.TestCase): ...@@ -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
......
...@@ -1803,23 +1803,22 @@ static PyTypeObject Element_Type = { ...@@ -1803,23 +1803,22 @@ static PyTypeObject Element_Type = {
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject* root; /* root node (first created node) */ PyObject *root; /* root node (first created node) */
ElementObject* this; /* current node */ ElementObject *this; /* current node */
ElementObject* last; /* most recently created node */ ElementObject *last; /* most recently created node */
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 */
PyObject* start_event_obj; /* event objects (NULL to ignore) */ PyObject *start_event_obj; /* event objects (NULL to ignore) */
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,48 +1828,42 @@ static PyTypeObject TreeBuilder_Type; ...@@ -1829,48 +1828,42 @@ 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) {
self = PyObject_New(TreeBuilderObject, &TreeBuilder_Type); t->root = NULL;
if (self == NULL)
return NULL;
self->root = NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
self->this = (ElementObject*) Py_None; t->this = (ElementObject *)Py_None;
Py_INCREF(Py_None); Py_INCREF(Py_None);
self->last = (ElementObject*) Py_None; t->last = (ElementObject *)Py_None;
self->data = NULL; t->data = NULL;
t->stack = PyList_New(20);
self->stack = PyList_New(20); if (!t->stack) {
self->index = 0; Py_DECREF(t->this);
Py_DECREF(t->last);
self->events = NULL; return NULL;
self->start_event_obj = self->end_event_obj = NULL; }
self->start_ns_event_obj = self->end_ns_event_obj = NULL; t->index = 0;
ALLOC(sizeof(TreeBuilderObject), "create treebuilder");
return (PyObject*) self; t->events = NULL;
t->start_event_obj = t->end_event_obj = NULL;
t->start_ns_event_obj = t->end_ns_event_obj = NULL;
}
return (PyObject *)t;
} }
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
treebuilder_dealloc(TreeBuilderObject* self) treebuilder_dealloc(TreeBuilderObject *self)
{ {
Py_XDECREF(self->end_ns_event_obj); Py_XDECREF(self->end_ns_event_obj);
Py_XDECREF(self->start_ns_event_obj); Py_XDECREF(self->start_ns_event_obj);
...@@ -1883,9 +1876,7 @@ treebuilder_dealloc(TreeBuilderObject* self) ...@@ -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 = { ...@@ -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 = { ...@@ -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) ...@@ -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 = { ...@@ -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) ...@@ -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;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment