leforestier / yattag

Python library to generate HTML or XML in a readable, concise and pythonic way.
333 stars 31 forks source link

attributes order #60

Closed jan-spurny closed 1 year ago

jan-spurny commented 4 years ago

I run into a problem when porting our software from python2 to python3 - there are unittests which just compare html output (str) of yattag to stored html files - and now all these tests started to fail because html attributes in yattag are represented by dict, so in python3 versions prior to 3.7 (I think), final attribute order is randomized, which results in failing tests. For example:

$ cat example.py 
from yattag import Doc

doc, tag, text = Doc().tagtext()
with tag('html'):
    with tag('body'):
        doc.attr(klass = 'foo', a = 'bar', b = 'baz')
print(doc.getvalue())

$ python example.py 
<html><body a="bar" b="baz" class="foo"></body></html>
$ python example.py 
<html><body a="bar" class="foo" b="baz"></body></html>
$ python example.py 
<html><body b="baz" a="bar" class="foo"></body></html>
$ python example.py 
<html><body class="foo" b="baz" a="bar"></body></html>

Would it be possible to add something like order_attrs: bool=False optional parameter to Doc.get_value() or something similar to make order (and therefore resulting text) predictable?

leforestier commented 4 years ago

Hi Jan, yes, only from Python 3.6 is the order of keyword arguments preserved. Not much we can do about that. But you can change how you test. Have a look at how I wrote the tests here: https://github.com/leforestier/yattag/blob/master/test/tests_simpledoc.py I used xml.etree.ElementTree to parse the strings returned by getvalue(). You could do the same: parse the resulting strings and check that the attributes of the nodes are the attributes you expect.