bpo-30365: Backport warnings and fix bugs in ElementTree. (#1581)
Running Python with the -3 option now emits deprecation warnings for getchildren() and getiterator() methods of the Element class in the xml.etree.cElementTree module and when pass the html argument to xml.etree.ElementTree.XMLParser(). Fixed a deprecation warning about the doctype() method of the xml.etree.ElementTree.XMLParser class. Now it is emitted only when define the doctype() method in the subclass of XMLParser. Fixed a bug in the test_bug_200708_close test method. An EchoTarget instance was incorrectly passed to XMLParser() as the html argument and silently ignored. Tests no longer failed when use the -m option for running only selected test methods. Checking warnings now is more specific, warnings are expected only when use deprecated features.
This commit is contained in:
parent
800e4b7ad6
commit
09b52471f3
|
@ -8,6 +8,7 @@
|
|||
|
||||
import cgi
|
||||
import copy
|
||||
import functools
|
||||
import io
|
||||
import pickle
|
||||
import StringIO
|
||||
|
@ -86,6 +87,16 @@ ENTITY_XML = """\
|
|||
"""
|
||||
|
||||
|
||||
def checkwarnings(*filters):
|
||||
def decorator(test):
|
||||
def newtest(*args, **kwargs):
|
||||
with support.check_warnings(*filters):
|
||||
test(*args, **kwargs)
|
||||
functools.update_wrapper(newtest, test)
|
||||
return newtest
|
||||
return decorator
|
||||
|
||||
|
||||
class ModuleTest(unittest.TestCase):
|
||||
# TODO: this should be removed once we get rid of the global module vars
|
||||
|
||||
|
@ -656,6 +667,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):
|
||||
# Test Element.getchildren()
|
||||
|
||||
|
@ -1356,9 +1371,15 @@ class BugsTest(unittest.TestCase):
|
|||
|
||||
# Test custom builder.
|
||||
class EchoTarget:
|
||||
def start(self, tag, attrib):
|
||||
pass
|
||||
def end(self, tag):
|
||||
pass
|
||||
def data(self, text):
|
||||
pass
|
||||
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')
|
||||
|
||||
|
@ -1908,7 +1929,12 @@ class ElementFindTest(unittest.TestCase):
|
|||
e = ET.XML(SAMPLE_XML)
|
||||
self.assertEqual(ET.ElementTree(e).find('tag').tag, 'tag')
|
||||
self.assertEqual(ET.ElementTree(e).find('./tag').tag, 'tag')
|
||||
self.assertEqual(ET.ElementTree(e).find('/tag').tag, 'tag')
|
||||
# this produces a warning
|
||||
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 support.check_warnings((msg, FutureWarning)):
|
||||
self.assertEqual(ET.ElementTree(e).find('/tag').tag, 'tag')
|
||||
e[2] = ET.XML(SAMPLE_SECTION)
|
||||
self.assertEqual(ET.ElementTree(e).find('section/tag').tag, 'tag')
|
||||
self.assertIsNone(ET.ElementTree(e).find('tog'))
|
||||
|
@ -1919,14 +1945,15 @@ class ElementFindTest(unittest.TestCase):
|
|||
self.assertEqual(ET.ElementTree(e).findtext('tog/foo', 'default'),
|
||||
'default')
|
||||
self.assertEqual(ET.ElementTree(e).findtext('./tag'), 'text')
|
||||
self.assertEqual(ET.ElementTree(e).findtext('/tag'), 'text')
|
||||
with support.check_warnings((msg, FutureWarning)):
|
||||
self.assertEqual(ET.ElementTree(e).findtext('/tag'), 'text')
|
||||
self.assertEqual(ET.ElementTree(e).findtext('section/tag'), 'subtext')
|
||||
|
||||
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'] * 2)
|
||||
with support.check_warnings((msg, FutureWarning)):
|
||||
it = ET.ElementTree(e).findall('/tag')
|
||||
self.assertEqual(summarize_list(it), ['tag'] * 2)
|
||||
|
||||
|
||||
class ElementIterTest(unittest.TestCase):
|
||||
|
@ -2014,6 +2041,15 @@ class ElementIterTest(unittest.TestCase):
|
|||
self.assertEqual(self._ilist(doc, '*'), all_tags)
|
||||
|
||||
def test_getiterator(self):
|
||||
# Element.getiterator() is deprecated.
|
||||
if sys.py3kwarning or ET is pyET:
|
||||
with support.check_warnings(("This method will be removed in future versions. "
|
||||
"Use .+ instead.", PendingDeprecationWarning)):
|
||||
self._test_getiterator()
|
||||
else:
|
||||
self._test_getiterator()
|
||||
|
||||
def _test_getiterator(self):
|
||||
doc = ET.XML('''
|
||||
<document>
|
||||
<house>
|
||||
|
@ -2178,13 +2214,13 @@ class XMLParserTest(unittest.TestCase):
|
|||
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 support.check_py3k_warnings((r'.*\bhtml\b', DeprecationWarning)):
|
||||
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())
|
||||
|
@ -2593,44 +2629,6 @@ class NoAcceleratorTest(unittest.TestCase):
|
|||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
class CleanContext(object):
|
||||
"""Provide default namespace mapping and path cache."""
|
||||
checkwarnings = None
|
||||
|
||||
def __init__(self, quiet=False):
|
||||
deprecations = (
|
||||
("This method of XMLParser is deprecated. Define doctype\(\) "
|
||||
"method on the TreeBuilder target.", DeprecationWarning),
|
||||
# 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 = pyET._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.
|
||||
|
@ -2666,11 +2664,22 @@ def test_main(module=None):
|
|||
NoAcceleratorTest,
|
||||
])
|
||||
|
||||
# Provide default namespace mapping and path cache.
|
||||
from xml.etree import ElementPath
|
||||
nsmap = pyET._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 = None
|
||||
|
||||
|
|
|
@ -1450,6 +1450,8 @@ class TreeBuilder(object):
|
|||
self._tail = 1
|
||||
return self._last
|
||||
|
||||
_sentinel = ['sentinel']
|
||||
|
||||
##
|
||||
# Element structure builder for XML source data, based on the
|
||||
# <b>expat</b> parser.
|
||||
|
@ -1465,7 +1467,11 @@ class TreeBuilder(object):
|
|||
|
||||
class XMLParser(object):
|
||||
|
||||
def __init__(self, html=0, target=None, encoding=None):
|
||||
def __init__(self, html=_sentinel, target=None, encoding=None):
|
||||
if html is not _sentinel:
|
||||
warnings.warnpy3k(
|
||||
"The html argument of XMLParser() is deprecated",
|
||||
DeprecationWarning, stacklevel=2)
|
||||
try:
|
||||
from xml.parsers import expat
|
||||
except ImportError:
|
||||
|
@ -1617,7 +1623,7 @@ class XMLParser(object):
|
|||
pubid = pubid[1:-1]
|
||||
if hasattr(self.target, "doctype"):
|
||||
self.target.doctype(name, pubid, system[1:-1])
|
||||
elif self.doctype is not self._XMLParser__doctype:
|
||||
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])
|
||||
|
|
|
@ -42,6 +42,15 @@ Extension Modules
|
|||
Library
|
||||
-------
|
||||
|
||||
- bpo-30365: Running Python with the -3 option now emits deprecation warnings
|
||||
for getchildren() and getiterator() methods of the Element class in the
|
||||
xml.etree.cElementTree module and when pass the html argument to
|
||||
xml.etree.ElementTree.XMLParser().
|
||||
|
||||
- bpo-30365: Fixed a deprecation warning about the doctype() method of the
|
||||
xml.etree.ElementTree.XMLParser class. Now it is emitted only when define
|
||||
the doctype() method in the subclass of XMLParser.
|
||||
|
||||
- bpo-30329: imaplib now catchs the Windows socket WSAEINVAL error
|
||||
(code 10022) on shutdown(SHUT_RDWR): An invalid operation was attempted.
|
||||
This error occurs sometimes on SSL connections.
|
||||
|
|
|
@ -962,7 +962,11 @@ element_getchildren(ElementObject* self, PyObject* args)
|
|||
int i;
|
||||
PyObject* list;
|
||||
|
||||
/* FIXME: report as deprecated? */
|
||||
if (PyErr_WarnPy3k("This method will be removed in future versions. "
|
||||
"Use 'list(elem)' or iteration over elem instead.",
|
||||
1) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyArg_ParseTuple(args, ":getchildren"))
|
||||
return NULL;
|
||||
|
@ -984,13 +988,10 @@ element_getchildren(ElementObject* self, PyObject* args)
|
|||
}
|
||||
|
||||
static PyObject*
|
||||
element_iter(ElementObject* self, PyObject* args)
|
||||
element_iter_impl(ElementObject* self, PyObject* tag)
|
||||
{
|
||||
PyObject* args;
|
||||
PyObject* result;
|
||||
|
||||
PyObject* tag = Py_None;
|
||||
if (!PyArg_ParseTuple(args, "|O:iter", &tag))
|
||||
return NULL;
|
||||
|
||||
if (!elementtree_iter_obj) {
|
||||
PyErr_SetString(
|
||||
|
@ -1014,6 +1015,34 @@ element_iter(ElementObject* self, PyObject* args)
|
|||
return result;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
element_iter(ElementObject* self, PyObject* args)
|
||||
{
|
||||
PyObject* tag = Py_None;
|
||||
if (!PyArg_ParseTuple(args, "|O:iter", &tag))
|
||||
return NULL;
|
||||
|
||||
return element_iter_impl(self, tag);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
element_getiterator(ElementObject* self, PyObject* args)
|
||||
{
|
||||
PyObject* tag = Py_None;
|
||||
if (!PyArg_ParseTuple(args, "|O:getiterator", &tag))
|
||||
return NULL;
|
||||
|
||||
/* Change for a DeprecationWarning in 1.4 */
|
||||
if (Py_Py3kWarningFlag &&
|
||||
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 element_iter_impl(self, tag);
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
element_itertext(ElementObject* self, PyObject* args)
|
||||
|
@ -1510,7 +1539,7 @@ static PyMethodDef element_methods[] = {
|
|||
{"itertext", (PyCFunction) element_itertext, METH_VARARGS},
|
||||
{"iterfind", (PyCFunction) element_iterfind, METH_VARARGS},
|
||||
|
||||
{"getiterator", (PyCFunction) element_iter, METH_VARARGS},
|
||||
{"getiterator", (PyCFunction) element_getiterator, METH_VARARGS},
|
||||
{"getchildren", (PyCFunction) element_getchildren, METH_VARARGS},
|
||||
|
||||
{"items", (PyCFunction) element_items, METH_VARARGS},
|
||||
|
|
Loading…
Reference in New Issue