bpo-29204: Emit warnings for already deprecated ElementTree features. (#773)

Element.getiterator() and the html parameter of XMLParser() were
deprecated only in the documentation (since Python 3.2 and 3.4 correspondintly).
Now using them emits a deprecation warning.

* Don’t need check_warnings any more.
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index dbdad23..952a4fd 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -6,6 +6,7 @@
 # monkey-patched when running the "test_xml_etree_c" test suite.
 
 import copy
+import functools
 import html
 import io
 import operator
@@ -90,6 +91,16 @@
 """
 
 
+def checkwarnings(*filters, quiet=False):
+    def decorator(test):
+        def newtest(*args, **kwargs):
+            with support.check_warnings(*filters, quiet=quiet):
+                test(*args, **kwargs)
+        functools.update_wrapper(newtest, test)
+        return newtest
+    return decorator
+
+
 class ModuleTest(unittest.TestCase):
     def test_sanity(self):
         # Import sanity.
@@ -690,6 +701,10 @@
             ])
 
 
+    # Element.getchildren() and ElementTree.getiterator() are deprecated.
+    @checkwarnings(("This method will be removed in future versions.  "
+                    "Use .+ instead.",
+                    (DeprecationWarning, PendingDeprecationWarning)))
     def test_getchildren(self):
         # Test Element.getchildren()
 
@@ -1558,7 +1573,7 @@
         class EchoTarget:
             def close(self):
                 return ET.Element("element") # simulate root
-        parser = ET.XMLParser(EchoTarget())
+        parser = ET.XMLParser(target=EchoTarget())
         parser.feed("<element>some text</element>")
         self.assertEqual(parser.close().tag, 'element')
 
@@ -2225,8 +2240,12 @@
         self.assertEqual(summarize_list(ET.ElementTree(e).findall('tag')),
             ['tag'] * 2)
         # this produces a warning
-        self.assertEqual(summarize_list(ET.ElementTree(e).findall('//tag')),
-            ['tag'] * 3)
+        msg = ("This search is broken in 1.3 and earlier, and will be fixed "
+               "in a future version.  If you rely on the current behaviour, "
+               "change it to '.+'")
+        with self.assertWarnsRegex(FutureWarning, msg):
+            it = ET.ElementTree(e).findall('//tag')
+        self.assertEqual(summarize_list(it), ['tag'] * 3)
 
 
 class ElementIterTest(unittest.TestCase):
@@ -2311,6 +2330,9 @@
         self.assertEqual(self._ilist(doc), all_tags)
         self.assertEqual(self._ilist(doc, '*'), all_tags)
 
+    # Element.getiterator() is deprecated.
+    @checkwarnings(("This method will be removed in future versions.  "
+                    "Use .+ instead.", PendingDeprecationWarning))
     def test_getiterator(self):
         doc = ET.XML('''
             <document>
@@ -2493,13 +2515,13 @@
     def test_constructor_args(self):
         # Positional args. The first (html) is not supported, but should be
         # nevertheless correctly accepted.
-        parser = ET.XMLParser(None, ET.TreeBuilder(), 'utf-8')
+        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',
-                               html=[{}],
                                target=ET.TreeBuilder())
         parser2.feed(self.sample1)
         self._check_sample_element(parser2.close())
@@ -3016,46 +3038,6 @@
 # --------------------------------------------------------------------
 
 
-class CleanContext(object):
-    """Provide default namespace mapping and path cache."""
-    checkwarnings = None
-
-    def __init__(self, quiet=False):
-        if sys.flags.optimize >= 2:
-            # under -OO, doctests cannot be run and therefore not all warnings
-            # will be emitted
-            quiet = True
-        deprecations = (
-            # Search behaviour is broken if search path starts with "/".
-            ("This search is broken in 1.3 and earlier, and will be fixed "
-             "in a future version.  If you rely on the current behaviour, "
-             "change it to '.+'", FutureWarning),
-            # Element.getchildren() and Element.getiterator() are deprecated.
-            ("This method will be removed in future versions.  "
-             "Use .+ instead.", DeprecationWarning),
-            ("This method will be removed in future versions.  "
-             "Use .+ instead.", PendingDeprecationWarning))
-        self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet)
-
-    def __enter__(self):
-        from xml.etree import ElementPath
-        self._nsmap = ET.register_namespace._namespace_map
-        # Copy the default namespace mapping
-        self._nsmap_copy = self._nsmap.copy()
-        # Copy the path cache (should be empty)
-        self._path_cache = ElementPath._cache
-        ElementPath._cache = self._path_cache.copy()
-        self.checkwarnings.__enter__()
-
-    def __exit__(self, *args):
-        from xml.etree import ElementPath
-        # Restore mapping and path cache
-        self._nsmap.clear()
-        self._nsmap.update(self._nsmap_copy)
-        ElementPath._cache = self._path_cache
-        self.checkwarnings.__exit__(*args)
-
-
 def test_main(module=None):
     # When invoked without a module, runs the Python ET tests by loading pyET.
     # Otherwise, uses the given module as the ET.
@@ -3095,11 +3077,22 @@
             NoAcceleratorTest,
             ])
 
+    # Provide default namespace mapping and path cache.
+    from xml.etree import ElementPath
+    nsmap = ET.register_namespace._namespace_map
+    # Copy the default namespace mapping
+    nsmap_copy = nsmap.copy()
+    # Copy the path cache (should be empty)
+    path_cache = ElementPath._cache
+    ElementPath._cache = path_cache.copy()
     try:
-        # XXX the C module should give the same warnings as the Python module
-        with CleanContext(quiet=(pyET is not ET)):
-            support.run_unittest(*test_classes)
+        support.run_unittest(*test_classes)
     finally:
+        from xml.etree import ElementPath
+        # Restore mapping and path cache
+        nsmap.clear()
+        nsmap.update(nsmap_copy)
+        ElementPath._cache = path_cache
         # don't interfere with subsequent tests
         ET = pyET = None
 
diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py
index 7c60699..171a3f8 100644
--- a/Lib/test/test_xml_etree_c.py
+++ b/Lib/test/test_xml_etree_c.py
@@ -8,7 +8,8 @@
 cET = import_fresh_module('xml.etree.ElementTree',
                           fresh=['_elementtree'])
 cET_alias = import_fresh_module('xml.etree.cElementTree',
-                                fresh=['_elementtree', 'xml.etree'])
+                                fresh=['_elementtree', 'xml.etree'],
+                                deprecated=True)
 
 
 @unittest.skipUnless(cET, 'requires _elementtree')
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
index 7354056..7944cf1 100644
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -1430,6 +1430,7 @@
         self._tail = 1
         return self._last
 
+_sentinel = ['sentinel']
 
 # also see ElementTree and TreeBuilder
 class XMLParser:
@@ -1443,7 +1444,11 @@
 
     """
 
-    def __init__(self, html=0, target=None, encoding=None):
+    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)
         try:
             from xml.parsers import expat
         except ImportError:
diff --git a/Misc/NEWS b/Misc/NEWS
index 5fff581..87b4782 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -298,6 +298,10 @@
 Library
 -------
 
+- bpo-29204: Element.getiterator() and the html parameter of XMLParser() were
+  deprecated only in the documentation (since Python 3.2 and 3.4 correspondintly).
+  Now using them emits a deprecation warning.
+
 - bpo-27863: Fixed multiple crashes in ElementTree caused by race conditions
   and wrong types. 
 
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index 36aa391..4e1750f 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -1366,7 +1366,12 @@
     Py_ssize_t i;
     PyObject* list;
 
-    /* FIXME: report as deprecated? */
+    if (PyErr_WarnEx(PyExc_DeprecationWarning,
+                     "This method will be removed in future versions.  "
+                     "Use 'list(elem)' or iteration over elem instead.",
+                     1) < 0) {
+        return NULL;
+    }
 
     if (!self->extra)
         return PyList_New(0);
@@ -1416,6 +1421,28 @@
 
 
 /*[clinic input]
+_elementtree.Element.getiterator
+
+    tag: object = None
+
+[clinic start generated code]*/
+
+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,
+                     "This method will be removed in future versions.  "
+                     "Use 'tree.iter()' or 'list(tree.iter())' instead.",
+                     1) < 0) {
+        return NULL;
+    }
+    return _elementtree_Element_iter_impl(self, tag);
+}
+
+
+/*[clinic input]
 _elementtree.Element.itertext
 
 [clinic start generated code]*/
@@ -3244,6 +3271,14 @@
                                      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;
+        }
+    }
+
     self->entity = PyDict_New();
     if (!self->entity)
         return -1;
@@ -3716,7 +3751,7 @@
     _ELEMENTTREE_ELEMENT_ITERTEXT_METHODDEF
     _ELEMENTTREE_ELEMENT_ITERFIND_METHODDEF
 
-    {"getiterator", (PyCFunction)_elementtree_Element_iter, METH_FASTCALL, _elementtree_Element_iter__doc__},
+    _ELEMENTTREE_ELEMENT_GETITERATOR_METHODDEF
     _ELEMENTTREE_ELEMENT_GETCHILDREN_METHODDEF
 
     _ELEMENTTREE_ELEMENT_ITEMS_METHODDEF
diff --git a/Modules/clinic/_elementtree.c.h b/Modules/clinic/_elementtree.c.h
index c13cb35..7d1fd18 100644
--- a/Modules/clinic/_elementtree.c.h
+++ b/Modules/clinic/_elementtree.c.h
@@ -333,6 +333,35 @@
     return return_value;
 }
 
+PyDoc_STRVAR(_elementtree_Element_getiterator__doc__,
+"getiterator($self, /, tag=None)\n"
+"--\n"
+"\n");
+
+#define _ELEMENTTREE_ELEMENT_GETITERATOR_METHODDEF    \
+    {"getiterator", (PyCFunction)_elementtree_Element_getiterator, METH_FASTCALL, _elementtree_Element_getiterator__doc__},
+
+static PyObject *
+_elementtree_Element_getiterator_impl(ElementObject *self, PyObject *tag);
+
+static PyObject *
+_elementtree_Element_getiterator(ElementObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    static const char * const _keywords[] = {"tag", NULL};
+    static _PyArg_Parser _parser = {"|O:getiterator", _keywords, 0};
+    PyObject *tag = Py_None;
+
+    if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
+        &tag)) {
+        goto exit;
+    }
+    return_value = _elementtree_Element_getiterator_impl(self, tag);
+
+exit:
+    return return_value;
+}
+
 PyDoc_STRVAR(_elementtree_Element_itertext__doc__,
 "itertext($self, /)\n"
 "--\n"
@@ -726,4 +755,4 @@
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=b69fa98c40917f58 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=fbc92d64735adec0 input=a9049054013a1b77]*/