Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions openmc/_xml.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
_LXML_MAX_TEXT_SIZE = 2 * 1024**3 # 2 GB


def _check_text_size(text, context=""):
"""Raise an error if *text* exceeds the lxml 2 GB limit.

Parameters
----------
text : str
Text that will be assigned to an XML element or attribute.
context : str
Human-readable description of what is being written, used in the
error message.

Raises
------
ValueError
If len(text) >= 2 GB.
"""
if len(text) >= _LXML_MAX_TEXT_SIZE:
size_gb = len(text) / 1024**3
raise ValueError(
f"The text content for {context!r} is ~{size_gb:.1f} GB, which "
f"exceeds the lxml limit of 2 GB. lxml will silently produce an "
f"empty element. Consider reducing the number of entries."
)


def clean_indentation(element, level=0, spaces_per_level=2, trailing_indent=True):
"""Set indentation of XML element and its sub-elements.
Copied and pasted from https://effbot.org/zone/element-lib.htm#prettyprint.
Expand Down
11 changes: 8 additions & 3 deletions openmc/cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import openmc
import openmc.checkvalue as cv
from ._xml import get_elem_list, get_text
from ._xml import _check_text_size, get_elem_list, get_text
from .mixin import IDManagerMixin
from .plots import add_plot_params
from .region import Region, Complement
Expand Down Expand Up @@ -640,6 +640,7 @@ def create_xml_subelement(self, xml_element, memo=None):
matlist_str = " ".join(
["void" if m is None else str(m.id) for m in self.fill]
)
_check_text_size(matlist_str, f"cell {self.id} material")
material_subelement.text = matlist_str

elif self.fill_type in ('universe', 'lattice'):
Expand Down Expand Up @@ -681,14 +682,18 @@ def create_surface_elements(node, element, memo=None):
if self.temperature is not None:
if isinstance(self.temperature, Iterable):
temperature_subelement= ET.SubElement(element, "temperature")
temperature_subelement.text = ' '.join(str(t) for t in self.temperature)
text = ' '.join(str(t) for t in self.temperature)
_check_text_size(text, f"cell {self.id} temperature")
temperature_subelement.text = text
else:
element.set("temperature", str(self.temperature))

if self.density is not None:
if isinstance(self.density, Iterable):
density_subelement= ET.SubElement(element, "density")
density_subelement.text = ' '.join(str(d) for d in self.density)
text = ' '.join(str(d) for d in self.density)
_check_text_size(text, f"cell {self.id} density")
density_subelement.text = text
else:
element.set("density", str(self.density))

Expand Down
6 changes: 6 additions & 0 deletions tests/unit_tests/test_cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,3 +433,9 @@ def test_plot(run_in_tmpdir):
# ensure that calling the plot method doesn't
# affect the universe ID space
assert u_before.id + 1 == u_after.id


def test_xml_text_size_check():
from openmc._xml import _check_text_size, _LXML_MAX_TEXT_SIZE
with pytest.raises(ValueError, match="exceeds the lxml limit"):
_check_text_size("x" * _LXML_MAX_TEXT_SIZE, "test element")
Loading