summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2019-03-01 15:11:50 +0100
committerStefan Behnel <stefan_ml@behnel.de>2019-03-01 15:11:50 +0100
commit8027c39cd60a40323eb2ffcfac6bbc102e317a53 (patch)
treee4f8c698e7020f36f7cd37afb4743a66339be764 /src
parentb5c8cab47422346d8dd295afc0f70b956c9424b5 (diff)
downloadpython-lxml-8027c39cd60a40323eb2ffcfac6bbc102e317a53.tar.gz
Keep the original dict insertion order in Py3.6+ when setting attributes or namespaces from a user provided dict.
This follows the ElementTree change in Py3.8, see https://bugs.python.org/issue34160.
Diffstat (limited to 'src')
-rw-r--r--src/lxml/apihelpers.pxi17
-rw-r--r--src/lxml/objectify.pyx2
2 files changed, 15 insertions, 4 deletions
diff --git a/src/lxml/apihelpers.pxi b/src/lxml/apihelpers.pxi
index cf932d43..5d410e60 100644
--- a/src/lxml/apihelpers.pxi
+++ b/src/lxml/apihelpers.pxi
@@ -244,6 +244,10 @@ cdef _iter_nsmap(nsmap):
The difference to _iter_attrib() is that None doesn't sort with strings
in Py3.x.
"""
+ if python.PY_VERSION_HEX >= 0x03060000:
+ # dicts are insertion-ordered in Py3.6+ => keep the user provided order.
+ if isinstance(nsmap, dict):
+ return nsmap.items()
if len(nsmap) <= 1:
return nsmap.items()
# nsmap will usually be a plain unordered dict => avoid type checking overhead
@@ -271,7 +275,10 @@ cdef _iter_attrib(attrib):
Tries to preserve an existing order and sorts if it assumes no order.
"""
# attrib will usually be a plain unordered dict
- if type(attrib) is dict:
+ if isinstance(attrib, dict):
+ if python.PY_VERSION_HEX >= 0x03060000:
+ # dicts are insertion-ordered in Py3.6+ => keep the user provided order.
+ return attrib.items()
return sorted(attrib.items())
elif isinstance(attrib, (_Attrib, OrderedDict)):
return attrib.items()
@@ -292,8 +299,12 @@ cdef _initNodeAttributes(xmlNode* c_node, _Document doc, attrib, dict extra):
is_html = doc._parser._for_html
seen = set()
if extra:
- for name, value in sorted(extra.items()):
- _addAttributeToNode(c_node, doc, is_html, name, value, seen)
+ if python.PY_VERSION_HEX >= 0x03060000:
+ for name, value in extra.items():
+ _addAttributeToNode(c_node, doc, is_html, name, value, seen)
+ else:
+ for name, value in sorted(extra.items()):
+ _addAttributeToNode(c_node, doc, is_html, name, value, seen)
if attrib:
for name, value in _iter_attrib(attrib):
_addAttributeToNode(c_node, doc, is_html, name, value, seen)
diff --git a/src/lxml/objectify.pyx b/src/lxml/objectify.pyx
index f5fe7b51..9da49a1c 100644
--- a/src/lxml/objectify.pyx
+++ b/src/lxml/objectify.pyx
@@ -1327,7 +1327,7 @@ cdef object _dump(_Element element, int indent):
result = f"{indentstr}{element.tag} = {value} [{_typename(element)}]\n"
xsi_ns = u"{%s}" % XML_SCHEMA_INSTANCE_NS
pytype_ns = u"{%s}" % PYTYPE_NAMESPACE
- for name, value in cetree.iterattributes(element, 3):
+ for name, value in sorted(cetree.iterattributes(element, 3)):
if u'{' in name:
if name == PYTYPE_ATTRIBUTE:
if value == TREE_PYTYPE_NAME: