]> granicus.if.org Git - python/commitdiff
Issue #13988: cElementTree is deprecated and the _elementtree accelerator is automati...
authorFlorent Xicluna <florent.xicluna@gmail.com>
Mon, 13 Feb 2012 10:03:30 +0000 (11:03 +0100)
committerFlorent Xicluna <florent.xicluna@gmail.com>
Mon, 13 Feb 2012 10:03:30 +0000 (11:03 +0100)
Doc/library/xml.etree.elementtree.rst
Doc/whatsnew/3.3.rst
Lib/test/test_xml_etree.py
Lib/test/test_xml_etree_c.py
Lib/xml/etree/ElementTree.py
Lib/xml/etree/cElementTree.py
Misc/NEWS
Modules/_elementtree.c

index a46d99d969e5e44e8ac44e3a049736725df2c25c..07ec22de89bff3c8218eaac74bdaa56025cd42ed 100644 (file)
@@ -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:
 
index dd2968131b3217aeaa1f66d31adc7b4e3bea9096..8cabab607664d115e629adcad06eecd28e31e0be 100644 (file)
@@ -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
index 36b08cd9c7650f2d42ccb332b39bb092f5fb8554..a0ee377c09e72cfdf3e380e898bcecf6ed309ed5 100644 (file)
@@ -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()
index 2ff118fae88226a25608d7aa4c7d817afc353340..0fed7c11ff07fc31aa4254b8cdbd81d241912400 100644 (file)
@@ -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()
index f94c48c09c7d205a4ff22e86161d592b4b08d14c..93147ebc72a2d2c1315523fb4cf9ebf52f9ac1db 100644 (file)
@@ -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
 
index aaef59e519fdee56d9187b4ba02b242c384655f1..368e679189582990ab92cd73b8b820e74df253a7 100644 (file)
@@ -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 *
index 5503ee9485efc13b5cd7c6140551d6594bdb0598..a70d162ad398bd8878bda690294dc84f68f97805 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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
 -----
 
index af7661eb0c7789d3dcb2bdd6937d1accb2548890..78d8177d68bbf9edb076b942e0ebd9ac989f2fb6 100644 (file)
@@ -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);