OrderedDict attributes no longer work in python 2.7

Bug #1838252 reported by Cosimo Lupo on 2019-07-29
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
lxml
Low
scoder

Bug Description

Up until lxml 4.3.5, I could pass an OrderedDict as an etree.Element's attributes to ensure that when serialized to XML, it would keep the order of the attributes:

    In [1]: from lxml import etree

    In [2]: from collections import OrderedDict

    In [3]: e = etree.Element("glyph", OrderedDict([("name", "a"), ("format", "2")]))

    In [4]: etree.tostring(e)
    Out[4]: '<glyph name="a" format="2"/>'

After upgrading to lxml 4.4.0, I know always get the attributes sorted alphabetically:

    Out[4]: '<glyph format="2" name="a"/>'

Note that this only happens with version 4.4.0 under python 2.7. It does _not_ also happen with python 3. In the latter case, I am still able to preserve the attributes order when passing an OrderedDict to Element constructor.

Is this a regression or a deliberate change?
I still maintain a py2.py3 codebase and would like to keep the old behavior if possible.
Thank you.

## -- LXML SYSTEM INFO

Python : sys.version_info(major=2, minor=7, micro=16, releaselevel='final', serial=0)
lxml.etree : (4, 4, 0, 0)
libxml used : (2, 9, 9)
libxml compiled : (2, 9, 9)
libxslt used : (1, 1, 33)
libxslt compiled : (1, 1, 33)
## ------

Cosimo Lupo (lupocos) wrote :

I just noticed the issue happens on python 3.5 as well, not only python 2.7.
I suspect that in the latest lxml 4.4.0, the attributes that are passed to the Element constructor are casted to a built-in dict, and the latter remembers the insertion order from >= python 3.6.

scoder (scoder) wrote :

Thanks for the report. It's not intended. The bug is here:

https://github.com/lxml/lxml/blob/master/src/lxml/apihelpers.pxi#L290-L305

Note how the inheritance test first checks for "dict", then for "OrderedDict". Sadly, "OrderedDict" inherits from "dict", so the second branch is never taken for it.

Changed in lxml:
milestone: none → 4.4.1
status: New → Confirmed
scoder (scoder) wrote :
Changed in lxml:
assignee: nobody → scoder (scoder)
status: Confirmed → Fix Committed
Cosimo Lupo (lupocos) wrote :

Thank you very much for the quick fix! :)
I look forward to the next release.

scoder (scoder) on 2019-08-15
Changed in lxml:
importance: Undecided → Low
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers