Skip to content
Draft
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
2 changes: 2 additions & 0 deletions foamlib/_files/_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
MutableSubDict,
StandaloneData,
StandaloneDataLike,
StringDimensionSet,
SubDict,
SubDictLike,
)
Expand Down Expand Up @@ -118,6 +119,7 @@ class FoamFile(

Dimensioned = Dimensioned
DimensionSet = DimensionSet
StringDimensionSet = StringDimensionSet

class SubDict(
MutableMapping[str, Union[Data, MutableSubDict]],
Expand Down
15 changes: 13 additions & 2 deletions foamlib/_files/_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,20 @@ def _keyword_entry_of(
| Keyword("false", _IDENTBODYCHARS)
| Keyword("off", _IDENTBODYCHARS)
).set_parse_action(lambda: False)

# Parser for string-based dimension units (e.g., Pa, mm^2, s^-2)
_UNIT_CHARS = printables.replace("[", "").replace("]", "").replace(";", "")
_UNIT_STRING = (
Word(_UNIT_CHARS)[1, ...].set_parse_action(lambda tks: " ".join(tks))
)

_DIMENSIONS = (
Literal("[").suppress() + common.number[0, 7] + Literal("]").suppress()
).set_parse_action(lambda tks: DimensionSet(*tks))
# Numeric dimensions: [1 -1 -2 0 0 0 0]
(Literal("[").suppress() + common.number[0, 7] + Literal("]").suppress()).set_parse_action(lambda tks: DimensionSet(*tks))
|
# String-based units: [ Pa ] or [Pa mm^2 s^-2]
(Literal("[").suppress() + _UNIT_STRING + Literal("]").suppress()).set_parse_action(lambda tks: tks[0])
)
_TENSOR = common.ieee_float | (
Literal("(").suppress()
+ Group(common.ieee_float[3] | common.ieee_float[6] | common.ieee_float[9])
Expand Down
28 changes: 24 additions & 4 deletions foamlib/_files/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,29 @@
]


class StringDimensionSet:

Check failure on line 84 in foamlib/_files/_types.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (PLW1641)

foamlib/_files/_types.py:84:7: PLW1641 Object does not implement `__hash__` method

Check failure on line 84 in foamlib/_files/_types.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (PLW1641)

foamlib/_files/_types.py:84:7: PLW1641 Object does not implement `__hash__` method
"""Represents string-based dimensions like 'Pa', 'mm^2 s^-2', etc."""

Check failure on line 86 in foamlib/_files/_types.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

foamlib/_files/_types.py:86:1: W293 Blank line contains whitespace

Check failure on line 86 in foamlib/_files/_types.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

foamlib/_files/_types.py:86:1: W293 Blank line contains whitespace
def __init__(self, units: str) -> None:
self.units = units

Check failure on line 89 in foamlib/_files/_types.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

foamlib/_files/_types.py:89:1: W293 Blank line contains whitespace

Check failure on line 89 in foamlib/_files/_types.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

foamlib/_files/_types.py:89:1: W293 Blank line contains whitespace
def __repr__(self) -> str:
return f"StringDimensionSet('{self.units}')"

Check failure on line 92 in foamlib/_files/_types.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

foamlib/_files/_types.py:92:1: W293 Blank line contains whitespace

Check failure on line 92 in foamlib/_files/_types.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

foamlib/_files/_types.py:92:1: W293 Blank line contains whitespace
def __eq__(self, other: object) -> bool:
if isinstance(other, StringDimensionSet):
return self.units == other.units
return False

Check failure on line 97 in foamlib/_files/_types.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

foamlib/_files/_types.py:97:1: W293 Blank line contains whitespace

Check failure on line 97 in foamlib/_files/_types.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

foamlib/_files/_types.py:97:1: W293 Blank line contains whitespace
def __str__(self) -> str:
return self.units


class Dimensioned:
def __init__(
self,
value: TensorLike,
dimensions: DimensionSet | Sequence[float],
dimensions: DimensionSet | StringDimensionSet | Sequence[float] | str,
name: str | None = None,
) -> None:
if is_sequence(value):
Expand All @@ -94,10 +112,12 @@
assert isinstance(value, (int, float, np.ndarray))
self.value = float(value)

if not isinstance(dimensions, DimensionSet):
self.dimensions = DimensionSet(*dimensions)
else:
if isinstance(dimensions, str):
self.dimensions = StringDimensionSet(dimensions)
elif isinstance(dimensions, (DimensionSet, StringDimensionSet)):
self.dimensions = dimensions
else:
self.dimensions = DimensionSet(*dimensions)

self.name = name

Expand Down
37 changes: 37 additions & 0 deletions tests/test_files/test_parsing/test_loads.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,40 @@
assert np.array_equal(
faces[1][faces[0][1] : faces[0][2]], [3516631, 3516634, 3516633, 3516632]
)


def test_string_dimensions() -> None:
"""Test parsing of string-based dimensions like [ Pa ], addressing issue #332."""
# Test simple string dimensions
assert FoamFile.loads("[ Pa ]") == "Pa"
assert FoamFile.loads("[Pa]") == "Pa"

Check failure on line 110 in tests/test_files/test_parsing/test_loads.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

tests/test_files/test_parsing/test_loads.py:110:1: W293 Blank line contains whitespace

Check failure on line 110 in tests/test_files/test_parsing/test_loads.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

tests/test_files/test_parsing/test_loads.py:110:1: W293 Blank line contains whitespace
# Test complex string dimensions
assert FoamFile.loads("[Pa mm^2 s^-2]") == "Pa mm^2 s^-2"
assert FoamFile.loads("[ kg m s^-2 ]") == "kg m s^-2"

Check failure on line 114 in tests/test_files/test_parsing/test_loads.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

tests/test_files/test_parsing/test_loads.py:114:1: W293 Blank line contains whitespace

Check failure on line 114 in tests/test_files/test_parsing/test_loads.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

tests/test_files/test_parsing/test_loads.py:114:1: W293 Blank line contains whitespace
# Test string dimensions in dimensioned values
dimensioned = FoamFile.loads("g [ Pa ] 9.81")
assert isinstance(dimensioned, FoamFile.Dimensioned)
assert isinstance(dimensioned.dimensions, FoamFile.StringDimensionSet)
assert dimensioned.dimensions.units == "Pa"
assert dimensioned.value == 9.81
assert dimensioned.name == "g"

Check failure on line 122 in tests/test_files/test_parsing/test_loads.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

tests/test_files/test_parsing/test_loads.py:122:1: W293 Blank line contains whitespace

Check failure on line 122 in tests/test_files/test_parsing/test_loads.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

tests/test_files/test_parsing/test_loads.py:122:1: W293 Blank line contains whitespace
# Test that numeric dimensions still work as before
assert FoamFile.loads("[1 1 -2 0 0 0 0]") == FoamFile.DimensionSet(
mass=1, length=1, time=-2
)

Check failure on line 127 in tests/test_files/test_parsing/test_loads.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

tests/test_files/test_parsing/test_loads.py:127:1: W293 Blank line contains whitespace

Check failure on line 127 in tests/test_files/test_parsing/test_loads.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (W293)

tests/test_files/test_parsing/test_loads.py:127:1: W293 Blank line contains whitespace
# Test in a dictionary context (the original issue scenario)
result = FoamFile.loads("""
functions
{
test
{
type exprField;
dimensions [ Pa ];
}
}
""")
assert result["functions"]["test"]["dimensions"] == "Pa"
Loading