[Python-checkins] bpo-34160: Preserve user specified order of Element attributes (GH-10163)

Raymond Hettinger webhook-mailer at python.org
Sun Oct 28 14:18:26 EDT 2018


https://github.com/python/cpython/commit/e3685fd5fdd8808acda81bfc12fb9702d4b59a60
commit: e3685fd5fdd8808acda81bfc12fb9702d4b59a60
branch: master
author: Raymond Hettinger <rhettinger at users.noreply.github.com>
committer: GitHub <noreply at github.com>
date: 2018-10-28T11:18:22-07:00
summary:

bpo-34160: Preserve user specified order of Element attributes (GH-10163)

files:
A Misc/NEWS.d/next/Library/2018-10-27-21-11-42.bpo-34160.UzyPZf.rst
M Doc/library/xml.etree.elementtree.rst
M Lib/test/test_xml_etree.py
M Lib/xml/etree/ElementTree.py

diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst
index 0cb949a9f481..aae80140374c 100644
--- a/Doc/library/xml.etree.elementtree.rst
+++ b/Doc/library/xml.etree.elementtree.rst
@@ -489,6 +489,10 @@ Functions
 
    *elem* is an element tree or an individual element.
 
+   .. versionchanged:: 3.8
+      The :func:`dump` function now preserves the attribute order specified
+      by the user.
+
 
 .. function:: fromstring(text)
 
@@ -947,6 +951,10 @@ ElementTree Objects
       .. versionadded:: 3.4
          The *short_empty_elements* parameter.
 
+      .. versionchanged:: 3.8
+         The :meth:`write` method now preserves the attribute order specified
+         by the user.
+
 
 This is the XML file that is going to be manipulated::
 
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 8b1690508797..9988dad86384 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -5,6 +5,7 @@
 # For this purpose, the module-level "ET" symbol is temporarily
 # monkey-patched when running the "test_xml_etree_c" test suite.
 
+import contextlib
 import copy
 import functools
 import html
@@ -1044,6 +1045,25 @@ def test_html_empty_elems_serialization(self):
                                        method='html')
                 self.assertEqual(serialized, expected)
 
+    def test_dump_attribute_order(self):
+        # See BPO 34160
+        e = ET.Element('cirriculum', status='public', company='example')
+        with support.captured_stdout() as stdout:
+            ET.dump(e)
+        self.assertEqual(stdout.getvalue(),
+                         '<cirriculum status="public" company="example" />\n')
+
+    def test_tree_write_attribute_order(self):
+        # See BPO 34160
+        root = ET.Element('cirriculum', status='public', company='example')
+        tree = ET.ElementTree(root)
+        f = io.BytesIO()
+        with contextlib.redirect_stdout(f):
+            tree.write(f, encoding='utf-8', xml_declaration=True)
+        self.assertEqual(f.getvalue(),
+                         b"<?xml version='1.0' encoding='utf-8'?>\n"
+                         b'<cirriculum status="public" company="example" />')
+
 
 class XMLPullParserTest(unittest.TestCase):
 
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
index 85586d0b1c49..d4df83fb51cc 100644
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -923,7 +923,7 @@ def _serialize_xml(write, elem, qnames, namespaces,
                             k,
                             _escape_attrib(v)
                             ))
-                for k, v in sorted(items):  # lexical order
+                for k, v in items:
                     if isinstance(k, QName):
                         k = k.text
                     if isinstance(v, QName):
diff --git a/Misc/NEWS.d/next/Library/2018-10-27-21-11-42.bpo-34160.UzyPZf.rst b/Misc/NEWS.d/next/Library/2018-10-27-21-11-42.bpo-34160.UzyPZf.rst
new file mode 100644
index 000000000000..6f3c076d3c03
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-10-27-21-11-42.bpo-34160.UzyPZf.rst
@@ -0,0 +1 @@
+ElementTree now preserves the attribute order specified by the user.



More information about the Python-checkins mailing list