Commit b4dac71a authored by Georg Brandl's avatar Georg Brandl

#5355: Provide mappings from Expat error numbers to string descriptions and...

#5355: Provide mappings from Expat error numbers to string descriptions and backwards, in order to actually make it possible to analyze error codes provided by ExpatError.
parent f668df5f
...@@ -169,7 +169,7 @@ XMLParser Objects ...@@ -169,7 +169,7 @@ XMLParser Objects
This method can only be called before the :meth:`Parse` or :meth:`ParseFile` This method can only be called before the :meth:`Parse` or :meth:`ParseFile`
methods are called; calling it after either of those have been called causes methods are called; calling it after either of those have been called causes
:exc:`ExpatError` to be raised with the :attr:`code` attribute set to :exc:`ExpatError` to be raised with the :attr:`code` attribute set to
:const:`errors.XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING`. ``errors.codes[errors.XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING]``.
:class:`xmlparser` objects have the following attributes: :class:`xmlparser` objects have the following attributes:
...@@ -467,8 +467,21 @@ ExpatError Exceptions ...@@ -467,8 +467,21 @@ ExpatError Exceptions
.. attribute:: ExpatError.code .. attribute:: ExpatError.code
Expat's internal error number for the specific error. This will match one of Expat's internal error number for the specific error. The
the constants defined in the ``errors`` object from this module. :data:`errors.messages` dictionary maps these error numbers to Expat's error
messages. For example::
from xml.parsers.expat import ParserCreate, ExpatError, errors
p = ParserCreate()
try:
p.Parse(some_xml_document)
except ExpatError as err:
print("Error:", errors.messages[err.code])
The :mod:`errors` module also provides error message constants and a
dictionary :data:`~errors.codes` mapping these messages back to the error
codes, see below.
.. attribute:: ExpatError.lineno .. attribute:: ExpatError.lineno
...@@ -530,15 +543,16 @@ The output from this program is:: ...@@ -530,15 +543,16 @@ The output from this program is::
Content Model Descriptions Content Model Descriptions
-------------------------- --------------------------
.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org> .. module:: xml.parsers.expat.model
.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
Content modules are described using nested tuples. Each tuple contains four Content modules are described using nested tuples. Each tuple contains four
values: the type, the quantifier, the name, and a tuple of children. Children values: the type, the quantifier, the name, and a tuple of children. Children
are simply additional content module descriptions. are simply additional content module descriptions.
The values of the first two fields are constants defined in the ``model`` object The values of the first two fields are constants defined in the
of the :mod:`xml.parsers.expat` module. These constants can be collected in two :mod:`xml.parsers.expat.model` module. These constants can be collected in two
groups: the model type group and the quantifier group. groups: the model type group and the quantifier group.
The constants in the model type group are: The constants in the model type group are:
...@@ -610,143 +624,139 @@ The constants in the quantifier group are: ...@@ -610,143 +624,139 @@ The constants in the quantifier group are:
Expat error constants Expat error constants
--------------------- ---------------------
The following constants are provided in the ``errors`` object of the .. module:: xml.parsers.expat.errors
:mod:`xml.parsers.expat` module. These constants are useful in interpreting
some of the attributes of the :exc:`ExpatError` exception objects raised when an The following constants are provided in the :mod:`xml.parsers.expat.errors`
error has occurred. module. These constants are useful in interpreting some of the attributes of
the :exc:`ExpatError` exception objects raised when an error has occurred.
Since for backwards compatibility reasons, the constants' value is the error
*message* and not the numeric error *code*, you do this by comparing its
:attr:`code` attribute with
:samp:`errors.codes[errors.XML_ERROR_{CONSTANT_NAME}]`.
The ``errors`` module has the following attributes:
.. data:: codes
A dictionary mapping numeric error codes to their string descriptions.
.. versionadded:: 3.2
.. data:: messages
A dictionary mapping string descriptions to their error codes.
The ``errors`` object has the following attributes: .. versionadded:: 3.2
.. data:: XML_ERROR_ASYNC_ENTITY .. data:: XML_ERROR_ASYNC_ENTITY
:noindex:
.. data:: XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF .. data:: XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF
:noindex:
An entity reference in an attribute value referred to an external entity instead An entity reference in an attribute value referred to an external entity instead
of an internal entity. of an internal entity.
.. data:: XML_ERROR_BAD_CHAR_REF .. data:: XML_ERROR_BAD_CHAR_REF
:noindex:
A character reference referred to a character which is illegal in XML (for A character reference referred to a character which is illegal in XML (for
example, character ``0``, or '``&#0;``'). example, character ``0``, or '``&#0;``').
.. data:: XML_ERROR_BINARY_ENTITY_REF .. data:: XML_ERROR_BINARY_ENTITY_REF
:noindex:
An entity reference referred to an entity which was declared with a notation, so An entity reference referred to an entity which was declared with a notation, so
cannot be parsed. cannot be parsed.
.. data:: XML_ERROR_DUPLICATE_ATTRIBUTE .. data:: XML_ERROR_DUPLICATE_ATTRIBUTE
:noindex:
An attribute was used more than once in a start tag. An attribute was used more than once in a start tag.
.. data:: XML_ERROR_INCORRECT_ENCODING .. data:: XML_ERROR_INCORRECT_ENCODING
:noindex:
.. data:: XML_ERROR_INVALID_TOKEN .. data:: XML_ERROR_INVALID_TOKEN
:noindex:
Raised when an input byte could not properly be assigned to a character; for Raised when an input byte could not properly be assigned to a character; for
example, a NUL byte (value ``0``) in a UTF-8 input stream. example, a NUL byte (value ``0``) in a UTF-8 input stream.
.. data:: XML_ERROR_JUNK_AFTER_DOC_ELEMENT .. data:: XML_ERROR_JUNK_AFTER_DOC_ELEMENT
:noindex:
Something other than whitespace occurred after the document element. Something other than whitespace occurred after the document element.
.. data:: XML_ERROR_MISPLACED_XML_PI .. data:: XML_ERROR_MISPLACED_XML_PI
:noindex:
An XML declaration was found somewhere other than the start of the input data. An XML declaration was found somewhere other than the start of the input data.
.. data:: XML_ERROR_NO_ELEMENTS .. data:: XML_ERROR_NO_ELEMENTS
:noindex:
The document contains no elements (XML requires all documents to contain exactly The document contains no elements (XML requires all documents to contain exactly
one top-level element).. one top-level element)..
.. data:: XML_ERROR_NO_MEMORY .. data:: XML_ERROR_NO_MEMORY
:noindex:
Expat was not able to allocate memory internally. Expat was not able to allocate memory internally.
.. data:: XML_ERROR_PARAM_ENTITY_REF .. data:: XML_ERROR_PARAM_ENTITY_REF
:noindex:
A parameter entity reference was found where it was not allowed. A parameter entity reference was found where it was not allowed.
.. data:: XML_ERROR_PARTIAL_CHAR .. data:: XML_ERROR_PARTIAL_CHAR
:noindex:
An incomplete character was found in the input. An incomplete character was found in the input.
.. data:: XML_ERROR_RECURSIVE_ENTITY_REF .. data:: XML_ERROR_RECURSIVE_ENTITY_REF
:noindex:
An entity reference contained another reference to the same entity; possibly via An entity reference contained another reference to the same entity; possibly via
a different name, and possibly indirectly. a different name, and possibly indirectly.
.. data:: XML_ERROR_SYNTAX .. data:: XML_ERROR_SYNTAX
:noindex:
Some unspecified syntax error was encountered. Some unspecified syntax error was encountered.
.. data:: XML_ERROR_TAG_MISMATCH .. data:: XML_ERROR_TAG_MISMATCH
:noindex:
An end tag did not match the innermost open start tag. An end tag did not match the innermost open start tag.
.. data:: XML_ERROR_UNCLOSED_TOKEN .. data:: XML_ERROR_UNCLOSED_TOKEN
:noindex:
Some token (such as a start tag) was not closed before the end of the stream or Some token (such as a start tag) was not closed before the end of the stream or
the next token was encountered. the next token was encountered.
.. data:: XML_ERROR_UNDEFINED_ENTITY .. data:: XML_ERROR_UNDEFINED_ENTITY
:noindex:
A reference was made to a entity which was not defined. A reference was made to a entity which was not defined.
.. data:: XML_ERROR_UNKNOWN_ENCODING .. data:: XML_ERROR_UNKNOWN_ENCODING
:noindex:
The document encoding is not supported by Expat. The document encoding is not supported by Expat.
.. data:: XML_ERROR_UNCLOSED_CDATA_SECTION .. data:: XML_ERROR_UNCLOSED_CDATA_SECTION
:noindex:
A CDATA marked section was not closed. A CDATA marked section was not closed.
.. data:: XML_ERROR_EXTERNAL_ENTITY_HANDLING .. data:: XML_ERROR_EXTERNAL_ENTITY_HANDLING
:noindex:
.. data:: XML_ERROR_NOT_STANDALONE .. data:: XML_ERROR_NOT_STANDALONE
:noindex:
The parser determined that the document was not "standalone" though it declared The parser determined that the document was not "standalone" though it declared
itself to be in the XML declaration, and the :attr:`NotStandaloneHandler` was itself to be in the XML declaration, and the :attr:`NotStandaloneHandler` was
...@@ -754,15 +764,12 @@ The ``errors`` object has the following attributes: ...@@ -754,15 +764,12 @@ The ``errors`` object has the following attributes:
.. data:: XML_ERROR_UNEXPECTED_STATE .. data:: XML_ERROR_UNEXPECTED_STATE
:noindex:
.. data:: XML_ERROR_ENTITY_DECLARED_IN_PE .. data:: XML_ERROR_ENTITY_DECLARED_IN_PE
:noindex:
.. data:: XML_ERROR_FEATURE_REQUIRES_XML_DTD .. data:: XML_ERROR_FEATURE_REQUIRES_XML_DTD
:noindex:
An operation was requested that requires DTD support to be compiled in, but An operation was requested that requires DTD support to be compiled in, but
Expat was configured without DTD support. This should never be reported by a Expat was configured without DTD support. This should never be reported by a
...@@ -770,7 +777,6 @@ The ``errors`` object has the following attributes: ...@@ -770,7 +777,6 @@ The ``errors`` object has the following attributes:
.. data:: XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING .. data:: XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING
:noindex:
A behavioral change was requested after parsing started that can only be changed A behavioral change was requested after parsing started that can only be changed
before parsing has started. This is (currently) only raised by before parsing has started. This is (currently) only raised by
...@@ -778,63 +784,53 @@ The ``errors`` object has the following attributes: ...@@ -778,63 +784,53 @@ The ``errors`` object has the following attributes:
.. data:: XML_ERROR_UNBOUND_PREFIX .. data:: XML_ERROR_UNBOUND_PREFIX
:noindex:
An undeclared prefix was found when namespace processing was enabled. An undeclared prefix was found when namespace processing was enabled.
.. data:: XML_ERROR_UNDECLARING_PREFIX .. data:: XML_ERROR_UNDECLARING_PREFIX
:noindex:
The document attempted to remove the namespace declaration associated with a The document attempted to remove the namespace declaration associated with a
prefix. prefix.
.. data:: XML_ERROR_INCOMPLETE_PE .. data:: XML_ERROR_INCOMPLETE_PE
:noindex:
A parameter entity contained incomplete markup. A parameter entity contained incomplete markup.
.. data:: XML_ERROR_XML_DECL .. data:: XML_ERROR_XML_DECL
:noindex:
The document contained no document element at all. The document contained no document element at all.
.. data:: XML_ERROR_TEXT_DECL .. data:: XML_ERROR_TEXT_DECL
:noindex:
There was an error parsing a text declaration in an external entity. There was an error parsing a text declaration in an external entity.
.. data:: XML_ERROR_PUBLICID .. data:: XML_ERROR_PUBLICID
:noindex:
Characters were found in the public id that are not allowed. Characters were found in the public id that are not allowed.
.. data:: XML_ERROR_SUSPENDED .. data:: XML_ERROR_SUSPENDED
:noindex:
The requested operation was made on a suspended parser, but isn't allowed. This The requested operation was made on a suspended parser, but isn't allowed. This
includes attempts to provide additional input or to stop the parser. includes attempts to provide additional input or to stop the parser.
.. data:: XML_ERROR_NOT_SUSPENDED .. data:: XML_ERROR_NOT_SUSPENDED
:noindex:
An attempt to resume the parser was made when the parser had not been suspended. An attempt to resume the parser was made when the parser had not been suspended.
.. data:: XML_ERROR_ABORTED .. data:: XML_ERROR_ABORTED
:noindex:
This should not be reported to Python applications. This should not be reported to Python applications.
.. data:: XML_ERROR_FINISHED .. data:: XML_ERROR_FINISHED
:noindex:
The requested operation was made on a parser which was finished parsing input, The requested operation was made on a parser which was finished parsing input,
but isn't allowed. This includes attempts to provide additional input or to but isn't allowed. This includes attempts to provide additional input or to
...@@ -842,7 +838,6 @@ The ``errors`` object has the following attributes: ...@@ -842,7 +838,6 @@ The ``errors`` object has the following attributes:
.. data:: XML_ERROR_SUSPEND_PE .. data:: XML_ERROR_SUSPEND_PE
:noindex:
.. rubric:: Footnotes .. rubric:: Footnotes
......
...@@ -63,6 +63,10 @@ Library ...@@ -63,6 +63,10 @@ Library
Extensions Extensions
---------- ----------
- Issue #5355: Provide mappings from Expat error numbers to string
descriptions and backwards, in order to actually make it possible
to analyze error codes provided by ExpatError.
- The Unicode database was updated to 6.0.0. - The Unicode database was updated to 6.0.0.
Tools/Demos Tools/Demos
......
...@@ -1685,8 +1685,12 @@ MODULE_INITFUNC(void) ...@@ -1685,8 +1685,12 @@ MODULE_INITFUNC(void)
PyObject *modelmod_name; PyObject *modelmod_name;
PyObject *model_module; PyObject *model_module;
PyObject *sys_modules; PyObject *sys_modules;
PyObject *tmpnum, *tmpstr;
PyObject *codes_dict;
PyObject *rev_codes_dict;
int res;
static struct PyExpat_CAPI capi; static struct PyExpat_CAPI capi;
PyObject* capi_object; PyObject *capi_object;
if (errmod_name == NULL) if (errmod_name == NULL)
return NULL; return NULL;
...@@ -1789,9 +1793,29 @@ MODULE_INITFUNC(void) ...@@ -1789,9 +1793,29 @@ MODULE_INITFUNC(void)
} }
#endif #endif
codes_dict = PyDict_New();
rev_codes_dict = PyDict_New();
if (codes_dict == NULL || rev_codes_dict == NULL) {
Py_XDECREF(codes_dict);
Py_XDECREF(rev_codes_dict);
return NULL;
}
#define MYCONST(name) \ #define MYCONST(name) \
PyModule_AddStringConstant(errors_module, #name, \ if (PyModule_AddStringConstant(errors_module, #name, \
(char*)XML_ErrorString(name)) (char *)XML_ErrorString(name)) < 0) \
return NULL; \
tmpnum = PyLong_FromLong(name); \
if (tmpnum == NULL) return NULL; \
res = PyDict_SetItemString(codes_dict, \
XML_ErrorString(name), tmpnum); \
if (res < 0) return NULL; \
tmpstr = PyUnicode_FromString(XML_ErrorString(name)); \
if (tmpstr == NULL) return NULL; \
res = PyDict_SetItem(rev_codes_dict, tmpnum, tmpstr); \
Py_DECREF(tmpstr); \
Py_DECREF(tmpnum); \
if (res < 0) return NULL; \
MYCONST(XML_ERROR_NO_MEMORY); MYCONST(XML_ERROR_NO_MEMORY);
MYCONST(XML_ERROR_SYNTAX); MYCONST(XML_ERROR_SYNTAX);
...@@ -1833,8 +1857,15 @@ MODULE_INITFUNC(void) ...@@ -1833,8 +1857,15 @@ MODULE_INITFUNC(void)
MYCONST(XML_ERROR_FINISHED); MYCONST(XML_ERROR_FINISHED);
MYCONST(XML_ERROR_SUSPEND_PE); MYCONST(XML_ERROR_SUSPEND_PE);
PyModule_AddStringConstant(errors_module, "__doc__", if (PyModule_AddStringConstant(errors_module, "__doc__",
"Constants used to describe error conditions."); "Constants used to describe "
"error conditions.") < 0)
return NULL;
if (PyModule_AddObject(errors_module, "codes", codes_dict) < 0)
return NULL;
if (PyModule_AddObject(errors_module, "messages", rev_codes_dict) < 0)
return NULL;
#undef MYCONST #undef MYCONST
......
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