Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Lib/test/test_xml_etree.py
Original file line number Diff line number Diff line change
Expand Up @@ -2400,6 +2400,29 @@ def _check_sample1_element(self, e):
self.assertEqual(child.tail, 'tail')
self.assertEqual(child.attrib, {})

def test_exceptions(self):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't XMLParserTest be better place? In any case I think it is better to place this method at the end of the class, after testing normal cases.

And maybe use more specific method name? "test_builder_attribute_errors" or something like.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I kept it in the test class because the exceptions are related to the behaviour of the TreeBuilder.

class RaisingBuilder:
def __init__(self, raise_in=None, what=ValueError):
self.raise_in = raise_in
self.what = what

def __getattr__(self, name):
if name == self.raise_in:
raise self.what(self.raise_in)
def handle(*args):
pass
return handle

ET.XMLParser(target=RaisingBuilder())
# cET also checks for 'close' and 'doctype', PyET does it only at need
for event in ('start', 'data', 'end', 'comment', 'pi'):
with self.assertRaisesRegex(ValueError, event):
ET.XMLParser(target=RaisingBuilder(event))

ET.XMLParser(target=RaisingBuilder(what=AttributeError))
for event in ('start', 'data', 'end', 'comment', 'pi'):
ET.XMLParser(target=RaisingBuilder(event, what=AttributeError))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Close the parser explicitly. Just for the case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. (Requires parsing something, though.)


def test_dummy_builder(self):
class BaseDummyBuilder:
def close(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The C accelerator module of ElementTree ignored exceptions raised when
looking up TreeBuilder target methods in XMLParser().
27 changes: 25 additions & 2 deletions Modules/_elementtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -3259,6 +3259,17 @@ xmlparser_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return (PyObject *)self;
}

static int
ignore_attribute_error(PyObject *value) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this { on new line.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if (value == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
return -1;
}
PyErr_Clear();
}
return 0;
}

/*[clinic input]
_elementtree.XMLParser.__init__

Expand Down Expand Up @@ -3313,14 +3324,26 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *html,
self->target = target;

self->handle_start = PyObject_GetAttrString(target, "start");
if (ignore_attribute_error(self->handle_start))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New PEP 7 rules require braces even around simple if body.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. (Sad in this case, given the relation between "active" code and error handling code.)

return -1;
self->handle_data = PyObject_GetAttrString(target, "data");
if (ignore_attribute_error(self->handle_data))
return -1;
self->handle_end = PyObject_GetAttrString(target, "end");
if (ignore_attribute_error(self->handle_end))
return -1;
self->handle_comment = PyObject_GetAttrString(target, "comment");
if (ignore_attribute_error(self->handle_comment))
return -1;
self->handle_pi = PyObject_GetAttrString(target, "pi");
if (ignore_attribute_error(self->handle_pi))
return -1;
self->handle_close = PyObject_GetAttrString(target, "close");
if (ignore_attribute_error(self->handle_close))
return -1;
self->handle_doctype = PyObject_GetAttrString(target, "doctype");

PyErr_Clear();
if (ignore_attribute_error(self->handle_doctype))
return -1;

/* configure parser */
EXPAT(SetUserData)(self->parser, self);
Expand Down