mirror of
https://github.com/python/cpython.git
synced 2024-11-24 02:15:30 +08:00
Issue #13988: cElementTree is deprecated and the _elementtree accelerator is automatically used whenever available.
This commit is contained in:
parent
d1c7b1afe8
commit
a72a98f24a
@ -32,17 +32,18 @@ To create an element instance, use the :class:`Element` constructor or the
|
||||
The :class:`ElementTree` class can be used to wrap an element structure, and
|
||||
convert it from and to XML.
|
||||
|
||||
A C implementation of this API is available as :mod:`xml.etree.cElementTree`.
|
||||
|
||||
See http://effbot.org/zone/element-index.htm for tutorials and links to other
|
||||
docs. Fredrik Lundh's page is also the location of the development version of
|
||||
the xml.etree.ElementTree.
|
||||
docs.
|
||||
|
||||
.. versionchanged:: 3.2
|
||||
The ElementTree API is updated to 1.3. For more information, see
|
||||
`Introducing ElementTree 1.3
|
||||
<http://effbot.org/zone/elementtree-13-intro.htm>`_.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
This module will use a fast implementation whenever available.
|
||||
The :mod:`xml.etree.cElementTree` module is deprecated.
|
||||
|
||||
|
||||
.. _elementtree-functions:
|
||||
|
||||
|
@ -842,6 +842,8 @@ Deprecated Python modules, functions and methods
|
||||
* :issue:`13374`: The Windows bytes API has been deprecated in the :mod:`os`
|
||||
module. Use Unicode filenames, instead of bytes filenames, to not depend on
|
||||
the ANSI code page anymore and to support any filename.
|
||||
* :issue:`13988`: The :mod:`xml.etree.cElementTree` module is deprecated. The
|
||||
accelerator is used automatically whenever available.
|
||||
|
||||
|
||||
Deprecated functions and types of the C API
|
||||
|
@ -16,9 +16,9 @@ import html
|
||||
import unittest
|
||||
|
||||
from test import support
|
||||
from test.support import findfile
|
||||
from test.support import findfile, import_fresh_module
|
||||
|
||||
from xml.etree import ElementTree as ET
|
||||
pyET = import_fresh_module('xml.etree.ElementTree', blocked=['_elementtree'])
|
||||
|
||||
SIMPLE_XMLFILE = findfile("simple.xml", subdir="xmltestdata")
|
||||
try:
|
||||
@ -275,7 +275,7 @@ def simplefind():
|
||||
"""
|
||||
Test find methods using the elementpath fallback.
|
||||
|
||||
>>> from xml.etree import ElementTree
|
||||
>>> ElementTree = pyET
|
||||
|
||||
>>> CurrentElementPath = ElementTree.ElementPath
|
||||
>>> ElementTree.ElementPath = ElementTree._SimpleElementPath()
|
||||
@ -460,17 +460,19 @@ def path_cache():
|
||||
"""
|
||||
Check that the path cache behaves sanely.
|
||||
|
||||
>>> from xml.etree import ElementPath
|
||||
|
||||
>>> elem = ET.XML(SAMPLE_XML)
|
||||
>>> for i in range(10): ET.ElementTree(elem).find('./'+str(i))
|
||||
>>> cache_len_10 = len(ET.ElementPath._cache)
|
||||
>>> cache_len_10 = len(ElementPath._cache)
|
||||
>>> for i in range(10): ET.ElementTree(elem).find('./'+str(i))
|
||||
>>> len(ET.ElementPath._cache) == cache_len_10
|
||||
>>> len(ElementPath._cache) == cache_len_10
|
||||
True
|
||||
>>> for i in range(20): ET.ElementTree(elem).find('./'+str(i))
|
||||
>>> len(ET.ElementPath._cache) > cache_len_10
|
||||
>>> len(ElementPath._cache) > cache_len_10
|
||||
True
|
||||
>>> for i in range(600): ET.ElementTree(elem).find('./'+str(i))
|
||||
>>> len(ET.ElementPath._cache) < 500
|
||||
>>> len(ElementPath._cache) < 500
|
||||
True
|
||||
"""
|
||||
|
||||
@ -1879,37 +1881,38 @@ class CleanContext(object):
|
||||
self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet)
|
||||
|
||||
def __enter__(self):
|
||||
from xml.etree import ElementTree
|
||||
self._nsmap = ElementTree._namespace_map
|
||||
self._path_cache = ElementTree.ElementPath._cache
|
||||
from xml.etree import ElementPath
|
||||
if hasattr(ET, '_namespace_map'):
|
||||
self._nsmap = ET._namespace_map
|
||||
else:
|
||||
# when testing the cElementTree alias
|
||||
from xml.etree.ElementTree import _namespace_map
|
||||
self._nsmap = _namespace_map
|
||||
# Copy the default namespace mapping
|
||||
ElementTree._namespace_map = self._nsmap.copy()
|
||||
self._nsmap_copy = self._nsmap.copy()
|
||||
# Copy the path cache (should be empty)
|
||||
ElementTree.ElementPath._cache = self._path_cache.copy()
|
||||
self._path_cache = ElementPath._cache
|
||||
ElementPath._cache = self._path_cache.copy()
|
||||
self.checkwarnings.__enter__()
|
||||
|
||||
def __exit__(self, *args):
|
||||
from xml.etree import ElementTree
|
||||
from xml.etree import ElementPath
|
||||
# Restore mapping and path cache
|
||||
ElementTree._namespace_map = self._nsmap
|
||||
ElementTree.ElementPath._cache = self._path_cache
|
||||
self._nsmap.clear()
|
||||
self._nsmap.update(self._nsmap_copy)
|
||||
ElementPath._cache = self._path_cache
|
||||
self.checkwarnings.__exit__(*args)
|
||||
|
||||
|
||||
def test_main(module_name='xml.etree.ElementTree'):
|
||||
def test_main(module=pyET):
|
||||
from test import test_xml_etree
|
||||
|
||||
use_py_module = (module_name == 'xml.etree.ElementTree')
|
||||
|
||||
# The same doctests are used for both the Python and the C implementations
|
||||
assert test_xml_etree.ET.__name__ == module_name
|
||||
test_xml_etree.ET = module
|
||||
|
||||
# XXX the C module should give the same warnings as the Python module
|
||||
with CleanContext(quiet=not use_py_module):
|
||||
with CleanContext(quiet=(module is not pyET)):
|
||||
support.run_doctest(test_xml_etree, verbosity=True)
|
||||
|
||||
# The module should not be changed by the tests
|
||||
assert test_xml_etree.ET.__name__ == module_name
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_main()
|
||||
|
@ -1,10 +1,9 @@
|
||||
# xml.etree test for cElementTree
|
||||
|
||||
from test import support
|
||||
from test.support import bigmemtest, _2G
|
||||
import unittest
|
||||
|
||||
cET = support.import_module('xml.etree.cElementTree')
|
||||
from xml.etree import ElementTree as cET, cElementTree as cET_alias
|
||||
|
||||
|
||||
# cElementTree specific tests
|
||||
@ -13,10 +12,9 @@ def sanity():
|
||||
r"""
|
||||
Import sanity.
|
||||
|
||||
>>> from xml.etree import cElementTree
|
||||
|
||||
Issue #6697.
|
||||
|
||||
>>> cElementTree = cET
|
||||
>>> e = cElementTree.Element('a')
|
||||
>>> getattr(e, '\uD800') # doctest: +ELLIPSIS
|
||||
Traceback (most recent call last):
|
||||
@ -55,19 +53,10 @@ def test_main():
|
||||
|
||||
support.run_unittest(MiscTests)
|
||||
|
||||
# Assign the C implementation before running the doctests
|
||||
# Patch the __name__, to prevent confusion with the pure Python test
|
||||
pyET = test_xml_etree.ET
|
||||
py__name__ = test_xml_etree.__name__
|
||||
test_xml_etree.ET = cET
|
||||
if __name__ != '__main__':
|
||||
test_xml_etree.__name__ = __name__
|
||||
try:
|
||||
# Run the same test suite as xml.etree.ElementTree
|
||||
test_xml_etree.test_main(module_name='xml.etree.cElementTree')
|
||||
finally:
|
||||
test_xml_etree.ET = pyET
|
||||
test_xml_etree.__name__ = py__name__
|
||||
# Run the same test suite as the Python module
|
||||
test_xml_etree.test_main(module=cET)
|
||||
# Exercise the deprecated alias
|
||||
test_xml_etree.test_main(module=cET_alias)
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_main()
|
||||
|
@ -68,8 +68,9 @@ __all__ = [
|
||||
"tostring", "tostringlist",
|
||||
"TreeBuilder",
|
||||
"VERSION",
|
||||
"XML",
|
||||
"XML", "XMLID",
|
||||
"XMLParser", "XMLTreeBuilder",
|
||||
"register_namespace",
|
||||
]
|
||||
|
||||
VERSION = "1.3.0"
|
||||
@ -148,9 +149,9 @@ class ParseError(SyntaxError):
|
||||
# @defreturn flag
|
||||
|
||||
def iselement(element):
|
||||
# FIXME: not sure about this; might be a better idea to look
|
||||
# for tag/attrib/text attributes
|
||||
return isinstance(element, Element) or hasattr(element, "tag")
|
||||
# FIXME: not sure about this;
|
||||
# isinstance(element, Element) or look for tag/attrib/text attributes
|
||||
return hasattr(element, 'tag')
|
||||
|
||||
##
|
||||
# Element class. This class defines the Element interface, and
|
||||
@ -1684,6 +1685,87 @@ class XMLParser:
|
||||
del self.target, self._parser # get rid of circular references
|
||||
return tree
|
||||
|
||||
|
||||
# Import the C accelerators
|
||||
try:
|
||||
# Element, SubElement, ParseError, TreeBuilder, XMLParser
|
||||
from _elementtree import *
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
# Overwrite 'ElementTree.parse' and 'iterparse' to use the C XMLParser
|
||||
|
||||
class ElementTree(ElementTree):
|
||||
def parse(self, source, parser=None):
|
||||
close_source = False
|
||||
if not hasattr(source, 'read'):
|
||||
source = open(source, 'rb')
|
||||
close_source = True
|
||||
try:
|
||||
if parser is not None:
|
||||
while True:
|
||||
data = source.read(65536)
|
||||
if not data:
|
||||
break
|
||||
parser.feed(data)
|
||||
self._root = parser.close()
|
||||
else:
|
||||
parser = XMLParser()
|
||||
self._root = parser._parse(source)
|
||||
return self._root
|
||||
finally:
|
||||
if close_source:
|
||||
source.close()
|
||||
|
||||
class iterparse:
|
||||
root = None
|
||||
def __init__(self, file, events=None):
|
||||
self._close_file = False
|
||||
if not hasattr(file, 'read'):
|
||||
file = open(file, 'rb')
|
||||
self._close_file = True
|
||||
self._file = file
|
||||
self._events = []
|
||||
self._index = 0
|
||||
self._error = None
|
||||
self.root = self._root = None
|
||||
b = TreeBuilder()
|
||||
self._parser = XMLParser(b)
|
||||
self._parser._setevents(self._events, events)
|
||||
|
||||
def __next__(self):
|
||||
while True:
|
||||
try:
|
||||
item = self._events[self._index]
|
||||
self._index += 1
|
||||
return item
|
||||
except IndexError:
|
||||
pass
|
||||
if self._error:
|
||||
e = self._error
|
||||
self._error = None
|
||||
raise e
|
||||
if self._parser is None:
|
||||
self.root = self._root
|
||||
if self._close_file:
|
||||
self._file.close()
|
||||
raise StopIteration
|
||||
# load event buffer
|
||||
del self._events[:]
|
||||
self._index = 0
|
||||
data = self._file.read(16384)
|
||||
if data:
|
||||
try:
|
||||
self._parser.feed(data)
|
||||
except SyntaxError as exc:
|
||||
self._error = exc
|
||||
else:
|
||||
self._root = self._parser.close()
|
||||
self._parser = None
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
# compatibility
|
||||
XMLTreeBuilder = XMLParser
|
||||
|
||||
|
@ -1,153 +1,3 @@
|
||||
# Wrapper module for _elementtree
|
||||
# Deprecated alias for xml.etree.ElementTree
|
||||
|
||||
from xml.etree.ElementTree import (ElementTree, dump, iselement, QName,
|
||||
fromstringlist,
|
||||
tostring, tostringlist, VERSION)
|
||||
# These ones are not in ElementTree.__all__
|
||||
from xml.etree.ElementTree import ElementPath, register_namespace
|
||||
|
||||
# Import the C accelerators:
|
||||
# Element, SubElement, TreeBuilder, XMLParser, ParseError
|
||||
from _elementtree import *
|
||||
|
||||
|
||||
class ElementTree(ElementTree):
|
||||
|
||||
def parse(self, source, parser=None):
|
||||
close_source = False
|
||||
if not hasattr(source, 'read'):
|
||||
source = open(source, 'rb')
|
||||
close_source = True
|
||||
try:
|
||||
if parser is not None:
|
||||
while True:
|
||||
data = source.read(65536)
|
||||
if not data:
|
||||
break
|
||||
parser.feed(data)
|
||||
self._root = parser.close()
|
||||
else:
|
||||
parser = XMLParser()
|
||||
self._root = parser._parse(source)
|
||||
return self._root
|
||||
finally:
|
||||
if close_source:
|
||||
source.close()
|
||||
|
||||
|
||||
class iterparse:
|
||||
root = None
|
||||
|
||||
def __init__(self, file, events=None):
|
||||
self._close_file = False
|
||||
if not hasattr(file, 'read'):
|
||||
file = open(file, 'rb')
|
||||
self._close_file = True
|
||||
self._file = file
|
||||
self._events = []
|
||||
self._index = 0
|
||||
self._error = None
|
||||
self.root = self._root = None
|
||||
b = TreeBuilder()
|
||||
self._parser = XMLParser(b)
|
||||
self._parser._setevents(self._events, events)
|
||||
|
||||
def __next__(self):
|
||||
while True:
|
||||
try:
|
||||
item = self._events[self._index]
|
||||
self._index += 1
|
||||
return item
|
||||
except IndexError:
|
||||
pass
|
||||
if self._error:
|
||||
e = self._error
|
||||
self._error = None
|
||||
raise e
|
||||
if self._parser is None:
|
||||
self.root = self._root
|
||||
if self._close_file:
|
||||
self._file.close()
|
||||
raise StopIteration
|
||||
# load event buffer
|
||||
del self._events[:]
|
||||
self._index = 0
|
||||
data = self._file.read(16384)
|
||||
if data:
|
||||
try:
|
||||
self._parser.feed(data)
|
||||
except SyntaxError as exc:
|
||||
self._error = exc
|
||||
else:
|
||||
self._root = self._parser.close()
|
||||
self._parser = None
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Everything below this line can be removed
|
||||
# after cElementTree is folded behind ElementTree.
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
from xml.etree.ElementTree import Comment as _Comment, PI as _PI
|
||||
|
||||
|
||||
def parse(source, parser=None):
|
||||
tree = ElementTree()
|
||||
tree.parse(source, parser)
|
||||
return tree
|
||||
|
||||
|
||||
def XML(text, parser=None):
|
||||
if not parser:
|
||||
parser = XMLParser()
|
||||
parser = XMLParser()
|
||||
parser.feed(text)
|
||||
return parser.close()
|
||||
|
||||
|
||||
def XMLID(text, parser=None):
|
||||
tree = XML(text, parser=parser)
|
||||
ids = {}
|
||||
for elem in tree.iter():
|
||||
id = elem.get('id')
|
||||
if id:
|
||||
ids[id] = elem
|
||||
return tree, ids
|
||||
|
||||
|
||||
class CommentProxy:
|
||||
|
||||
def __call__(self, text=None):
|
||||
element = Element(_Comment)
|
||||
element.text = text
|
||||
return element
|
||||
|
||||
def __eq__(self, other):
|
||||
return _Comment == other
|
||||
|
||||
|
||||
class PIProxy:
|
||||
|
||||
def __call__(self, target, text=None):
|
||||
element = Element(_PI)
|
||||
element.text = target
|
||||
if text:
|
||||
element.text = element.text + ' ' + text
|
||||
return element
|
||||
|
||||
def __eq__(self, other):
|
||||
return _PI == other
|
||||
|
||||
|
||||
Comment = CommentProxy()
|
||||
PI = ProcessingInstruction = PIProxy()
|
||||
del CommentProxy, PIProxy
|
||||
|
||||
# Aliases
|
||||
fromstring = XML
|
||||
XMLTreeBuilder = XMLParser
|
||||
from xml.etree.ElementTree import *
|
||||
|
@ -1886,6 +1886,9 @@ Library
|
||||
- Issue #12191: Added shutil.chown() to change user and/or group owner of a
|
||||
given path also specifying their names.
|
||||
|
||||
- Issue #13988: The _elementtree accelerator is used whenever available.
|
||||
Now xml.etree.cElementTree becomes a deprecated alias to ElementTree.
|
||||
|
||||
Build
|
||||
-----
|
||||
|
||||
|
@ -70,7 +70,7 @@
|
||||
helps if you have lots of leaf nodes with attributes). */
|
||||
|
||||
/* Also note that pymalloc always allocates blocks in multiples of
|
||||
eight bytes. For the current version of cElementTree, this means
|
||||
eight bytes. For the current C version of ElementTree, this means
|
||||
that the number of children should be an even number, at least on
|
||||
32-bit platforms. */
|
||||
|
||||
@ -2649,7 +2649,7 @@ xmlparser_setevents(XMLParserObject* self, PyObject* args)
|
||||
if (!TreeBuilder_CheckExact(self->target)) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"event handling only supported for cElementTree.Treebuilder "
|
||||
"event handling only supported for ElementTree.TreeBuilder "
|
||||
"targets"
|
||||
);
|
||||
return NULL;
|
||||
@ -2906,7 +2906,7 @@ PyInit__elementtree(void)
|
||||
#endif
|
||||
|
||||
elementtree_parseerror_obj = PyErr_NewException(
|
||||
"cElementTree.ParseError", PyExc_SyntaxError, NULL
|
||||
"xml.etree.ElementTree.ParseError", PyExc_SyntaxError, NULL
|
||||
);
|
||||
Py_INCREF(elementtree_parseerror_obj);
|
||||
PyModule_AddObject(m, "ParseError", elementtree_parseerror_obj);
|
||||
|
Loading…
Reference in New Issue
Block a user