[Python-checkins] bpo-29209: Remove old-deprecated features in ElementTree. (GH-6769)

Serhiy Storchaka webhook-mailer at python.org
Tue Jul 24 05:03:41 EDT 2018


https://github.com/python/cpython/commit/02ec92fa7b1dddc23d479ee0b87dc283793505a8
commit: 02ec92fa7b1dddc23d479ee0b87dc283793505a8
branch: master
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2018-07-24T12:03:34+03:00
summary:

bpo-29209: Remove old-deprecated features in ElementTree. (GH-6769)

Also make getchildren() and getiterator() emitting
a DeprecationWarning instead of PendingDeprecationWarning.

files:
A Misc/NEWS.d/next/Library/2018-05-12-13-06-41.bpo-29209.h5RxYy.rst
M Doc/library/xml.etree.elementtree.rst
M Doc/whatsnew/3.8.rst
M Lib/test/test_xml_etree.py
M Lib/xml/etree/ElementTree.py
M Modules/_elementtree.c
M Modules/clinic/_elementtree.c.h

diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst
index 6298f1396ae2..0cb949a9f481 100644
--- a/Doc/library/xml.etree.elementtree.rst
+++ b/Doc/library/xml.etree.elementtree.rst
@@ -772,13 +772,13 @@ Element Objects
 
    .. method:: getchildren()
 
-      .. deprecated:: 3.2
+      .. deprecated-removed:: 3.2 3.9
          Use ``list(elem)`` or iteration.
 
 
    .. method:: getiterator(tag=None)
 
-      .. deprecated:: 3.2
+      .. deprecated-removed:: 3.2 3.9
          Use method :meth:`Element.iter` instead.
 
 
@@ -888,7 +888,7 @@ ElementTree Objects
 
    .. method:: getiterator(tag=None)
 
-      .. deprecated:: 3.2
+      .. deprecated-removed:: 3.2 3.9
          Use method :meth:`ElementTree.iter` instead.
 
 
@@ -1050,20 +1050,20 @@ XMLParser Objects
 ^^^^^^^^^^^^^^^^^
 
 
-.. class:: XMLParser(html=0, target=None, encoding=None)
+.. class:: XMLParser(*, target=None, encoding=None)
 
    This class is the low-level building block of the module.  It uses
    :mod:`xml.parsers.expat` for efficient, event-based parsing of XML.  It can
    be fed XML data incrementally with the :meth:`feed` method, and parsing
    events are translated to a push API - by invoking callbacks on the *target*
    object.  If *target* is omitted, the standard :class:`TreeBuilder` is used.
-   The *html* argument was historically used for backwards compatibility and is
-   now deprecated.  If *encoding* [1]_ is given, the value overrides the
+   If *encoding* [1]_ is given, the value overrides the
    encoding specified in the XML file.
 
-   .. deprecated:: 3.4
-      The *html* argument.  The remaining arguments should be passed via
-      keyword to prepare for the removal of the *html* argument.
+   .. versionchanged:: 3.8
+      Parameters are now :ref:`keyword-only <keyword-only_parameter>`.
+      The *html* argument no longer supported.
+
 
    .. method:: close()
 
@@ -1072,13 +1072,6 @@ XMLParser Objects
       this is the toplevel document element.
 
 
-   .. method:: doctype(name, pubid, system)
-
-      .. deprecated:: 3.2
-         Define the :meth:`TreeBuilder.doctype` method on a custom TreeBuilder
-         target.
-
-
    .. method:: feed(data)
 
       Feeds data to the parser.  *data* is encoded data.
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index c6ecebc746fe..3f515357e953 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -158,6 +158,11 @@ Build and C API Changes
 Deprecated
 ==========
 
+* Deprecated methods ``getchildren()`` and ``getiterator()`` in
+  the :mod:`~xml.etree.ElementTree` module emit now a
+  :exc:`DeprecationWarning` instead of :exc:`PendingDeprecationWarning`.
+  They will be removed in Python 3.9.
+  (Contributed by Serhiy Storchaka in :issue:`29209`.)
 
 
 Removed
@@ -173,6 +178,14 @@ Removed
 * ``filemode`` function is removed from :mod:`tarfile` module.
   It is not documented and deprecated since Python 3.3.
 
+* The :class:`~xml.etree.ElementTree.XMLParser` constructor no longer accepts
+  the *html* argument.  It never had effect and was deprecated in Python 3.4.
+  All other parameters are now :ref:`keyword-only <keyword-only_parameter>`.
+  (Contributed by Serhiy Storchaka in :issue:`29209`.)
+
+* Removed the ``doctype()`` method of :class:`~xml.etree.ElementTree.XMLParser`.
+  (Contributed by Serhiy Storchaka in :issue:`29209`.)
+
 
 Porting to Python 3.8
 =====================
@@ -204,6 +217,13 @@ Changes in the Python API
   a database if it does not exist.
   (Contributed by Serhiy Storchaka in :issue:`32749`.)
 
+* The ``doctype()`` method defined in a subclass of
+  :class:`~xml.etree.ElementTree.XMLParser` will no longer be called and will
+  cause emitting a :exc:`RuntimeWarning` instead of a :exc:`DeprecationWarning`.
+  Define the :meth:`doctype() <xml.etree.ElementTree.TreeBuilder.doctype>`
+  method on a target for handling an XML doctype declaration.
+  (Contributed by Serhiy Storchaka in :issue:`29209`.)
+
 * A :exc:`RuntimeError` is now raised when the custom metaclass doesn't
   provide the ``__classcell__`` entry in the namespace passed to
   ``type.__new__``.  A :exc:`DeprecationWarning` was emitted in Python
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index e11397585d97..a52529051bf0 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -706,7 +706,7 @@ def comment(self, data):
     # Element.getchildren() and ElementTree.getiterator() are deprecated.
     @checkwarnings(("This method will be removed in future versions.  "
                     "Use .+ instead.",
-                    (DeprecationWarning, PendingDeprecationWarning)))
+                    DeprecationWarning))
     def test_getchildren(self):
         # Test Element.getchildren()
 
@@ -2399,7 +2399,7 @@ def test_iter_by_tag(self):
 
     # Element.getiterator() is deprecated.
     @checkwarnings(("This method will be removed in future versions.  "
-                    "Use .+ instead.", PendingDeprecationWarning))
+                    "Use .+ instead.", DeprecationWarning))
     def test_getiterator(self):
         doc = ET.XML('''
             <document>
@@ -2605,14 +2605,6 @@ def _check_sample_element(self, e):
         self.assertEqual(e[0].text, '22')
 
     def test_constructor_args(self):
-        # Positional args. The first (html) is not supported, but should be
-        # nevertheless correctly accepted.
-        with self.assertWarnsRegex(DeprecationWarning, r'\bhtml\b'):
-            parser = ET.XMLParser(None, ET.TreeBuilder(), 'utf-8')
-        parser.feed(self.sample1)
-        self._check_sample_element(parser.close())
-
-        # Now as keyword args.
         parser2 = ET.XMLParser(encoding='utf-8',
                                target=ET.TreeBuilder())
         parser2.feed(self.sample1)
@@ -2626,13 +2618,6 @@ class MyParser(ET.XMLParser):
         self._check_sample_element(parser.close())
 
     def test_doctype_warning(self):
-        parser = ET.XMLParser()
-        with self.assertWarns(DeprecationWarning):
-            parser.doctype('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
-                'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')
-        parser.feed('<html/>')
-        parser.close()
-
         with warnings.catch_warnings():
             warnings.simplefilter('error', DeprecationWarning)
             parser = ET.XMLParser()
@@ -2642,21 +2627,20 @@ def test_doctype_warning(self):
     def test_subclass_doctype(self):
         _doctype = None
         class MyParserWithDoctype(ET.XMLParser):
-            def doctype(self, name, pubid, system):
+            def doctype(self, *args, **kwargs):
                 nonlocal _doctype
-                _doctype = (name, pubid, system)
+                _doctype = (args, kwargs)
 
         parser = MyParserWithDoctype()
-        with self.assertWarns(DeprecationWarning):
+        with self.assertWarnsRegex(RuntimeWarning, 'doctype'):
             parser.feed(self.sample2)
         parser.close()
-        self.assertEqual(_doctype,
-            ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
-             'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
+        self.assertIsNone(_doctype)
 
         _doctype = _doctype2 = None
         with warnings.catch_warnings():
             warnings.simplefilter('error', DeprecationWarning)
+            warnings.simplefilter('error', RuntimeWarning)
             class DoctypeParser:
                 def doctype(self, name, pubid, system):
                     nonlocal _doctype2
@@ -2674,6 +2658,7 @@ def test_inherited_doctype(self):
         '''Ensure that ordinary usage is not deprecated (Issue 19176)'''
         with warnings.catch_warnings():
             warnings.simplefilter('error', DeprecationWarning)
+            warnings.simplefilter('error', RuntimeWarning)
             class MyParserWithoutDoctype(ET.XMLParser):
                 pass
             parser = MyParserWithoutDoctype()
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
index 87277045b525..371b37147e32 100644
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -412,11 +412,10 @@ def iter(self, tag=None):
 
     # compatibility
     def getiterator(self, tag=None):
-        # Change for a DeprecationWarning in 1.4
         warnings.warn(
             "This method will be removed in future versions.  "
             "Use 'elem.iter()' or 'list(elem.iter())' instead.",
-            PendingDeprecationWarning, stacklevel=2
+            DeprecationWarning, stacklevel=2
         )
         return list(self.iter(tag))
 
@@ -622,11 +621,10 @@ def iter(self, tag=None):
 
     # compatibility
     def getiterator(self, tag=None):
-        # Change for a DeprecationWarning in 1.4
         warnings.warn(
             "This method will be removed in future versions.  "
             "Use 'tree.iter()' or 'list(tree.iter())' instead.",
-            PendingDeprecationWarning, stacklevel=2
+            DeprecationWarning, stacklevel=2
         )
         return list(self.iter(tag))
 
@@ -1431,13 +1429,11 @@ def end(self, tag):
         self._tail = 1
         return self._last
 
-_sentinel = ['sentinel']
 
 # also see ElementTree and TreeBuilder
 class XMLParser:
     """Element structure builder for XML source data based on the expat parser.
 
-    *html* are predefined HTML entities (deprecated and not supported),
     *target* is an optional target object which defaults to an instance of the
     standard TreeBuilder class, *encoding* is an optional encoding string
     which if given, overrides the encoding specified in the XML file:
@@ -1445,11 +1441,7 @@ class XMLParser:
 
     """
 
-    def __init__(self, html=_sentinel, target=None, encoding=None):
-        if html is not _sentinel:
-            warnings.warn(
-                "The html argument of XMLParser() is deprecated",
-                DeprecationWarning, stacklevel=2)
+    def __init__(self, *, target=None, encoding=None):
         try:
             from xml.parsers import expat
         except ImportError:
@@ -1602,27 +1594,13 @@ def _default(self, text):
                     return
                 if hasattr(self.target, "doctype"):
                     self.target.doctype(name, pubid, system[1:-1])
-                elif self.doctype != self._XMLParser__doctype:
-                    # warn about deprecated call
-                    self._XMLParser__doctype(name, pubid, system[1:-1])
-                    self.doctype(name, pubid, system[1:-1])
-                self._doctype = None
-
-    def doctype(self, name, pubid, system):
-        """(Deprecated)  Handle doctype declaration
-
-        *name* is the Doctype name, *pubid* is the public identifier,
-        and *system* is the system identifier.
+                elif hasattr(self, "doctype"):
+                    warnings.warn(
+                        "The doctype() method of XMLParser is ignored.  "
+                        "Define doctype() method on the TreeBuilder target.",
+                        RuntimeWarning)
 
-        """
-        warnings.warn(
-            "This method of XMLParser is deprecated.  Define doctype() "
-            "method on the TreeBuilder target.",
-            DeprecationWarning,
-            )
-
-    # sentinel, if doctype is redefined in a subclass
-    __doctype = doctype
+                self._doctype = None
 
     def feed(self, data):
         """Feed encoded data to parser."""
diff --git a/Misc/NEWS.d/next/Library/2018-05-12-13-06-41.bpo-29209.h5RxYy.rst b/Misc/NEWS.d/next/Library/2018-05-12-13-06-41.bpo-29209.h5RxYy.rst
new file mode 100644
index 000000000000..78d9b0c55daa
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-05-12-13-06-41.bpo-29209.h5RxYy.rst
@@ -0,0 +1,6 @@
+Removed the ``doctype()`` method and the *html* parameter of the constructor
+of :class:`~xml.etree.ElementTree.XMLParser`.  The ``doctype()`` method
+defined in a subclass will no longer be called.  Deprecated methods
+``getchildren()`` and ``getiterator()`` in the :mod:`~xml.etree.ElementTree`
+module emit now a :exc:`DeprecationWarning` instead of
+:exc:`PendingDeprecationWarning`.
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index 1dfdb3ce34f3..1500a6de270d 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -1429,8 +1429,7 @@ static PyObject *
 _elementtree_Element_getiterator_impl(ElementObject *self, PyObject *tag)
 /*[clinic end generated code: output=cb69ff4a3742dfa1 input=500da1a03f7b9e28]*/
 {
-    /* Change for a DeprecationWarning in 1.4 */
-    if (PyErr_WarnEx(PyExc_PendingDeprecationWarning,
+    if (PyErr_WarnEx(PyExc_DeprecationWarning,
                      "This method will be removed in future versions.  "
                      "Use 'tree.iter()' or 'list(tree.iter())' instead.",
                      1) < 0) {
@@ -2770,12 +2769,6 @@ typedef struct {
 
 } XMLParserObject;
 
-static PyObject*
-_elementtree_XMLParser_doctype(XMLParserObject *self, PyObject *const *args, Py_ssize_t nargs);
-static PyObject *
-_elementtree_XMLParser_doctype_impl(XMLParserObject *self, PyObject *name,
-                                    PyObject *pubid, PyObject *system);
-
 /* helpers */
 
 LOCAL(PyObject*)
@@ -3139,10 +3132,9 @@ expat_start_doctype_handler(XMLParserObject *self,
                             const XML_Char *pubid,
                             int has_internal_subset)
 {
-    PyObject *self_pyobj = (PyObject *)self;
+    _Py_IDENTIFIER(doctype);
     PyObject *doctype_name_obj, *sysid_obj, *pubid_obj;
-    PyObject *parser_doctype = NULL;
-    PyObject *res = NULL;
+    PyObject *res;
 
     if (PyErr_Occurred())
         return;
@@ -3179,33 +3171,15 @@ expat_start_doctype_handler(XMLParserObject *self,
         res = PyObject_CallFunctionObjArgs(self->handle_doctype,
                                            doctype_name_obj, pubid_obj,
                                            sysid_obj, NULL);
-        Py_CLEAR(res);
+        Py_XDECREF(res);
     }
-    else {
-        /* Now see if the parser itself has a doctype method. If yes and it's
-         * a custom method, call it but warn about deprecation. If it's only
-         * the vanilla XMLParser method, do nothing.
-         */
-        parser_doctype = PyObject_GetAttrString(self_pyobj, "doctype");
-        if (parser_doctype &&
-            !(PyCFunction_Check(parser_doctype) &&
-              PyCFunction_GET_SELF(parser_doctype) == self_pyobj &&
-              PyCFunction_GET_FUNCTION(parser_doctype) ==
-                    (PyCFunction) _elementtree_XMLParser_doctype)) {
-            res = _elementtree_XMLParser_doctype_impl(self, doctype_name_obj,
-                                                      pubid_obj, sysid_obj);
-            if (!res)
-                goto clear;
-            Py_DECREF(res);
-            res = PyObject_CallFunctionObjArgs(parser_doctype,
-                                               doctype_name_obj, pubid_obj,
-                                               sysid_obj, NULL);
-            Py_CLEAR(res);
-        }
+    else if (_PyObject_LookupAttrId((PyObject *)self, &PyId_doctype, &res) > 0) {
+        (void)PyErr_WarnEx(PyExc_RuntimeWarning,
+                "The doctype() method of XMLParser is ignored.  "
+                "Define doctype() method on the TreeBuilder target.",
+                1);
     }
 
-clear:
-    Py_XDECREF(parser_doctype);
     Py_DECREF(doctype_name_obj);
     Py_DECREF(pubid_obj);
     Py_DECREF(sysid_obj);
@@ -3269,25 +3243,17 @@ ignore_attribute_error(PyObject *value)
 /*[clinic input]
 _elementtree.XMLParser.__init__
 
-    html: object = NULL
+    *
     target: object = NULL
     encoding: str(accept={str, NoneType}) = NULL
 
 [clinic start generated code]*/
 
 static int
-_elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *html,
-                                     PyObject *target, const char *encoding)
-/*[clinic end generated code: output=d6a16c63dda54441 input=155bc5695baafffd]*/
-{
-    if (html != NULL) {
-        if (PyErr_WarnEx(PyExc_DeprecationWarning,
-                         "The html argument of XMLParser() is deprecated",
-                         1) < 0) {
-            return -1;
-        }
-    }
-
+_elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target,
+                                     const char *encoding)
+/*[clinic end generated code: output=3ae45ec6cdf344e4 input=96288fcba916cfce]*/
+{
     self->entity = PyDict_New();
     if (!self->entity)
         return -1;
@@ -3615,30 +3581,6 @@ _elementtree_XMLParser__parse_whole(XMLParserObject *self, PyObject *file)
     return res;
 }
 
-/*[clinic input]
-_elementtree.XMLParser.doctype
-
-    name: object
-    pubid: object
-    system: object
-    /
-
-[clinic start generated code]*/
-
-static PyObject *
-_elementtree_XMLParser_doctype_impl(XMLParserObject *self, PyObject *name,
-                                    PyObject *pubid, PyObject *system)
-/*[clinic end generated code: output=10fb50c2afded88d input=84050276cca045e1]*/
-{
-    if (PyErr_WarnEx(PyExc_DeprecationWarning,
-                     "This method of XMLParser is deprecated.  Define"
-                     " doctype() method on the TreeBuilder target.",
-                     1) < 0) {
-        return NULL;
-    }
-    Py_RETURN_NONE;
-}
-
 /*[clinic input]
 _elementtree.XMLParser._setevents
 
@@ -3923,7 +3865,6 @@ static PyMethodDef xmlparser_methods[] = {
     _ELEMENTTREE_XMLPARSER_CLOSE_METHODDEF
     _ELEMENTTREE_XMLPARSER__PARSE_WHOLE_METHODDEF
     _ELEMENTTREE_XMLPARSER__SETEVENTS_METHODDEF
-    _ELEMENTTREE_XMLPARSER_DOCTYPE_METHODDEF
     {NULL, NULL}
 };
 
diff --git a/Modules/clinic/_elementtree.c.h b/Modules/clinic/_elementtree.c.h
index 6b558876dd0b..78b9be89a3e6 100644
--- a/Modules/clinic/_elementtree.c.h
+++ b/Modules/clinic/_elementtree.c.h
@@ -632,24 +632,23 @@ _elementtree_TreeBuilder_start(TreeBuilderObject *self, PyObject *const *args, P
 }
 
 static int
-_elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *html,
-                                     PyObject *target, const char *encoding);
+_elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target,
+                                     const char *encoding);
 
 static int
 _elementtree_XMLParser___init__(PyObject *self, PyObject *args, PyObject *kwargs)
 {
     int return_value = -1;
-    static const char * const _keywords[] = {"html", "target", "encoding", NULL};
-    static _PyArg_Parser _parser = {"|OOz:XMLParser", _keywords, 0};
-    PyObject *html = NULL;
+    static const char * const _keywords[] = {"target", "encoding", NULL};
+    static _PyArg_Parser _parser = {"|$Oz:XMLParser", _keywords, 0};
     PyObject *target = NULL;
     const char *encoding = NULL;
 
     if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
-        &html, &target, &encoding)) {
+        &target, &encoding)) {
         goto exit;
     }
-    return_value = _elementtree_XMLParser___init___impl((XMLParserObject *)self, html, target, encoding);
+    return_value = _elementtree_XMLParser___init___impl((XMLParserObject *)self, target, encoding);
 
 exit:
     return return_value;
@@ -688,37 +687,6 @@ PyDoc_STRVAR(_elementtree_XMLParser__parse_whole__doc__,
 #define _ELEMENTTREE_XMLPARSER__PARSE_WHOLE_METHODDEF    \
     {"_parse_whole", (PyCFunction)_elementtree_XMLParser__parse_whole, METH_O, _elementtree_XMLParser__parse_whole__doc__},
 
-PyDoc_STRVAR(_elementtree_XMLParser_doctype__doc__,
-"doctype($self, name, pubid, system, /)\n"
-"--\n"
-"\n");
-
-#define _ELEMENTTREE_XMLPARSER_DOCTYPE_METHODDEF    \
-    {"doctype", (PyCFunction)_elementtree_XMLParser_doctype, METH_FASTCALL, _elementtree_XMLParser_doctype__doc__},
-
-static PyObject *
-_elementtree_XMLParser_doctype_impl(XMLParserObject *self, PyObject *name,
-                                    PyObject *pubid, PyObject *system);
-
-static PyObject *
-_elementtree_XMLParser_doctype(XMLParserObject *self, PyObject *const *args, Py_ssize_t nargs)
-{
-    PyObject *return_value = NULL;
-    PyObject *name;
-    PyObject *pubid;
-    PyObject *system;
-
-    if (!_PyArg_UnpackStack(args, nargs, "doctype",
-        3, 3,
-        &name, &pubid, &system)) {
-        goto exit;
-    }
-    return_value = _elementtree_XMLParser_doctype_impl(self, name, pubid, system);
-
-exit:
-    return return_value;
-}
-
 PyDoc_STRVAR(_elementtree_XMLParser__setevents__doc__,
 "_setevents($self, events_queue, events_to_report=None, /)\n"
 "--\n"
@@ -749,4 +717,4 @@ _elementtree_XMLParser__setevents(XMLParserObject *self, PyObject *const *args,
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=c5a85a88bbb5cc06 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=1bff22415aabb78b input=a9049054013a1b77]*/



More information about the Python-checkins mailing list