diff --git a/openmc/_xml.py b/openmc/_xml.py index b49d192097..32679fd89e 100644 --- a/openmc/_xml.py +++ b/openmc/_xml.py @@ -43,3 +43,21 @@ def get_text(elem, name, default=None): else: child = elem.find(name) return child.text if child is not None else default + + +def reorder_attributes(root): + """Sort attributes in XML to preserve pre-Python 3.8 behavior + + Parameters + ---------- + root : xml.etree.ElementTree.Element + Root element + + """ + for el in root.iter(): + attrib = el.attrib + if len(attrib) > 1: + # adjust attribute order, e.g. by sorting + attribs = sorted(attrib.items()) + attrib.clear() + attrib.update(attribs) diff --git a/openmc/data/library.py b/openmc/data/library.py index a66260b929..cd0fe0895b 100644 --- a/openmc/data/library.py +++ b/openmc/data/library.py @@ -5,7 +5,7 @@ import pathlib import h5py from openmc.mixin import EqualityMixin -from openmc._xml import clean_indentation +from openmc._xml import clean_indentation, reorder_attributes class DataLibrary(EqualityMixin): @@ -112,6 +112,7 @@ class DataLibrary(EqualityMixin): clean_indentation(root) # Write XML file + reorder_attributes(root) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root) tree.write(str(path), xml_declaration=True, encoding='utf-8', method='xml') diff --git a/openmc/geometry.py b/openmc/geometry.py index 450f223b19..3becde9a7a 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -110,6 +110,7 @@ class Geometry: p /= 'geometry.xml' # Write the XML Tree to the geometry.xml file + xml.reorder_attributes(root_element) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8') diff --git a/openmc/material.py b/openmc/material.py index 92f5132c52..2ab36cf7e8 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -12,7 +12,7 @@ import numpy as np import openmc import openmc.data import openmc.checkvalue as cv -from ._xml import clean_indentation +from ._xml import clean_indentation, reorder_attributes from .mixin import IDManagerMixin @@ -1239,6 +1239,7 @@ class Materials(cv.CheckedList): clean_indentation(element, level=1) element.tail = element.tail.strip(' ') fh.write(' ') + reorder_attributes(element) # TODO: Remove when support is Python 3.8+ ET.ElementTree(element).write(fh, encoding='unicode') # Write the elements. @@ -1247,6 +1248,7 @@ class Materials(cv.CheckedList): clean_indentation(element, level=1) element.tail = element.tail.strip(' ') fh.write(' ') + reorder_attributes(element) # TODO: Remove when support is Python 3.8+ ET.ElementTree(element).write(fh, encoding='unicode') # Write the closing tag for the root element. diff --git a/openmc/plots.py b/openmc/plots.py index 05ce684df9..33020c48a9 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -8,7 +8,7 @@ import numpy as np import openmc import openmc.checkvalue as cv -from ._xml import clean_indentation +from ._xml import clean_indentation, reorder_attributes from .mixin import IDManagerMixin @@ -844,5 +844,6 @@ class Plots(cv.CheckedList): p /= 'plots.xml' # Write the XML Tree to the plots.xml file + reorder_attributes(self._plots_file) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(self._plots_file) tree.write(str(p), xml_declaration=True, encoding='utf-8') diff --git a/openmc/settings.py b/openmc/settings.py index 6774427554..16d4e9578d 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -6,7 +6,7 @@ from xml.etree import ElementTree as ET import openmc.checkvalue as cv from . import VolumeCalculation, Source, RegularMesh -from ._xml import clean_indentation, get_text +from ._xml import clean_indentation, get_text, reorder_attributes class RunMode(Enum): @@ -1375,6 +1375,7 @@ class Settings: p /= 'settings.xml' # Write the XML Tree to the settings.xml file + reorder_attributes(root_element) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8') diff --git a/openmc/tallies.py b/openmc/tallies.py index cf09c14161..646482ede9 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -14,7 +14,7 @@ import scipy.sparse as sps import openmc import openmc.checkvalue as cv -from ._xml import clean_indentation +from ._xml import clean_indentation, reorder_attributes from .mixin import IDManagerMixin @@ -3143,5 +3143,6 @@ class Tallies(cv.CheckedList): p /= 'tallies.xml' # Write the XML Tree to the tallies.xml file + reorder_attributes(root_element) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8')