Issue #14207: the ParseError exception raised by _elementtree was made
consistent to the one raised by the Python module (the 'code' attribute was added). In addition, the exception is now documented. Added a test to check that ParseError has the required attributes, and threw away the equivalent doctest which is no longer required.
This commit is contained in:
parent
f996e775ea
commit
5b77d81314
|
@ -198,7 +198,6 @@ Functions
|
|||
Element Objects
|
||||
---------------
|
||||
|
||||
|
||||
.. class:: Element(tag, attrib={}, **extra)
|
||||
|
||||
Element class. This class defines the Element interface, and provides a
|
||||
|
@ -643,6 +642,24 @@ This is an example of counting the maximum depth of an XML file::
|
|||
>>> parser.close()
|
||||
4
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. class:: ParseError
|
||||
|
||||
XML parse error, raised by the various parsing methods in this module when
|
||||
parsing fails. The string representation of an instance of this exception
|
||||
will contain a user-friendly error message. In addition, it will have
|
||||
the following attributes available:
|
||||
|
||||
.. attribute:: code
|
||||
|
||||
A numeric error code from the expat parser. See the documentation of
|
||||
:mod:`xml.parsers.expat` for the list of error codes and their meanings.
|
||||
|
||||
.. attribute:: position
|
||||
|
||||
A tuple of *line*, *column* numbers, specifying where the error occurred.
|
||||
|
||||
.. rubric:: Footnotes
|
||||
|
||||
|
|
|
@ -1055,26 +1055,6 @@ def entity():
|
|||
'<document>text</document>'
|
||||
"""
|
||||
|
||||
def error(xml):
|
||||
"""
|
||||
|
||||
Test error handling.
|
||||
|
||||
>>> issubclass(ET.ParseError, SyntaxError)
|
||||
True
|
||||
>>> error("foo").position
|
||||
(1, 0)
|
||||
>>> error("<tag>&foo;</tag>").position
|
||||
(1, 5)
|
||||
>>> error("foobar<").position
|
||||
(1, 6)
|
||||
|
||||
"""
|
||||
try:
|
||||
ET.XML(xml)
|
||||
except ET.ParseError:
|
||||
return sys.exc_info()[1]
|
||||
|
||||
def namespace():
|
||||
"""
|
||||
Test namespace issues.
|
||||
|
@ -2039,6 +2019,27 @@ class StringIOTest(unittest.TestCase):
|
|||
self.assertEqual(tree.getroot().tag, 'site')
|
||||
|
||||
|
||||
class ParseErrorTest(unittest.TestCase):
|
||||
def test_subclass(self):
|
||||
self.assertIsInstance(ET.ParseError(), SyntaxError)
|
||||
|
||||
def _get_error(self, s):
|
||||
try:
|
||||
ET.fromstring(s)
|
||||
except ET.ParseError as e:
|
||||
return e
|
||||
|
||||
def test_error_position(self):
|
||||
self.assertEqual(self._get_error('foo').position, (1, 0))
|
||||
self.assertEqual(self._get_error('<tag>&foo;</tag>').position, (1, 5))
|
||||
self.assertEqual(self._get_error('foobar<').position, (1, 6))
|
||||
|
||||
def test_error_code(self):
|
||||
import xml.parsers.expat.errors as ERRORS
|
||||
self.assertEqual(self._get_error('foo').code,
|
||||
ERRORS.codes[ERRORS.XML_ERROR_SYNTAX])
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
|
@ -2091,6 +2092,7 @@ def test_main(module=pyET):
|
|||
test_classes = [
|
||||
ElementSlicingTest,
|
||||
StringIOTest,
|
||||
ParseErrorTest,
|
||||
ElementTreeTest,
|
||||
TreeBuilderTest]
|
||||
if module is pyET:
|
||||
|
|
|
@ -2177,13 +2177,18 @@ makeuniversal(XMLParserObject* self, const char* string)
|
|||
return value;
|
||||
}
|
||||
|
||||
/* Set the ParseError exception with the given parameters.
|
||||
* If message is not NULL, it's used as the error string. Otherwise, the
|
||||
* message string is the default for the given error_code.
|
||||
*/
|
||||
static void
|
||||
expat_set_error(const char* message, int line, int column)
|
||||
expat_set_error(enum XML_Error error_code, int line, int column, char *message)
|
||||
{
|
||||
PyObject *errmsg, *error, *position;
|
||||
PyObject *errmsg, *error, *position, *code;
|
||||
|
||||
errmsg = PyUnicode_FromFormat("%s: line %d, column %d",
|
||||
message, line, column);
|
||||
message ? message : EXPAT(ErrorString)(error_code),
|
||||
line, column);
|
||||
if (errmsg == NULL)
|
||||
return;
|
||||
|
||||
|
@ -2192,7 +2197,19 @@ expat_set_error(const char* message, int line, int column)
|
|||
if (!error)
|
||||
return;
|
||||
|
||||
/* add position attribute */
|
||||
/* Add code and position attributes */
|
||||
code = PyLong_FromLong((long)error_code);
|
||||
if (!code) {
|
||||
Py_DECREF(error);
|
||||
return;
|
||||
}
|
||||
if (PyObject_SetAttrString(error, "code", code) == -1) {
|
||||
Py_DECREF(error);
|
||||
Py_DECREF(code);
|
||||
return;
|
||||
}
|
||||
Py_DECREF(code);
|
||||
|
||||
position = Py_BuildValue("(ii)", line, column);
|
||||
if (!position) {
|
||||
Py_DECREF(error);
|
||||
|
@ -2244,9 +2261,10 @@ expat_default_handler(XMLParserObject* self, const XML_Char* data_in,
|
|||
char message[128] = "undefined entity ";
|
||||
strncat(message, data_in, data_len < 100?data_len:100);
|
||||
expat_set_error(
|
||||
message,
|
||||
XML_ERROR_UNDEFINED_ENTITY,
|
||||
EXPAT(GetErrorLineNumber)(self->parser),
|
||||
EXPAT(GetErrorColumnNumber)(self->parser)
|
||||
EXPAT(GetErrorColumnNumber)(self->parser),
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2629,9 +2647,10 @@ expat_parse(XMLParserObject* self, char* data, int data_len, int final)
|
|||
|
||||
if (!ok) {
|
||||
expat_set_error(
|
||||
EXPAT(ErrorString)(EXPAT(GetErrorCode)(self->parser)),
|
||||
EXPAT(GetErrorCode)(self->parser),
|
||||
EXPAT(GetErrorLineNumber)(self->parser),
|
||||
EXPAT(GetErrorColumnNumber)(self->parser)
|
||||
EXPAT(GetErrorColumnNumber)(self->parser),
|
||||
NULL
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue