mirror of
https://github.com/python/cpython.git
synced 2025-08-02 08:02:56 +00:00
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.
This commit is contained in:
parent
722a3af092
commit
762ec97ea6
6 changed files with 120 additions and 53 deletions
|
@ -6,6 +6,7 @@
|
||||||
# monkey-patched when running the "test_xml_etree_c" test suite.
|
# monkey-patched when running the "test_xml_etree_c" test suite.
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import functools
|
||||||
import html
|
import html
|
||||||
import io
|
import io
|
||||||
import operator
|
import operator
|
||||||
|
@ -90,6 +91,16 @@ ENTITY_XML = """\
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
class ModuleTest(unittest.TestCase):
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
# Import sanity.
|
# Import sanity.
|
||||||
|
@ -690,6 +701,10 @@ class ElementTreeTest(unittest.TestCase):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# Element.getchildren() and ElementTree.getiterator() are deprecated.
|
||||||
|
@checkwarnings(("This method will be removed in future versions. "
|
||||||
|
"Use .+ instead.",
|
||||||
|
(DeprecationWarning, PendingDeprecationWarning)))
|
||||||
def test_getchildren(self):
|
def test_getchildren(self):
|
||||||
# Test Element.getchildren()
|
# Test Element.getchildren()
|
||||||
|
|
||||||
|
@ -1558,7 +1573,7 @@ class BugsTest(unittest.TestCase):
|
||||||
class EchoTarget:
|
class EchoTarget:
|
||||||
def close(self):
|
def close(self):
|
||||||
return ET.Element("element") # simulate root
|
return ET.Element("element") # simulate root
|
||||||
parser = ET.XMLParser(EchoTarget())
|
parser = ET.XMLParser(target=EchoTarget())
|
||||||
parser.feed("<element>some text</element>")
|
parser.feed("<element>some text</element>")
|
||||||
self.assertEqual(parser.close().tag, 'element')
|
self.assertEqual(parser.close().tag, 'element')
|
||||||
|
|
||||||
|
@ -2225,8 +2240,12 @@ class ElementFindTest(unittest.TestCase):
|
||||||
self.assertEqual(summarize_list(ET.ElementTree(e).findall('tag')),
|
self.assertEqual(summarize_list(ET.ElementTree(e).findall('tag')),
|
||||||
['tag'] * 2)
|
['tag'] * 2)
|
||||||
# this produces a warning
|
# this produces a warning
|
||||||
self.assertEqual(summarize_list(ET.ElementTree(e).findall('//tag')),
|
msg = ("This search is broken in 1.3 and earlier, and will be fixed "
|
||||||
['tag'] * 3)
|
"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):
|
class ElementIterTest(unittest.TestCase):
|
||||||
|
@ -2311,6 +2330,9 @@ class ElementIterTest(unittest.TestCase):
|
||||||
self.assertEqual(self._ilist(doc), all_tags)
|
self.assertEqual(self._ilist(doc), all_tags)
|
||||||
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):
|
def test_getiterator(self):
|
||||||
doc = ET.XML('''
|
doc = ET.XML('''
|
||||||
<document>
|
<document>
|
||||||
|
@ -2493,13 +2515,13 @@ class XMLParserTest(unittest.TestCase):
|
||||||
def test_constructor_args(self):
|
def test_constructor_args(self):
|
||||||
# Positional args. The first (html) is not supported, but should be
|
# Positional args. The first (html) is not supported, but should be
|
||||||
# nevertheless correctly accepted.
|
# 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)
|
parser.feed(self.sample1)
|
||||||
self._check_sample_element(parser.close())
|
self._check_sample_element(parser.close())
|
||||||
|
|
||||||
# Now as keyword args.
|
# Now as keyword args.
|
||||||
parser2 = ET.XMLParser(encoding='utf-8',
|
parser2 = ET.XMLParser(encoding='utf-8',
|
||||||
html=[{}],
|
|
||||||
target=ET.TreeBuilder())
|
target=ET.TreeBuilder())
|
||||||
parser2.feed(self.sample1)
|
parser2.feed(self.sample1)
|
||||||
self._check_sample_element(parser2.close())
|
self._check_sample_element(parser2.close())
|
||||||
|
@ -3016,46 +3038,6 @@ class NoAcceleratorTest(unittest.TestCase):
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
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):
|
def test_main(module=None):
|
||||||
# When invoked without a module, runs the Python ET tests by loading pyET.
|
# When invoked without a module, runs the Python ET tests by loading pyET.
|
||||||
# Otherwise, uses the given module as the ET.
|
# Otherwise, uses the given module as the ET.
|
||||||
|
@ -3095,11 +3077,22 @@ def test_main(module=None):
|
||||||
NoAcceleratorTest,
|
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:
|
try:
|
||||||
# XXX the C module should give the same warnings as the Python module
|
support.run_unittest(*test_classes)
|
||||||
with CleanContext(quiet=(pyET is not ET)):
|
|
||||||
support.run_unittest(*test_classes)
|
|
||||||
finally:
|
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
|
# don't interfere with subsequent tests
|
||||||
ET = pyET = None
|
ET = pyET = None
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ import unittest
|
||||||
cET = import_fresh_module('xml.etree.ElementTree',
|
cET = import_fresh_module('xml.etree.ElementTree',
|
||||||
fresh=['_elementtree'])
|
fresh=['_elementtree'])
|
||||||
cET_alias = import_fresh_module('xml.etree.cElementTree',
|
cET_alias = import_fresh_module('xml.etree.cElementTree',
|
||||||
fresh=['_elementtree', 'xml.etree'])
|
fresh=['_elementtree', 'xml.etree'],
|
||||||
|
deprecated=True)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(cET, 'requires _elementtree')
|
@unittest.skipUnless(cET, 'requires _elementtree')
|
||||||
|
|
|
@ -1430,6 +1430,7 @@ class TreeBuilder:
|
||||||
self._tail = 1
|
self._tail = 1
|
||||||
return self._last
|
return self._last
|
||||||
|
|
||||||
|
_sentinel = ['sentinel']
|
||||||
|
|
||||||
# also see ElementTree and TreeBuilder
|
# also see ElementTree and TreeBuilder
|
||||||
class XMLParser:
|
class XMLParser:
|
||||||
|
@ -1443,7 +1444,11 @@ class XMLParser:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
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:
|
try:
|
||||||
from xml.parsers import expat
|
from xml.parsers import expat
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
|
@ -298,6 +298,10 @@ Extension Modules
|
||||||
Library
|
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
|
- bpo-27863: Fixed multiple crashes in ElementTree caused by race conditions
|
||||||
and wrong types.
|
and wrong types.
|
||||||
|
|
||||||
|
|
|
@ -1366,7 +1366,12 @@ _elementtree_Element_getchildren_impl(ElementObject *self)
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
PyObject* list;
|
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)
|
if (!self->extra)
|
||||||
return PyList_New(0);
|
return PyList_New(0);
|
||||||
|
@ -1415,6 +1420,28 @@ _elementtree_Element_iter_impl(ElementObject *self, PyObject *tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*[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]
|
/*[clinic input]
|
||||||
_elementtree.Element.itertext
|
_elementtree.Element.itertext
|
||||||
|
|
||||||
|
@ -3244,6 +3271,14 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *html,
|
||||||
PyObject *target, const char *encoding)
|
PyObject *target, const char *encoding)
|
||||||
/*[clinic end generated code: output=d6a16c63dda54441 input=155bc5695baafffd]*/
|
/*[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();
|
self->entity = PyDict_New();
|
||||||
if (!self->entity)
|
if (!self->entity)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -3716,7 +3751,7 @@ static PyMethodDef element_methods[] = {
|
||||||
_ELEMENTTREE_ELEMENT_ITERTEXT_METHODDEF
|
_ELEMENTTREE_ELEMENT_ITERTEXT_METHODDEF
|
||||||
_ELEMENTTREE_ELEMENT_ITERFIND_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_GETCHILDREN_METHODDEF
|
||||||
|
|
||||||
_ELEMENTTREE_ELEMENT_ITEMS_METHODDEF
|
_ELEMENTTREE_ELEMENT_ITEMS_METHODDEF
|
||||||
|
|
|
@ -333,6 +333,35 @@ exit:
|
||||||
return return_value;
|
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__,
|
PyDoc_STRVAR(_elementtree_Element_itertext__doc__,
|
||||||
"itertext($self, /)\n"
|
"itertext($self, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -726,4 +755,4 @@ _elementtree_XMLParser__setevents(XMLParserObject *self, PyObject **args, Py_ssi
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=b69fa98c40917f58 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=fbc92d64735adec0 input=a9049054013a1b77]*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue