foamlib 0.2.9__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- foamlib/__init__.py +5 -3
- foamlib/_cases.py +20 -32
- foamlib/_files/__init__.py +9 -0
- foamlib/{_dictionaries → _files}/_base.py +9 -11
- foamlib/_files/_fields.py +158 -0
- foamlib/_files/_files.py +203 -0
- foamlib/_files/_io.py +73 -0
- foamlib/_files/_parsing.py +195 -0
- foamlib/_files/_serialization.py +156 -0
- {foamlib-0.2.9.dist-info → foamlib-0.3.0.dist-info}/METADATA +1 -1
- foamlib-0.3.0.dist-info/RECORD +16 -0
- foamlib/_dictionaries/__init__.py +0 -8
- foamlib/_dictionaries/_files.py +0 -422
- foamlib/_dictionaries/_parsing.py +0 -198
- foamlib/_dictionaries/_serialization.py +0 -129
- foamlib-0.2.9.dist-info/RECORD +0 -14
- {foamlib-0.2.9.dist-info → foamlib-0.3.0.dist-info}/LICENSE.txt +0 -0
- {foamlib-0.2.9.dist-info → foamlib-0.3.0.dist-info}/WHEEL +0 -0
- {foamlib-0.2.9.dist-info → foamlib-0.3.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,195 @@
|
|
1
|
+
import sys
|
2
|
+
from typing import Tuple, Union
|
3
|
+
|
4
|
+
if sys.version_info >= (3, 9):
|
5
|
+
from collections.abc import Iterator, Mapping, MutableMapping, Sequence
|
6
|
+
else:
|
7
|
+
from typing import Iterator, Mapping, MutableMapping, Sequence
|
8
|
+
|
9
|
+
if sys.version_info >= (3, 10):
|
10
|
+
from types import EllipsisType
|
11
|
+
else:
|
12
|
+
from typing import Any as EllipsisType
|
13
|
+
|
14
|
+
from pyparsing import (
|
15
|
+
Dict,
|
16
|
+
Forward,
|
17
|
+
Group,
|
18
|
+
Keyword,
|
19
|
+
LineEnd,
|
20
|
+
Literal,
|
21
|
+
Located,
|
22
|
+
Opt,
|
23
|
+
ParserElement,
|
24
|
+
ParseResults,
|
25
|
+
QuotedString,
|
26
|
+
Word,
|
27
|
+
c_style_comment,
|
28
|
+
common,
|
29
|
+
cpp_style_comment,
|
30
|
+
identbodychars,
|
31
|
+
printables,
|
32
|
+
)
|
33
|
+
|
34
|
+
from ._base import FoamDict
|
35
|
+
|
36
|
+
|
37
|
+
def _list_of(entry: ParserElement) -> ParserElement:
|
38
|
+
return Opt(
|
39
|
+
Literal("List") + Literal("<") + common.identifier + Literal(">")
|
40
|
+
).suppress() + (
|
41
|
+
(
|
42
|
+
Opt(common.integer).suppress()
|
43
|
+
+ (
|
44
|
+
Literal("(").suppress()
|
45
|
+
+ Group((entry)[...], aslist=True)
|
46
|
+
+ Literal(")").suppress()
|
47
|
+
)
|
48
|
+
)
|
49
|
+
| (
|
50
|
+
common.integer + Literal("{").suppress() + entry + Literal("}").suppress()
|
51
|
+
).set_parse_action(lambda tks: [[tks[1]] * tks[0]])
|
52
|
+
)
|
53
|
+
|
54
|
+
|
55
|
+
def _dictionary_of(
|
56
|
+
keyword: ParserElement,
|
57
|
+
data_entries: ParserElement,
|
58
|
+
*,
|
59
|
+
len: Union[int, EllipsisType] = ...,
|
60
|
+
located: bool = False,
|
61
|
+
) -> ParserElement:
|
62
|
+
subdict = Forward()
|
63
|
+
|
64
|
+
keyword_entry = keyword + (
|
65
|
+
(Literal("{").suppress() + subdict + Literal("}").suppress())
|
66
|
+
| (data_entries + Literal(";").suppress())
|
67
|
+
)
|
68
|
+
|
69
|
+
if located:
|
70
|
+
keyword_entry = Located(keyword_entry)
|
71
|
+
|
72
|
+
subdict <<= Dict(Group(keyword_entry)[...], asdict=not located)
|
73
|
+
|
74
|
+
return Dict(Group(keyword_entry)[len], asdict=not located)
|
75
|
+
|
76
|
+
|
77
|
+
_SWITCH = (
|
78
|
+
Keyword("yes") | Keyword("true") | Keyword("on") | Keyword("y") | Keyword("t")
|
79
|
+
).set_parse_action(lambda: True) | (
|
80
|
+
Keyword("no") | Keyword("false") | Keyword("off") | Keyword("n") | Keyword("f")
|
81
|
+
).set_parse_action(lambda: False)
|
82
|
+
_DIMENSIONS = (
|
83
|
+
Literal("[").suppress() + common.number * 7 + Literal("]").suppress()
|
84
|
+
).set_parse_action(lambda tks: FoamDict.DimensionSet(*tks))
|
85
|
+
_TENSOR = _list_of(common.number) | common.number
|
86
|
+
_IDENTIFIER = Word(identbodychars + "$", printables.replace(";", ""))
|
87
|
+
_DIMENSIONED = (Opt(_IDENTIFIER) + _DIMENSIONS + _TENSOR).set_parse_action(
|
88
|
+
lambda tks: FoamDict.Dimensioned(*reversed(tks.as_list()))
|
89
|
+
)
|
90
|
+
_FIELD = (Keyword("uniform").suppress() + _TENSOR) | (
|
91
|
+
Keyword("nonuniform").suppress() + _list_of(_TENSOR)
|
92
|
+
)
|
93
|
+
_TOKEN = QuotedString('"', unquote_results=False) | _IDENTIFIER
|
94
|
+
_DATA = Forward()
|
95
|
+
_KEYWORD_ENTRY = _dictionary_of(_TOKEN, _DATA, len=1)
|
96
|
+
_DATA_ENTRY = Forward()
|
97
|
+
_LIST_ENTRY = _KEYWORD_ENTRY | _DATA_ENTRY
|
98
|
+
_LIST = _list_of(_LIST_ENTRY)
|
99
|
+
_DATA_ENTRY <<= (
|
100
|
+
_FIELD | _LIST | _DIMENSIONED | _DIMENSIONS | common.number | _SWITCH | _TOKEN
|
101
|
+
)
|
102
|
+
|
103
|
+
_DATA <<= _DATA_ENTRY[1, ...].set_parse_action(
|
104
|
+
lambda tks: tuple(tks) if len(tks) > 1 else [tks[0]]
|
105
|
+
)
|
106
|
+
|
107
|
+
_FILE = (
|
108
|
+
_dictionary_of(_TOKEN, Opt(_DATA, default=""), located=True)
|
109
|
+
.ignore(c_style_comment)
|
110
|
+
.ignore(cpp_style_comment)
|
111
|
+
.ignore(Literal("#include") + ... + LineEnd()) # type: ignore [no-untyped-call]
|
112
|
+
)
|
113
|
+
|
114
|
+
|
115
|
+
class Parsed(Mapping[Tuple[str, ...], Union[FoamDict.Data, EllipsisType]]):
|
116
|
+
def __init__(self, contents: str) -> None:
|
117
|
+
self._parsed: MutableMapping[
|
118
|
+
Tuple[str, ...],
|
119
|
+
Tuple[int, Union[FoamDict.Data, EllipsisType], int],
|
120
|
+
] = {}
|
121
|
+
for parse_result in _FILE.parse_string(contents, parse_all=True):
|
122
|
+
self._parsed.update(self._flatten_result(parse_result))
|
123
|
+
|
124
|
+
@staticmethod
|
125
|
+
def _flatten_result(
|
126
|
+
parse_result: ParseResults, *, _keywords: Tuple[str, ...] = ()
|
127
|
+
) -> Mapping[Tuple[str, ...], Tuple[int, Union[FoamDict.Data, EllipsisType], int]]:
|
128
|
+
ret: MutableMapping[
|
129
|
+
Tuple[str, ...],
|
130
|
+
Tuple[int, Union[FoamDict.Data, EllipsisType], int],
|
131
|
+
] = {}
|
132
|
+
start = parse_result.locn_start
|
133
|
+
assert isinstance(start, int)
|
134
|
+
item = parse_result.value
|
135
|
+
assert isinstance(item, Sequence)
|
136
|
+
end = parse_result.locn_end
|
137
|
+
assert isinstance(end, int)
|
138
|
+
keyword, *data = item
|
139
|
+
assert isinstance(keyword, str)
|
140
|
+
ret[(*_keywords, keyword)] = (start, ..., end)
|
141
|
+
for d in data:
|
142
|
+
if isinstance(d, ParseResults):
|
143
|
+
ret.update(Parsed._flatten_result(d, _keywords=(*_keywords, keyword)))
|
144
|
+
else:
|
145
|
+
ret[(*_keywords, keyword)] = (start, d, end)
|
146
|
+
return ret
|
147
|
+
|
148
|
+
def __getitem__(
|
149
|
+
self, keywords: Tuple[str, ...]
|
150
|
+
) -> Union[FoamDict.Data, EllipsisType]:
|
151
|
+
_, data, _ = self._parsed[keywords]
|
152
|
+
return data
|
153
|
+
|
154
|
+
def __contains__(self, keywords: object) -> bool:
|
155
|
+
return keywords in self._parsed
|
156
|
+
|
157
|
+
def __iter__(self) -> Iterator[Tuple[str, ...]]:
|
158
|
+
return iter(self._parsed)
|
159
|
+
|
160
|
+
def __len__(self) -> int:
|
161
|
+
return len(self._parsed)
|
162
|
+
|
163
|
+
def entry_location(
|
164
|
+
self, keywords: Tuple[str, ...], *, missing_ok: bool = False
|
165
|
+
) -> Tuple[int, int]:
|
166
|
+
try:
|
167
|
+
start, _, end = self._parsed[keywords]
|
168
|
+
except KeyError:
|
169
|
+
if missing_ok:
|
170
|
+
if len(keywords) > 1:
|
171
|
+
_, _, end = self._parsed[keywords[:-1]]
|
172
|
+
end -= 1
|
173
|
+
else:
|
174
|
+
end = -1
|
175
|
+
|
176
|
+
start = end
|
177
|
+
else:
|
178
|
+
raise
|
179
|
+
|
180
|
+
return start, end
|
181
|
+
|
182
|
+
def as_dict(self) -> FoamDict._Dict:
|
183
|
+
ret: FoamDict._Dict = {}
|
184
|
+
for keywords, (_, data, _) in self._parsed.items():
|
185
|
+
r = ret
|
186
|
+
for k in keywords[:-1]:
|
187
|
+
assert isinstance(r, dict)
|
188
|
+
v = r[k]
|
189
|
+
assert isinstance(v, dict)
|
190
|
+
r = v
|
191
|
+
|
192
|
+
assert isinstance(r, dict)
|
193
|
+
r[keywords[-1]] = {} if data is ... else data # type: ignore [assignment]
|
194
|
+
|
195
|
+
return ret
|
@@ -0,0 +1,156 @@
|
|
1
|
+
import sys
|
2
|
+
from contextlib import suppress
|
3
|
+
|
4
|
+
if sys.version_info >= (3, 9):
|
5
|
+
from collections.abc import Mapping
|
6
|
+
else:
|
7
|
+
from typing import Mapping
|
8
|
+
|
9
|
+
from .._util import is_sequence
|
10
|
+
from ._base import FoamDict
|
11
|
+
|
12
|
+
|
13
|
+
def _serialize_switch(data: FoamDict._SetData) -> str:
|
14
|
+
if data is True:
|
15
|
+
return "yes"
|
16
|
+
elif data is False:
|
17
|
+
return "no"
|
18
|
+
else:
|
19
|
+
raise TypeError(f"Not a bool: {type(data)}")
|
20
|
+
|
21
|
+
|
22
|
+
def _serialize_list(
|
23
|
+
data: FoamDict._SetData,
|
24
|
+
) -> str:
|
25
|
+
if is_sequence(data):
|
26
|
+
return f"({' '.join(_serialize_data_entry(v) for v in data)})"
|
27
|
+
else:
|
28
|
+
raise TypeError(f"Not a valid sequence: {type(data)}")
|
29
|
+
|
30
|
+
|
31
|
+
def _serialize_field(
|
32
|
+
data: FoamDict._SetData,
|
33
|
+
) -> str:
|
34
|
+
if is_sequence(data):
|
35
|
+
try:
|
36
|
+
s = _serialize_list(data)
|
37
|
+
except TypeError:
|
38
|
+
raise TypeError(f"Not a valid field: {type(data)}") from None
|
39
|
+
else:
|
40
|
+
if not is_sequence(data[0]) and len(data) < 10:
|
41
|
+
return f"uniform {s}"
|
42
|
+
else:
|
43
|
+
if not is_sequence(data[0]):
|
44
|
+
kind = "scalar"
|
45
|
+
elif len(data[0]) == 3:
|
46
|
+
kind = "vector"
|
47
|
+
elif len(data[0]) == 6:
|
48
|
+
kind = "symmTensor"
|
49
|
+
elif len(data[0]) == 9:
|
50
|
+
kind = "tensor"
|
51
|
+
else:
|
52
|
+
raise TypeError(
|
53
|
+
f"Unsupported sequence length for field: {len(data[0])}"
|
54
|
+
)
|
55
|
+
return f"nonuniform List<{kind}> {len(data)}{s}"
|
56
|
+
else:
|
57
|
+
return f"uniform {data}"
|
58
|
+
|
59
|
+
|
60
|
+
def _serialize_dimensions(
|
61
|
+
data: FoamDict._SetData,
|
62
|
+
) -> str:
|
63
|
+
if is_sequence(data) and len(data) == 7:
|
64
|
+
return f"[{' '.join(str(v) for v in data)}]"
|
65
|
+
else:
|
66
|
+
raise TypeError(f"Not a valid dimension set: {type(data)}")
|
67
|
+
|
68
|
+
|
69
|
+
def _serialize_dimensioned(
|
70
|
+
data: FoamDict._SetData,
|
71
|
+
) -> str:
|
72
|
+
if isinstance(data, FoamDict.Dimensioned):
|
73
|
+
if data.name is not None:
|
74
|
+
return f"{data.name} {_serialize_dimensions(data.dimensions)} {_serialize_data_entry(data.value)}"
|
75
|
+
else:
|
76
|
+
return f"{_serialize_dimensions(data.dimensions)} {_serialize_data_entry(data.value)}"
|
77
|
+
else:
|
78
|
+
raise TypeError(f"Not a valid dimensioned value: {type(data)}")
|
79
|
+
|
80
|
+
|
81
|
+
def _serialize_data_entry(
|
82
|
+
data: FoamDict._SetData,
|
83
|
+
*,
|
84
|
+
assume_field: bool = False,
|
85
|
+
assume_dimensions: bool = False,
|
86
|
+
) -> str:
|
87
|
+
if isinstance(data, FoamDict.DimensionSet) or assume_dimensions:
|
88
|
+
with suppress(TypeError):
|
89
|
+
return _serialize_dimensions(data)
|
90
|
+
|
91
|
+
if assume_field:
|
92
|
+
with suppress(TypeError):
|
93
|
+
return _serialize_field(data)
|
94
|
+
|
95
|
+
with suppress(TypeError):
|
96
|
+
return _serialize_dimensioned(data)
|
97
|
+
|
98
|
+
with suppress(TypeError):
|
99
|
+
return _serialize_list(data)
|
100
|
+
|
101
|
+
with suppress(TypeError):
|
102
|
+
return _serialize_switch(data)
|
103
|
+
|
104
|
+
with suppress(TypeError):
|
105
|
+
return _serialize_dictionary(data)
|
106
|
+
|
107
|
+
return str(data)
|
108
|
+
|
109
|
+
|
110
|
+
def _serialize_data_entries(
|
111
|
+
data: FoamDict._SetData,
|
112
|
+
*,
|
113
|
+
assume_field: bool = False,
|
114
|
+
assume_dimensions: bool = False,
|
115
|
+
) -> str:
|
116
|
+
if isinstance(data, FoamDict.DimensionSet) or assume_dimensions:
|
117
|
+
with suppress(TypeError):
|
118
|
+
return _serialize_dimensions(data)
|
119
|
+
|
120
|
+
if assume_field:
|
121
|
+
with suppress(TypeError):
|
122
|
+
return _serialize_field(data)
|
123
|
+
|
124
|
+
if isinstance(data, tuple):
|
125
|
+
return " ".join(_serialize_data_entry(v) for v in data)
|
126
|
+
|
127
|
+
return _serialize_data_entry(data)
|
128
|
+
|
129
|
+
|
130
|
+
def _serialize_dictionary(
|
131
|
+
data: FoamDict._SetData,
|
132
|
+
) -> str:
|
133
|
+
if isinstance(data, Mapping):
|
134
|
+
return "\n".join(serialize_keyword_entry(k, v) for k, v in data.items())
|
135
|
+
else:
|
136
|
+
raise TypeError(f"Not a valid dictionary: {type(data)}")
|
137
|
+
|
138
|
+
|
139
|
+
def serialize_keyword_entry(
|
140
|
+
keyword: str,
|
141
|
+
data: FoamDict._SetData,
|
142
|
+
*,
|
143
|
+
assume_field: bool = False,
|
144
|
+
assume_dimensions: bool = False,
|
145
|
+
) -> str:
|
146
|
+
with suppress(TypeError):
|
147
|
+
return f"{keyword}\n{{\n{_serialize_dictionary(data)}\n}}"
|
148
|
+
|
149
|
+
data = _serialize_data_entries(
|
150
|
+
data, assume_field=assume_field, assume_dimensions=assume_dimensions
|
151
|
+
)
|
152
|
+
|
153
|
+
if not data:
|
154
|
+
return f"{keyword};"
|
155
|
+
else:
|
156
|
+
return f"{keyword} {data};"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
foamlib/__init__.py,sha256=erRnbigN4XBPDC0ykv-Lw7LVsw_xtuJ7h0tgkBTNQZ8,381
|
2
|
+
foamlib/_cases.py,sha256=SkUthKb98zXPMYACaGyfGC0Fo1jzD6cC4qEGesHfNfc,20554
|
3
|
+
foamlib/_util.py,sha256=PBTpBwt_j1GXASncSDZUR8pH2u_h8UyJXm8GeFKebTY,2552
|
4
|
+
foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
foamlib/_files/__init__.py,sha256=m4y_7wFV2Voly1aJrTYALjT3S1Aq7EbaijxdGFbJrmU,160
|
6
|
+
foamlib/_files/_base.py,sha256=vONemjJA-NxRuIjuxwz8PynjtF1UImrfBQm1EbgZEec,1768
|
7
|
+
foamlib/_files/_fields.py,sha256=jZZiMoBn0tixGnUGpITpRxcauqhPvYk65PIktBFvEHk,5073
|
8
|
+
foamlib/_files/_files.py,sha256=1fV1TUwtNsxzt1R1YKMbB_AGpjMl-W-7YQXl7Ynoyzc,6025
|
9
|
+
foamlib/_files/_io.py,sha256=alxMyxQh0zb6BZYqomZwOo9dQujMpRuS5yfpIKBEnaM,1976
|
10
|
+
foamlib/_files/_parsing.py,sha256=blyt1kpYruoW5I6DMDg8jhg6f5oz7gzedmAImuJ5b4k,5966
|
11
|
+
foamlib/_files/_serialization.py,sha256=kbl1OTvWqHwcDwS2k5CuqjDRmiv3NpA9hIXyv4boWBA,4268
|
12
|
+
foamlib-0.3.0.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
|
13
|
+
foamlib-0.3.0.dist-info/METADATA,sha256=hl5EKAs6_mbW-1qcuIFst4I6tDQqCkG4LyZlx3DMhZY,4650
|
14
|
+
foamlib-0.3.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
15
|
+
foamlib-0.3.0.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
|
16
|
+
foamlib-0.3.0.dist-info/RECORD,,
|