diff --git a/pyxform/survey.py b/pyxform/survey.py index 0ff0dd04b..1c902cd4e 100644 --- a/pyxform/survey.py +++ b/pyxform/survey.py @@ -713,8 +713,20 @@ def date_stamp(self): """Returns a date string with the format of %Y_%m_%d.""" return self._created.strftime("%Y_%m_%d") - def _to_ugly_xml(self): - return '' + self.xml().toxml() + def _to_testable_xml(self): + """Preserves attribute ordering across all Python versions. + + See python_test_case.reorder_attributes for related code. + """ + tree = ETree.fromstring(self.xml().toxml()) + for el in tree.iter(): + attrib = el.attrib + if len(attrib) > 1: + # adjust attribute order, e.g. by sorting + attribs = sorted(attrib.items()) + attrib.clear() + attrib.update(attribs) + return ETree.tostring(tree, encoding="utf-8").decode("utf-8") def _to_pretty_xml(self): """ diff --git a/pyxform/tests_v1/pyxform_test_case.py b/pyxform/tests_v1/pyxform_test_case.py index 024ec93cd..112a34e4d 100644 --- a/pyxform/tests_v1/pyxform_test_case.py +++ b/pyxform/tests_v1/pyxform_test_case.py @@ -343,6 +343,8 @@ def reorder_attributes(root): See bottom of https://docs.python.org/3/library/xml.etree.elementtree.html#element-objects and https://github.com/python/cpython/commit/a3697db0102b9b6747fe36009e42f9b08f0c1ea8 for more information. + + See survey._to_testable_xml for related code. """ for el in root.iter(): attrib = el.attrib diff --git a/pyxform/tests_v1/test_dynamic_default.py b/pyxform/tests_v1/test_dynamic_default.py index 0c105b0ce..3769eff8a 100644 --- a/pyxform/tests_v1/test_dynamic_default.py +++ b/pyxform/tests_v1/test_dynamic_default.py @@ -40,7 +40,7 @@ def test_handling_dynamic_default(self): kwargs={"id_string": "id", "name": "dynamic", "title": "some-title"}, autoname=False, ) - survey_xml = survey._to_pretty_xml() + survey_xml = survey._to_testable_xml() self.assertContains(survey_xml, "", 1) self.assertContains(survey_xml, "not_func$", 1) @@ -92,7 +92,7 @@ def test_handling_dynamic_default_in_repeat(self): kwargs={"id_string": "id", "name": "dynamic", "title": "some-title"}, autoname=False, ) - survey_xml = survey._to_pretty_xml() + survey_xml = survey._to_testable_xml() self.assertContains(survey_xml, "not_func$", 2) self.assertContains(survey_xml, "", 2) diff --git a/pyxform/tests_v1/test_whitespace.py b/pyxform/tests_v1/test_whitespace.py index 1e93b51ff..dddcb07d3 100644 --- a/pyxform/tests_v1/test_whitespace.py +++ b/pyxform/tests_v1/test_whitespace.py @@ -30,6 +30,6 @@ def test_values_without_whitespaces_are_processed_successfully(self): survey = self.md_to_pyxform_survey(md_raw=md) expected = """""" - xml = survey._to_pretty_xml() + xml = survey._to_testable_xml() self.assertEqual(1, xml.count(expected)) self.assertPyxformXform(md=md, xml__contains=expected, run_odk_validate=True)