Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 58d548d

Browse files
committed
Issue #14007: make TreeBuilder an actual type exposed from _elementtree, and subclassable.
1 parent d3f0882 commit 58d548d

2 files changed

Lines changed: 91 additions & 74 deletions

File tree

Lib/test/test_xml_etree.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,20 @@ class DummyBuilder(BaseDummyBuilder):
19791979
parser.feed(self.sample1)
19801980
self.assertIsNone(parser.close())
19811981

1982+
def test_subclass(self):
1983+
class MyTreeBuilder(ET.TreeBuilder):
1984+
def foobar(self, x):
1985+
return x * 2
1986+
1987+
tb = MyTreeBuilder()
1988+
self.assertEqual(tb.foobar(10), 20)
1989+
1990+
parser = ET.XMLParser(target=tb)
1991+
parser.feed(self.sample1)
1992+
1993+
e = parser.close()
1994+
self.assertEqual(e.tag, 'html')
1995+
19821996
# XXX in _elementtree, the constructor of TreeBuilder expects no
19831997
# arguments
19841998
@unittest.expectedFailure

Modules/_elementtree.c

Lines changed: 77 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,23 +1803,22 @@ static PyTypeObject Element_Type = {
18031803
typedef struct {
18041804
PyObject_HEAD
18051805

1806-
PyObject* root; /* root node (first created node) */
1806+
PyObject *root; /* root node (first created node) */
18071807

1808-
ElementObject* this; /* current node */
1809-
ElementObject* last; /* most recently created node */
1808+
ElementObject *this; /* current node */
1809+
ElementObject *last; /* most recently created node */
18101810

1811-
PyObject* data; /* data collector (string or list), or NULL */
1811+
PyObject *data; /* data collector (string or list), or NULL */
18121812

1813-
PyObject* stack; /* element stack */
1814-
Py_ssize_t index; /* current stack size (0=empty) */
1813+
PyObject *stack; /* element stack */
1814+
Py_ssize_t index; /* current stack size (0 means empty) */
18151815

18161816
/* element tracing */
1817-
PyObject* events; /* list of events, or NULL if not collecting */
1818-
PyObject* start_event_obj; /* event objects (NULL to ignore) */
1819-
PyObject* end_event_obj;
1820-
PyObject* start_ns_event_obj;
1821-
PyObject* end_ns_event_obj;
1822-
1817+
PyObject *events; /* list of events, or NULL if not collecting */
1818+
PyObject *start_event_obj; /* event objects (NULL to ignore) */
1819+
PyObject *end_event_obj;
1820+
PyObject *start_ns_event_obj;
1821+
PyObject *end_ns_event_obj;
18231822
} TreeBuilderObject;
18241823

18251824
static PyTypeObject TreeBuilder_Type;
@@ -1829,48 +1828,42 @@ static PyTypeObject TreeBuilder_Type;
18291828
/* -------------------------------------------------------------------- */
18301829
/* constructor and destructor */
18311830

1832-
LOCAL(PyObject*)
1833-
treebuilder_new(void)
1831+
static PyObject *
1832+
treebuilder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
18341833
{
1835-
TreeBuilderObject* self;
1836-
1837-
self = PyObject_New(TreeBuilderObject, &TreeBuilder_Type);
1838-
if (self == NULL)
1839-
return NULL;
1840-
1841-
self->root = NULL;
1842-
1843-
Py_INCREF(Py_None);
1844-
self->this = (ElementObject*) Py_None;
1834+
TreeBuilderObject *t = (TreeBuilderObject *)type->tp_alloc(type, 0);
1835+
if (t != NULL) {
1836+
t->root = NULL;
18451837

1846-
Py_INCREF(Py_None);
1847-
self->last = (ElementObject*) Py_None;
1848-
1849-
self->data = NULL;
1850-
1851-
self->stack = PyList_New(20);
1852-
self->index = 0;
1853-
1854-
self->events = NULL;
1855-
self->start_event_obj = self->end_event_obj = NULL;
1856-
self->start_ns_event_obj = self->end_ns_event_obj = NULL;
1838+
Py_INCREF(Py_None);
1839+
t->this = (ElementObject *)Py_None;
1840+
Py_INCREF(Py_None);
1841+
t->last = (ElementObject *)Py_None;
18571842

1858-
ALLOC(sizeof(TreeBuilderObject), "create treebuilder");
1843+
t->data = NULL;
1844+
t->stack = PyList_New(20);
1845+
if (!t->stack) {
1846+
Py_DECREF(t->this);
1847+
Py_DECREF(t->last);
1848+
return NULL;
1849+
}
1850+
t->index = 0;
18591851

1860-
return (PyObject*) self;
1852+
t->events = NULL;
1853+
t->start_event_obj = t->end_event_obj = NULL;
1854+
t->start_ns_event_obj = t->end_ns_event_obj = NULL;
1855+
}
1856+
return (PyObject *)t;
18611857
}
18621858

1863-
static PyObject*
1864-
treebuilder(PyObject* self_, PyObject* args)
1859+
static int
1860+
treebuilder_init(PyObject *self, PyObject *args, PyObject *kwds)
18651861
{
1866-
if (!PyArg_ParseTuple(args, ":TreeBuilder"))
1867-
return NULL;
1868-
1869-
return treebuilder_new();
1862+
return 0;
18701863
}
18711864

18721865
static void
1873-
treebuilder_dealloc(TreeBuilderObject* self)
1866+
treebuilder_dealloc(TreeBuilderObject *self)
18741867
{
18751868
Py_XDECREF(self->end_ns_event_obj);
18761869
Py_XDECREF(self->start_ns_event_obj);
@@ -1883,9 +1876,7 @@ treebuilder_dealloc(TreeBuilderObject* self)
18831876
Py_DECREF(self->this);
18841877
Py_XDECREF(self->root);
18851878

1886-
RELEASE(sizeof(TreeBuilderObject), "destroy treebuilder");
1887-
1888-
PyObject_Del(self);
1879+
Py_TYPE(self)->tp_free((PyObject *)self);
18891880
}
18901881

18911882
/* -------------------------------------------------------------------- */
@@ -2174,31 +2165,41 @@ static PyTypeObject TreeBuilder_Type = {
21742165
PyVarObject_HEAD_INIT(NULL, 0)
21752166
"TreeBuilder", sizeof(TreeBuilderObject), 0,
21762167
/* methods */
2177-
(destructor)treebuilder_dealloc, /* tp_dealloc */
2178-
0, /* tp_print */
2179-
0, /* tp_getattr */
2180-
0, /* tp_setattr */
2181-
0, /* tp_reserved */
2182-
0, /* tp_repr */
2183-
0, /* tp_as_number */
2184-
0, /* tp_as_sequence */
2185-
0, /* tp_as_mapping */
2186-
0, /* tp_hash */
2187-
0, /* tp_call */
2188-
0, /* tp_str */
2189-
0, /* tp_getattro */
2190-
0, /* tp_setattro */
2191-
0, /* tp_as_buffer */
2192-
Py_TPFLAGS_DEFAULT, /* tp_flags */
2193-
0, /* tp_doc */
2194-
0, /* tp_traverse */
2195-
0, /* tp_clear */
2196-
0, /* tp_richcompare */
2197-
0, /* tp_weaklistoffset */
2198-
0, /* tp_iter */
2199-
0, /* tp_iternext */
2200-
treebuilder_methods, /* tp_methods */
2201-
0, /* tp_members */
2168+
(destructor)treebuilder_dealloc, /* tp_dealloc */
2169+
0, /* tp_print */
2170+
0, /* tp_getattr */
2171+
0, /* tp_setattr */
2172+
0, /* tp_reserved */
2173+
0, /* tp_repr */
2174+
0, /* tp_as_number */
2175+
0, /* tp_as_sequence */
2176+
0, /* tp_as_mapping */
2177+
0, /* tp_hash */
2178+
0, /* tp_call */
2179+
0, /* tp_str */
2180+
0, /* tp_getattro */
2181+
0, /* tp_setattro */
2182+
0, /* tp_as_buffer */
2183+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
2184+
0, /* tp_doc */
2185+
0, /* tp_traverse */
2186+
0, /* tp_clear */
2187+
0, /* tp_richcompare */
2188+
0, /* tp_weaklistoffset */
2189+
0, /* tp_iter */
2190+
0, /* tp_iternext */
2191+
treebuilder_methods, /* tp_methods */
2192+
0, /* tp_members */
2193+
0, /* tp_getset */
2194+
0, /* tp_base */
2195+
0, /* tp_dict */
2196+
0, /* tp_descr_get */
2197+
0, /* tp_descr_set */
2198+
0, /* tp_dictoffset */
2199+
(initproc)treebuilder_init, /* tp_init */
2200+
PyType_GenericAlloc, /* tp_alloc */
2201+
treebuilder_new, /* tp_new */
2202+
0, /* tp_free */
22022203
};
22032204

22042205
/* ==================================================================== */
@@ -2684,7 +2685,7 @@ xmlparser(PyObject* self_, PyObject* args, PyObject* kw)
26842685

26852686
/* setup target handlers */
26862687
if (!target) {
2687-
target = treebuilder_new();
2688+
target = treebuilder_new(&TreeBuilder_Type, NULL, NULL);
26882689
if (!target) {
26892690
EXPAT(ParserFree)(self->parser);
26902691
PyObject_Del(self->names);
@@ -3073,7 +3074,6 @@ static PyTypeObject XMLParser_Type = {
30733074

30743075
static PyMethodDef _functions[] = {
30753076
{"SubElement", (PyCFunction) subelement, METH_VARARGS|METH_KEYWORDS},
3076-
{"TreeBuilder", (PyCFunction) treebuilder, METH_VARARGS},
30773077
#if defined(USE_EXPAT)
30783078
{"XMLParser", (PyCFunction) xmlparser, METH_VARARGS|METH_KEYWORDS},
30793079
#endif
@@ -3185,5 +3185,8 @@ PyInit__elementtree(void)
31853185
Py_INCREF((PyObject *)&Element_Type);
31863186
PyModule_AddObject(m, "Element", (PyObject *)&Element_Type);
31873187

3188+
Py_INCREF((PyObject *)&TreeBuilder_Type);
3189+
PyModule_AddObject(m, "TreeBuilder", (PyObject *)&TreeBuilder_Type);
3190+
31883191
return m;
31893192
}

0 commit comments

Comments
 (0)