https://github.com/python/cpython/commit/3b57bf84cdff77880c338799a428e6ce29c044db
commit: 3b57bf84cdff77880c338799a428e6ce29c044db
branch: 3.14
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-09-03T00:09:21+03:00
summary:

[3.14] gh-156821: Fix inaccuracies in the xml.parsers.expat documentation 
(GH-156822) (GH-156853)

Corrected, in the documentation and in the docstrings:

* GetInputContext() returns bytes, and its result extends to the end of the
  buffered input;
* Parse() accepts a bytes-like object as well as a string, and ignores the
  encoding declaration for a string;
* ParseFile() only supports binary files;
* XML_ERROR_XML_DECL was described as XML_ERROR_NO_ELEMENTS;
* UnparsedEntityDeclHandler is not restricted to Expat 1.2;
* GetSpecifiedAttributeCount() needs ordered_attributes.

Documented the intern parameter and attribute, namespace_prefixes,
SkippedEntityHandler, XML_CTYPE_MIXED and XML_CTYPE_NAME, and EXPAT_VERSION,
version_info and features.

Removed obsolete notes about Expat 1.2 and 1.95.0, and :noindex: from the
content model constants, which are not documented elsewhere; completed the
list of attribute types in AttlistDeclHandler.
(cherry picked from commit d16a691111503798820a4b3a60ffae7b76c4d85a)

files:
M Doc/library/pyexpat.rst
M Modules/clinic/pyexpat.c.h
M Modules/pyexpat.c

diff --git a/Doc/library/pyexpat.rst b/Doc/library/pyexpat.rst
index de9130bf1560d93..9247660f16a5afd 100644
--- a/Doc/library/pyexpat.rst
+++ b/Doc/library/pyexpat.rst
@@ -37,7 +37,7 @@ the XML document.
 This module uses the :mod:`pyexpat` module to provide access to the Expat
 parser.  Direct use of the :mod:`pyexpat` module is deprecated.
 
-This module provides one exception and one type object:
+This module provides the following exception, type object and data items:
 
 
 .. exception:: ExpatError
@@ -55,6 +55,29 @@ This module provides one exception and one type object:
 
    The type of the return values from the :func:`ParserCreate` function.
 
+
+.. data:: EXPAT_VERSION
+
+   The version string of the Expat library loaded by the interpreter,
+   like ``'expat_2.8.4'``.
+
+
+.. data:: version_info
+
+   The version of the Expat library loaded by the interpreter,
+   as a tuple of three integers: major, minor and micro version.
+
+
+.. data:: features
+
+   The list of the features with which the loaded Expat library
+   was compiled, as ``(name, value)`` pairs.
+   The value is only meaningful for features which have one,
+   like ``'XML_CONTEXT_BYTES'`` or the default protection limits
+   ``'XML_BLAP_ACT_THRES'`` and ``'XML_AT_MAX_AMP'``;
+   for other features, like ``'XML_DTD'`` and ``'XML_NS'``,
+   the value is ``0`` and only the presence of the name is significant.
+
 The :mod:`!xml.parsers.expat` module contains two functions:
 
 
@@ -63,7 +86,7 @@ The :mod:`!xml.parsers.expat` module contains two functions:
    Returns an explanatory string for a given error number *errno*.
 
 
-.. function:: ParserCreate(encoding=None, namespace_separator=None)
+.. function:: ParserCreate(encoding=None, namespace_separator=None, 
intern=None)
 
    Creates and returns a new :class:`xmlparser` object.   *encoding*, if 
specified,
    must be a string naming the encoding  used by the XML data.  Expat doesn't
@@ -110,6 +133,11 @@ The :mod:`!xml.parsers.expat` module contains two 
functions:
       http://www.python.org/ns/ elem1
       elem2
 
+   *intern*, if given, must be a dictionary.
+   It is used to intern the names of elements and attributes,
+   and is available as the :attr:`~xmlparser.intern` attribute.
+   By default a new empty dictionary is created for every parser.
+
    Due to limitations in the ``Expat`` library used by :mod:`pyexpat`,
    the :class:`xmlparser` instance returned can only be used to parse a single
    XML document.  Call ``ParserCreate`` for each document to provide unique
@@ -132,18 +160,24 @@ XMLParser Objects
 
 .. method:: xmlparser.Parse(data[, isfinal])
 
-   Parses the contents of the string *data*, calling the appropriate handler
-   functions to process the parsed data.  *isfinal* must be true on the final 
call
-   to this method; it allows the parsing of a single file in fragments,
+   Parses the contents of *data*,
+   calling the appropriate handler functions to process the parsed data.
+   *data* can be a :term:`bytes-like object` or a string.
+   If it is a string, the encoding declaration in the XML data is ignored,
+   and the data is parsed as already decoded text.
+   *isfinal* must be true on the final call to this method;
+   it allows the parsing of a single file in fragments,
    not the submission of multiple files.
-   *data* can be the empty string at any time.
+   *data* can be empty at any time.
 
 
 .. method:: xmlparser.ParseFile(file)
 
-   Parse XML data reading from the object *file*.  *file* only needs to provide
-   the ``read(nbytes)`` method, returning the empty string when there's no more
-   data.
+   Parse XML data reading from the object *file*.
+   *file* only needs to provide the ``read(nbytes)`` method,
+   which returns bytes, and an empty bytes object when there's no more data.
+   Text files are not supported;
+   use :meth:`Parse` for data which is already decoded.
 
 
 .. method:: xmlparser.SetBase(base)
@@ -163,9 +197,15 @@ XMLParser Objects
 
 .. method:: xmlparser.GetInputContext()
 
-   Returns the input data that generated the current event as a string. The 
data is
-   in the encoding of the entity which contains the text. When called while an
-   event handler is not active, the return value is ``None``.
+   Returns the input data which generated the current event
+   as a :class:`bytes` object.
+   The data is in the encoding of the entity which contains the text.
+   It extends to the end of the currently buffered input,
+   therefore it can contain also the data of the following events,
+   and if the event was generated by a large amount of text,
+   not all of it may be available.
+   When called while an event handler is not active,
+   the return value is ``None``.
 
 
 .. method:: xmlparser.ExternalEntityParserCreate(context[, encoding])
@@ -392,6 +432,22 @@ against some common XML vulnerabilities.
    default, this attribute is false; it may be changed at any time.
 
 
+.. attribute:: xmlparser.intern
+
+   The dictionary used to intern the names of elements and attributes.
+   It is either the dictionary passed as the *intern* argument
+   of :func:`ParserCreate`, or a new dictionary created for this parser.
+
+
+.. attribute:: xmlparser.namespace_prefixes
+
+   If set to a true value, and namespace processing is enabled,
+   the namespace prefix is reported as the third part of the expanded name,
+   separated by the namespace separator.
+   Names which have no prefix are not affected.
+   By default, this attribute is false; it may be changed at any time.
+
+
 The following attributes contain values relating to the most recent error
 encountered by an :class:`xmlparser` object, and will only have correct values
 once a call to :meth:`Parse` or :meth:`ParseFile` has raised an
@@ -455,8 +511,7 @@ otherwise stated.
    encoding of the document text, and an optional "standalone" declaration.
    *version* and *encoding* will be strings, and *standalone* will be ``1`` if 
the
    document is declared standalone, ``0`` if it is declared not to be 
standalone,
-   or ``-1`` if the standalone clause was omitted. This is only available with
-   Expat version 1.95.0 or newer.
+   or ``-1`` if the standalone clause was omitted.
 
 
 .. method:: xmlparser.StartDoctypeDeclHandler(doctypeName, systemId, publicId, 
has_internal_subset)
@@ -465,14 +520,12 @@ otherwise stated.
    ...``).  The *doctypeName* is provided exactly as presented.  The 
*systemId* and
    *publicId* parameters give the system and public identifiers if specified, 
or
    ``None`` if omitted.  *has_internal_subset* will be true if the document
-   contains an internal document declaration subset. This requires Expat 
version
-   1.2 or newer.
+   contains an internal document declaration subset.
 
 
 .. method:: xmlparser.EndDoctypeDeclHandler()
 
-   Called when Expat is done parsing the document type declaration. This 
requires
-   Expat version 1.2 or newer.
+   Called when Expat is done parsing the document type declaration.
 
 
 .. method:: xmlparser.ElementDeclHandler(name, model)
@@ -487,12 +540,16 @@ otherwise stated.
    declaration declares three attributes, this handler is called three times, 
once
    for each attribute.  *elname* is the name of the element to which the
    declaration applies and *attname* is the name of the attribute declared.  
The
-   attribute type is a string passed as *type*; the possible values are
-   ``'CDATA'``, ``'ID'``, ``'IDREF'``, ... *default* gives the default value 
for
+   The attribute type is a string passed as *type*:
+   ``'CDATA'``, ``'ID'``, ``'IDREF'``, ``'IDREFS'``, ``'ENTITY'``,
+   ``'ENTITIES'``, ``'NMTOKEN'`` or ``'NMTOKENS'``,
+   an enumeration like ``'(x|y)'``,
+   or a notation list like ``'NOTATION(n1|n2)'``.
+   *default* gives the default value for
    the attribute used when the attribute is not specified by the document 
instance,
    or ``None`` if there is no default value (``#IMPLIED`` values).  If the
    attribute is required to be given in the document instance, *required* will 
be
-   true. This requires Expat version 1.95.0 or newer.
+   true.
 
 
 .. method:: xmlparser.StartElementHandler(name, attributes)
@@ -528,10 +585,10 @@ otherwise stated.
 
 .. method:: xmlparser.UnparsedEntityDeclHandler(entityName, base, systemId, 
publicId, notationName)
 
-   Called for unparsed (NDATA) entity declarations.  This is only present for
-   version 1.2 of the Expat library; for more recent versions, use
-   :attr:`EntityDeclHandler` instead.  (The underlying function in the Expat
-   library has been declared obsolete.)
+   Called for unparsed (NDATA) entity declarations.
+   If this handler is not set, such declarations are reported by
+   :attr:`EntityDeclHandler`, which is preferred for new code.
+   (The underlying function in the Expat library has been declared obsolete.)
 
 
 .. method:: xmlparser.EntityDeclHandler(entityName, is_parameter_entity, 
value, base, systemId, publicId, notationName)
@@ -542,8 +599,7 @@ otherwise stated.
    ``None`` for parsed entities, and the name of the notation for unparsed
    entities. *is_parameter_entity* will be true if the entity is a parameter 
entity
    or false for general entities (most applications only need to be concerned 
with
-   general entities). This is only available starting with version 1.95.0 of 
the
-   Expat library.
+   general entities).
 
 
 .. method:: xmlparser.NotationDeclHandler(notationName, base, systemId, 
publicId)
@@ -597,7 +653,7 @@ otherwise stated.
 
 .. method:: xmlparser.DefaultHandlerExpand(data)
 
-   This is the same as the :func:`DefaultHandler`,  but doesn't inhibit 
expansion
+   This is the same as the :attr:`DefaultHandler`, but doesn't inhibit 
expansion
    of internal entities. The entity reference will not be passed to the default
    handler.
 
@@ -641,6 +697,16 @@ otherwise stated.
    :attr:`DefaultHandler` callback, if provided.
 
 
+.. method:: xmlparser.SkippedEntityHandler(entityName, is_parameter_entity)
+
+   Called for entity references which are not expanded,
+   because the parser did not read the declaration of the entity.
+   This happens when the external DTD subset or an external parameter entity
+   is not parsed.
+   *is_parameter_entity* is true for a parameter entity
+   and false for a general entity.
+
+
 .. _expaterror-objects:
 
 ExpatError Exceptions
@@ -746,35 +812,35 @@ The constants in the model type group are:
 
 
 .. data:: XML_CTYPE_ANY
-   :noindex:
 
    The element named by the model name was declared to have a content model of
    ``ANY``.
 
 
 .. data:: XML_CTYPE_CHOICE
-   :noindex:
 
    The named element allows a choice from a number of options; this is used for
    content models such as ``(A | B | C)``.
 
 
 .. data:: XML_CTYPE_EMPTY
-   :noindex:
 
    Elements which are declared to be ``EMPTY`` have this model type.
 
 
 .. data:: XML_CTYPE_MIXED
-   :noindex:
+
+   The named element allows character data, optionally interspersed with
+   the named children; this is used for content models such as
+   ``(#PCDATA)`` and ``(#PCDATA | A | B)*``.
 
 
 .. data:: XML_CTYPE_NAME
-   :noindex:
+
+   The model names a single element, as for ``A``.
 
 
 .. data:: XML_CTYPE_SEQ
-   :noindex:
 
    Models which represent a series of models which follow one after the other 
are
    indicated with this model type.  This is used for models such as ``(A, B, 
C)``.
@@ -783,25 +849,21 @@ The constants in the quantifier group are:
 
 
 .. data:: XML_CQUANT_NONE
-   :noindex:
 
    No modifier is given, so it can appear exactly once, as for ``A``.
 
 
 .. data:: XML_CQUANT_OPT
-   :noindex:
 
    The model is optional: it can appear once or not at all, as for ``A?``.
 
 
 .. data:: XML_CQUANT_PLUS
-   :noindex:
 
    The model must occur one or more times (like ``A+``).
 
 
 .. data:: XML_CQUANT_REP
-   :noindex:
 
    The model must occur zero or more times, as for ``A*``.
 
@@ -885,7 +947,7 @@ The ``errors`` module has the following attributes:
 .. data:: XML_ERROR_NO_ELEMENTS
 
    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
@@ -988,7 +1050,7 @@ The ``errors`` module has the following attributes:
 
 .. data:: XML_ERROR_XML_DECL
 
-   The document contained no document element at all.
+   There was an error parsing the XML declaration.
 
 
 .. data:: XML_ERROR_TEXT_DECL
diff --git a/Modules/clinic/pyexpat.c.h b/Modules/clinic/pyexpat.c.h
index aebca46c91f493b..820864ddeabbcc8 100644
--- a/Modules/clinic/pyexpat.c.h
+++ b/Modules/clinic/pyexpat.c.h
@@ -62,6 +62,8 @@ PyDoc_STRVAR(pyexpat_xmlparser_Parse__doc__,
 "\n"
 "Parse XML data.\n"
 "\n"
+"\'data\' can be a bytes-like object or a string.  If it is a string,\n"
+"the encoding declaration in the XML data is ignored.\n"
 "\'isfinal\' should be true at end of input.");
 
 #define PYEXPAT_XMLPARSER_PARSE_METHODDEF    \
@@ -116,7 +118,9 @@ PyDoc_STRVAR(pyexpat_xmlparser_ParseFile__doc__,
 "ParseFile($self, file, /)\n"
 "--\n"
 "\n"
-"Parse XML data from file-like object.");
+"Parse XML data from a binary file-like object.\n"
+"\n"
+"Its read() method should return bytes.");
 
 #define PYEXPAT_XMLPARSER_PARSEFILE_METHODDEF    \
     {"ParseFile", _PyCFunction_CAST(pyexpat_xmlparser_ParseFile), 
METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pyexpat_xmlparser_ParseFile__doc__},
@@ -216,11 +220,13 @@ PyDoc_STRVAR(pyexpat_xmlparser_GetInputContext__doc__,
 "GetInputContext($self, /)\n"
 "--\n"
 "\n"
-"Return the untranslated text of the input that caused the current event.\n"
+"Return the input which generated the current event as bytes.\n"
 "\n"
-"If the event was generated by a large amount of text (such as\n"
-"a start tag for an element with many attributes), not all of the\n"
-"text may be available.");
+"The data is in the encoding of the entity which contains the text.\n"
+"It extends to the end of the currently buffered input, therefore it\n"
+"can contain also the data of the following events, and if the event\n"
+"was generated by a large amount of text, not all of it may be\n"
+"available.");
 
 #define PYEXPAT_XMLPARSER_GETINPUTCONTEXT_METHODDEF    \
     {"GetInputContext", (PyCFunction)pyexpat_xmlparser_GetInputContext, 
METH_NOARGS, pyexpat_xmlparser_GetInputContext__doc__},
@@ -833,4 +839,4 @@ pyexpat_ErrorString(PyObject *module, PyObject *arg)
 #ifndef PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF
     #define PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF
 #endif /* 
!defined(PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF) */
-/*[clinic end generated code: output=b03765d16720ab5e input=a9049054013a1b77]*/
+/*[clinic end generated code: output=e505201898471561 input=a9049054013a1b77]*/
diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
index f9fd7a7a5b2f01f..6eab2b0163aa77a 100644
--- a/Modules/pyexpat.c
+++ b/Modules/pyexpat.c
@@ -844,13 +844,15 @@ pyexpat.xmlparser.Parse
 
 Parse XML data.
 
+'data' can be a bytes-like object or a string.  If it is a string,
+the encoding declaration in the XML data is ignored.
 'isfinal' should be true at end of input.
 [clinic start generated code]*/
 
 static PyObject *
 pyexpat_xmlparser_Parse_impl(xmlparseobject *self, PyTypeObject *cls,
                              PyObject *data, int isfinal)
-/*[clinic end generated code: output=8faffe07fe1f862a input=053e0f047e55c05a]*/
+/*[clinic end generated code: output=8faffe07fe1f862a input=f8f3ba4eadf837e5]*/
 {
     const char *s;
     Py_ssize_t slen;
@@ -943,13 +945,15 @@ pyexpat.xmlparser.ParseFile
     file: object
     /
 
-Parse XML data from file-like object.
+Parse XML data from a binary file-like object.
+
+Its read() method should return bytes.
 [clinic start generated code]*/
 
 static PyObject *
 pyexpat_xmlparser_ParseFile_impl(xmlparseobject *self, PyTypeObject *cls,
                                  PyObject *file)
-/*[clinic end generated code: output=34780a094c8ca3ae input=ba4bc9c541684793]*/
+/*[clinic end generated code: output=34780a094c8ca3ae input=c96030cf5e4f577e]*/
 {
     int rv = 1;
     PyObject *readmethod = NULL;
@@ -1025,16 +1029,18 @@ pyexpat_xmlparser_GetBase_impl(xmlparseobject *self)
 /*[clinic input]
 pyexpat.xmlparser.GetInputContext
 
-Return the untranslated text of the input that caused the current event.
+Return the input which generated the current event as bytes.
 
-If the event was generated by a large amount of text (such as
-a start tag for an element with many attributes), not all of the
-text may be available.
+The data is in the encoding of the entity which contains the text.
+It extends to the end of the currently buffered input, therefore it
+can contain also the data of the following events, and if the event
+was generated by a large amount of text, not all of it may be
+available.
 [clinic start generated code]*/
 
 static PyObject *
 pyexpat_xmlparser_GetInputContext_impl(xmlparseobject *self)
-/*[clinic end generated code: output=a88026d683fc22cc input=3ff7cb00783c8f98]*/
+/*[clinic end generated code: output=a88026d683fc22cc input=2d605aaa9edbb415]*/
 {
     if (self->in_callback) {
         int offset, size;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to