mirror of https://github.com/python/cpython
Merged upstream changes.
This commit is contained in:
commit
682c979871
|
@ -1855,58 +1855,16 @@ def check_issue10777():
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class CleanContext(object):
|
class ElementTreeTest(unittest.TestCase):
|
||||||
"""Provide default namespace mapping and path cache."""
|
|
||||||
checkwarnings = None
|
|
||||||
|
|
||||||
def __init__(self, quiet=False):
|
def test_istype(self):
|
||||||
if sys.flags.optimize >= 2:
|
self.assertIsInstance(ET.ParseError, type)
|
||||||
# under -OO, doctests cannot be run and therefore not all warnings
|
self.assertIsInstance(ET.QName, type)
|
||||||
# will be emitted
|
self.assertIsInstance(ET.ElementTree, type)
|
||||||
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),
|
|
||||||
# XMLParser.doctype() is deprecated.
|
|
||||||
("This method of XMLParser is deprecated. Define doctype.. "
|
|
||||||
"method on the TreeBuilder target.", DeprecationWarning))
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class TestAcceleratorNotImported(unittest.TestCase):
|
|
||||||
# Test that the C accelerator was not imported for pyET
|
|
||||||
def test_correct_import_pyET(self):
|
|
||||||
self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree')
|
|
||||||
|
|
||||||
|
|
||||||
class TestElementClass(unittest.TestCase):
|
|
||||||
def test_Element_is_a_type(self):
|
|
||||||
self.assertIsInstance(ET.Element, type)
|
self.assertIsInstance(ET.Element, type)
|
||||||
|
# XXX issue 14128 with C ElementTree
|
||||||
|
# self.assertIsInstance(ET.TreeBuilder, type)
|
||||||
|
# self.assertIsInstance(ET.XMLParser, type)
|
||||||
|
|
||||||
def test_Element_subclass_trivial(self):
|
def test_Element_subclass_trivial(self):
|
||||||
class MyElement(ET.Element):
|
class MyElement(ET.Element):
|
||||||
|
@ -1936,16 +1894,115 @@ class TestElementClass(unittest.TestCase):
|
||||||
self.assertEqual(mye.newmethod(), 'joe')
|
self.assertEqual(mye.newmethod(), 'joe')
|
||||||
|
|
||||||
|
|
||||||
|
class TreeBuilderTest(unittest.TestCase):
|
||||||
|
|
||||||
|
sample1 = ('<!DOCTYPE html PUBLIC'
|
||||||
|
' "-//W3C//DTD XHTML 1.0 Transitional//EN"'
|
||||||
|
' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
||||||
|
'<html>text</html>')
|
||||||
|
|
||||||
|
def test_dummy_builder(self):
|
||||||
|
class BaseDummyBuilder:
|
||||||
|
def close(self):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
class DummyBuilder(BaseDummyBuilder):
|
||||||
|
data = start = end = lambda *a: None
|
||||||
|
|
||||||
|
parser = ET.XMLParser(target=DummyBuilder())
|
||||||
|
parser.feed(self.sample1)
|
||||||
|
self.assertEqual(parser.close(), 42)
|
||||||
|
|
||||||
|
parser = ET.XMLParser(target=BaseDummyBuilder())
|
||||||
|
parser.feed(self.sample1)
|
||||||
|
self.assertEqual(parser.close(), 42)
|
||||||
|
|
||||||
|
parser = ET.XMLParser(target=object())
|
||||||
|
parser.feed(self.sample1)
|
||||||
|
self.assertIsNone(parser.close())
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.expectedFailure # XXX issue 14007 with C ElementTree
|
||||||
|
def test_doctype(self):
|
||||||
|
class DoctypeParser:
|
||||||
|
_doctype = None
|
||||||
|
|
||||||
|
def doctype(self, name, pubid, system):
|
||||||
|
self._doctype = (name, pubid, system)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
return self._doctype
|
||||||
|
|
||||||
|
parser = ET.XMLParser(target=DoctypeParser())
|
||||||
|
parser.feed(self.sample1)
|
||||||
|
|
||||||
|
self.assertEqual(parser.close(),
|
||||||
|
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
|
||||||
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
|
||||||
|
|
||||||
|
|
||||||
|
class NoAcceleratorTest(unittest.TestCase):
|
||||||
|
|
||||||
|
# Test that the C accelerator was not imported for pyET
|
||||||
|
def test_correct_import_pyET(self):
|
||||||
|
self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree')
|
||||||
|
self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree')
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
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=pyET):
|
def test_main(module=pyET):
|
||||||
from test import test_xml_etree
|
from test import test_xml_etree
|
||||||
|
|
||||||
# Run the tests specific to the Python implementation
|
|
||||||
support.run_unittest(TestAcceleratorNotImported)
|
|
||||||
|
|
||||||
# The same doctests are used for both the Python and the C implementations
|
# The same doctests are used for both the Python and the C implementations
|
||||||
test_xml_etree.ET = module
|
test_xml_etree.ET = module
|
||||||
|
|
||||||
support.run_unittest(TestElementClass)
|
test_classes = [ElementTreeTest, TreeBuilderTest]
|
||||||
|
if module is pyET:
|
||||||
|
# Run the tests specific to the Python implementation
|
||||||
|
test_classes += [NoAcceleratorTest]
|
||||||
|
|
||||||
|
support.run_unittest(*test_classes)
|
||||||
|
|
||||||
# XXX the C module should give the same warnings as the Python module
|
# XXX the C module should give the same warnings as the Python module
|
||||||
with CleanContext(quiet=(module is not pyET)):
|
with CleanContext(quiet=(module is not pyET)):
|
||||||
|
|
|
@ -1511,24 +1511,30 @@ class XMLParser:
|
||||||
self.target = self._target = target
|
self.target = self._target = target
|
||||||
self._error = expat.error
|
self._error = expat.error
|
||||||
self._names = {} # name memo cache
|
self._names = {} # name memo cache
|
||||||
# callbacks
|
# main callbacks
|
||||||
parser.DefaultHandlerExpand = self._default
|
parser.DefaultHandlerExpand = self._default
|
||||||
parser.StartElementHandler = self._start
|
if hasattr(target, 'start'):
|
||||||
parser.EndElementHandler = self._end
|
parser.StartElementHandler = self._start
|
||||||
parser.CharacterDataHandler = self._data
|
if hasattr(target, 'end'):
|
||||||
# optional callbacks
|
parser.EndElementHandler = self._end
|
||||||
parser.CommentHandler = self._comment
|
if hasattr(target, 'data'):
|
||||||
parser.ProcessingInstructionHandler = self._pi
|
parser.CharacterDataHandler = target.data
|
||||||
|
# miscellaneous callbacks
|
||||||
|
if hasattr(target, 'comment'):
|
||||||
|
parser.CommentHandler = target.comment
|
||||||
|
if hasattr(target, 'pi'):
|
||||||
|
parser.ProcessingInstructionHandler = target.pi
|
||||||
# let expat do the buffering, if supported
|
# let expat do the buffering, if supported
|
||||||
try:
|
try:
|
||||||
self._parser.buffer_text = 1
|
parser.buffer_text = 1
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
# use new-style attribute handling, if supported
|
# use new-style attribute handling, if supported
|
||||||
try:
|
try:
|
||||||
self._parser.ordered_attributes = 1
|
parser.ordered_attributes = 1
|
||||||
self._parser.specified_attributes = 1
|
parser.specified_attributes = 1
|
||||||
parser.StartElementHandler = self._start_list
|
if hasattr(target, 'start'):
|
||||||
|
parser.StartElementHandler = self._start_list
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
self._doctype = None
|
self._doctype = None
|
||||||
|
@ -1572,44 +1578,29 @@ class XMLParser:
|
||||||
attrib[fixname(attrib_in[i])] = attrib_in[i+1]
|
attrib[fixname(attrib_in[i])] = attrib_in[i+1]
|
||||||
return self.target.start(tag, attrib)
|
return self.target.start(tag, attrib)
|
||||||
|
|
||||||
def _data(self, text):
|
|
||||||
return self.target.data(text)
|
|
||||||
|
|
||||||
def _end(self, tag):
|
def _end(self, tag):
|
||||||
return self.target.end(self._fixname(tag))
|
return self.target.end(self._fixname(tag))
|
||||||
|
|
||||||
def _comment(self, data):
|
|
||||||
try:
|
|
||||||
comment = self.target.comment
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
return comment(data)
|
|
||||||
|
|
||||||
def _pi(self, target, data):
|
|
||||||
try:
|
|
||||||
pi = self.target.pi
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
return pi(target, data)
|
|
||||||
|
|
||||||
def _default(self, text):
|
def _default(self, text):
|
||||||
prefix = text[:1]
|
prefix = text[:1]
|
||||||
if prefix == "&":
|
if prefix == "&":
|
||||||
# deal with undefined entities
|
# deal with undefined entities
|
||||||
try:
|
try:
|
||||||
self.target.data(self.entity[text[1:-1]])
|
data_handler = self.target.data
|
||||||
|
except AttributeError:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
data_handler(self.entity[text[1:-1]])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
from xml.parsers import expat
|
from xml.parsers import expat
|
||||||
err = expat.error(
|
err = expat.error(
|
||||||
"undefined entity %s: line %d, column %d" %
|
"undefined entity %s: line %d, column %d" %
|
||||||
(text, self._parser.ErrorLineNumber,
|
(text, self.parser.ErrorLineNumber,
|
||||||
self._parser.ErrorColumnNumber)
|
self.parser.ErrorColumnNumber)
|
||||||
)
|
)
|
||||||
err.code = 11 # XML_ERROR_UNDEFINED_ENTITY
|
err.code = 11 # XML_ERROR_UNDEFINED_ENTITY
|
||||||
err.lineno = self._parser.ErrorLineNumber
|
err.lineno = self.parser.ErrorLineNumber
|
||||||
err.offset = self._parser.ErrorColumnNumber
|
err.offset = self.parser.ErrorColumnNumber
|
||||||
raise err
|
raise err
|
||||||
elif prefix == "<" and text[:9] == "<!DOCTYPE":
|
elif prefix == "<" and text[:9] == "<!DOCTYPE":
|
||||||
self._doctype = [] # inside a doctype declaration
|
self._doctype = [] # inside a doctype declaration
|
||||||
|
@ -1636,7 +1627,7 @@ class XMLParser:
|
||||||
pubid = pubid[1:-1]
|
pubid = pubid[1:-1]
|
||||||
if hasattr(self.target, "doctype"):
|
if hasattr(self.target, "doctype"):
|
||||||
self.target.doctype(name, pubid, system[1:-1])
|
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
|
# warn about deprecated call
|
||||||
self._XMLParser__doctype(name, pubid, system[1:-1])
|
self._XMLParser__doctype(name, pubid, system[1:-1])
|
||||||
self.doctype(name, pubid, system[1:-1])
|
self.doctype(name, pubid, system[1:-1])
|
||||||
|
@ -1667,7 +1658,7 @@ class XMLParser:
|
||||||
|
|
||||||
def feed(self, data):
|
def feed(self, data):
|
||||||
try:
|
try:
|
||||||
self._parser.Parse(data, 0)
|
self.parser.Parse(data, 0)
|
||||||
except self._error as v:
|
except self._error as v:
|
||||||
self._raiseerror(v)
|
self._raiseerror(v)
|
||||||
|
|
||||||
|
@ -1679,12 +1670,20 @@ class XMLParser:
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
try:
|
try:
|
||||||
self._parser.Parse("", 1) # end of data
|
self.parser.Parse("", 1) # end of data
|
||||||
except self._error as v:
|
except self._error as v:
|
||||||
self._raiseerror(v)
|
self._raiseerror(v)
|
||||||
tree = self.target.close()
|
try:
|
||||||
del self.target, self._parser # get rid of circular references
|
try:
|
||||||
return tree
|
close_handler = self.target.close
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
return close_handler()
|
||||||
|
finally:
|
||||||
|
# get rid of circular references
|
||||||
|
del self.parser, self._parser
|
||||||
|
del self.target, self._target
|
||||||
|
|
||||||
|
|
||||||
# Import the C accelerators
|
# Import the C accelerators
|
||||||
|
|
|
@ -13,6 +13,10 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #14007: Accept incomplete TreeBuilder objects (missing start, end,
|
||||||
|
data or close method) for the Python implementation as well.
|
||||||
|
Drop the no-op TreeBuilder().xml() method from the C implementation.
|
||||||
|
|
||||||
|
|
||||||
What's New in Python 3.3.0 Alpha 1?
|
What's New in Python 3.3.0 Alpha 1?
|
||||||
===================================
|
===================================
|
||||||
|
|
|
@ -1698,13 +1698,6 @@ treebuilder_dealloc(TreeBuilderObject* self)
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* handlers */
|
/* handlers */
|
||||||
|
|
||||||
LOCAL(PyObject*)
|
|
||||||
treebuilder_handle_xml(TreeBuilderObject* self, PyObject* encoding,
|
|
||||||
PyObject* standalone)
|
|
||||||
{
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOCAL(PyObject*)
|
LOCAL(PyObject*)
|
||||||
treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag,
|
treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag,
|
||||||
PyObject* attrib)
|
PyObject* attrib)
|
||||||
|
@ -1976,22 +1969,10 @@ treebuilder_start(TreeBuilderObject* self, PyObject* args)
|
||||||
return treebuilder_handle_start(self, tag, attrib);
|
return treebuilder_handle_start(self, tag, attrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
|
||||||
treebuilder_xml(TreeBuilderObject* self, PyObject* args)
|
|
||||||
{
|
|
||||||
PyObject* encoding;
|
|
||||||
PyObject* standalone;
|
|
||||||
if (!PyArg_ParseTuple(args, "OO:xml", &encoding, &standalone))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return treebuilder_handle_xml(self, encoding, standalone);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyMethodDef treebuilder_methods[] = {
|
static PyMethodDef treebuilder_methods[] = {
|
||||||
{"data", (PyCFunction) treebuilder_data, METH_VARARGS},
|
{"data", (PyCFunction) treebuilder_data, METH_VARARGS},
|
||||||
{"start", (PyCFunction) treebuilder_start, METH_VARARGS},
|
{"start", (PyCFunction) treebuilder_start, METH_VARARGS},
|
||||||
{"end", (PyCFunction) treebuilder_end, METH_VARARGS},
|
{"end", (PyCFunction) treebuilder_end, METH_VARARGS},
|
||||||
{"xml", (PyCFunction) treebuilder_xml, METH_VARARGS},
|
|
||||||
{"close", (PyCFunction) treebuilder_close, METH_VARARGS},
|
{"close", (PyCFunction) treebuilder_close, METH_VARARGS},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
@ -2052,8 +2033,6 @@ typedef struct {
|
||||||
|
|
||||||
PyObject* names;
|
PyObject* names;
|
||||||
|
|
||||||
PyObject* handle_xml;
|
|
||||||
|
|
||||||
PyObject* handle_start;
|
PyObject* handle_start;
|
||||||
PyObject* handle_data;
|
PyObject* handle_data;
|
||||||
PyObject* handle_end;
|
PyObject* handle_end;
|
||||||
|
@ -2506,7 +2485,6 @@ xmlparser(PyObject* self_, PyObject* args, PyObject* kw)
|
||||||
Py_INCREF(target);
|
Py_INCREF(target);
|
||||||
self->target = target;
|
self->target = target;
|
||||||
|
|
||||||
self->handle_xml = PyObject_GetAttrString(target, "xml");
|
|
||||||
self->handle_start = PyObject_GetAttrString(target, "start");
|
self->handle_start = PyObject_GetAttrString(target, "start");
|
||||||
self->handle_data = PyObject_GetAttrString(target, "data");
|
self->handle_data = PyObject_GetAttrString(target, "data");
|
||||||
self->handle_end = PyObject_GetAttrString(target, "end");
|
self->handle_end = PyObject_GetAttrString(target, "end");
|
||||||
|
@ -2562,7 +2540,6 @@ xmlparser_dealloc(XMLParserObject* self)
|
||||||
Py_XDECREF(self->handle_end);
|
Py_XDECREF(self->handle_end);
|
||||||
Py_XDECREF(self->handle_data);
|
Py_XDECREF(self->handle_data);
|
||||||
Py_XDECREF(self->handle_start);
|
Py_XDECREF(self->handle_start);
|
||||||
Py_XDECREF(self->handle_xml);
|
|
||||||
|
|
||||||
Py_DECREF(self->target);
|
Py_DECREF(self->target);
|
||||||
Py_DECREF(self->entity);
|
Py_DECREF(self->entity);
|
||||||
|
|
Loading…
Reference in New Issue