foamlib 0.3.3__py3-none-any.whl → 0.3.5__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 +1 -1
- foamlib/_cases.py +3 -13
- foamlib/_files/__init__.py +1 -2
- foamlib/_files/_files.py +173 -36
- foamlib/_files/_io.py +8 -5
- foamlib/_files/_parsing.py +61 -4
- foamlib/_files/_serialization.py +67 -49
- foamlib/_util.py +14 -6
- {foamlib-0.3.3.dist-info → foamlib-0.3.5.dist-info}/METADATA +13 -3
- foamlib-0.3.5.dist-info/RECORD +15 -0
- foamlib/_files/_fields.py +0 -165
- foamlib-0.3.3.dist-info/RECORD +0 -16
- {foamlib-0.3.3.dist-info → foamlib-0.3.5.dist-info}/LICENSE.txt +0 -0
- {foamlib-0.3.3.dist-info → foamlib-0.3.5.dist-info}/WHEEL +0 -0
- {foamlib-0.3.3.dist-info → foamlib-0.3.5.dist-info}/top_level.txt +0 -0
foamlib/__init__.py
CHANGED
foamlib/_cases.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
import asyncio
|
2
2
|
import multiprocessing
|
3
|
-
import os
|
4
3
|
import shutil
|
5
4
|
import sys
|
6
5
|
from contextlib import asynccontextmanager
|
@@ -17,13 +16,12 @@ if sys.version_info >= (3, 9):
|
|
17
16
|
Callable,
|
18
17
|
Collection,
|
19
18
|
Iterator,
|
20
|
-
Mapping,
|
21
19
|
Sequence,
|
22
20
|
Set,
|
23
21
|
)
|
24
22
|
else:
|
25
23
|
from typing import AbstractSet as Set
|
26
|
-
from typing import AsyncGenerator, Callable, Collection, Iterator,
|
24
|
+
from typing import AsyncGenerator, Callable, Collection, Iterator, Sequence
|
27
25
|
|
28
26
|
import aioshutil
|
29
27
|
|
@@ -87,7 +85,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
|
87
85
|
return str(self.path)
|
88
86
|
|
89
87
|
def __repr__(self) -> str:
|
90
|
-
return f"{type(self).
|
88
|
+
return f"{type(self).__qualname__}('{self.path}')"
|
91
89
|
|
92
90
|
def __str__(self) -> str:
|
93
91
|
return str(self.path)
|
@@ -203,12 +201,6 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
|
203
201
|
else:
|
204
202
|
return None
|
205
203
|
|
206
|
-
def _env(self) -> Mapping[str, str]:
|
207
|
-
"""Return the environment variables for this case."""
|
208
|
-
env = os.environ.copy()
|
209
|
-
env["PWD"] = str(self.path)
|
210
|
-
return env
|
211
|
-
|
212
204
|
def _parallel_cmd(
|
213
205
|
self, cmd: Union[Sequence[Union[str, Path]], str, Path]
|
214
206
|
) -> Union[Sequence[Union[str, Path]], str]:
|
@@ -298,7 +290,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
|
298
290
|
return str(self.path)
|
299
291
|
|
300
292
|
def __repr__(self) -> str:
|
301
|
-
return f"{type(self).
|
293
|
+
return f"{type(self).__qualname__}('{self.path}')"
|
302
294
|
|
303
295
|
def __str__(self) -> str:
|
304
296
|
return str(self.path)
|
@@ -359,7 +351,6 @@ class FoamCase(FoamCaseBase):
|
|
359
351
|
cmd,
|
360
352
|
check=check,
|
361
353
|
cwd=self.path,
|
362
|
-
env=self._env(),
|
363
354
|
)
|
364
355
|
else:
|
365
356
|
script_path = self._run_script(parallel=parallel) if script else None
|
@@ -522,7 +513,6 @@ class AsyncFoamCase(FoamCaseBase):
|
|
522
513
|
cmd,
|
523
514
|
check=check,
|
524
515
|
cwd=self.path,
|
525
|
-
env=self._env(),
|
526
516
|
)
|
527
517
|
else:
|
528
518
|
script_path = self._run_script(parallel=parallel) if script else None
|
foamlib/_files/__init__.py
CHANGED
foamlib/_files/_files.py
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
import sys
|
2
|
-
from typing import
|
3
|
-
Any,
|
4
|
-
Tuple,
|
5
|
-
Union,
|
6
|
-
)
|
2
|
+
from typing import Any, Tuple, Union, cast
|
7
3
|
|
8
4
|
if sys.version_info >= (3, 9):
|
9
|
-
from collections.abc import Iterator, Mapping, MutableMapping
|
5
|
+
from collections.abc import Iterator, Mapping, MutableMapping, Sequence
|
10
6
|
else:
|
11
|
-
from typing import Iterator, Mapping, MutableMapping
|
7
|
+
from typing import Iterator, Mapping, MutableMapping, Sequence
|
12
8
|
|
13
9
|
from ._base import FoamDict
|
14
10
|
from ._io import FoamFileIO
|
15
|
-
from ._serialization import
|
11
|
+
from ._serialization import Kind, dumpb
|
12
|
+
|
13
|
+
try:
|
14
|
+
import numpy as np
|
15
|
+
except ModuleNotFoundError:
|
16
|
+
pass
|
16
17
|
|
17
18
|
|
18
19
|
class FoamFile(
|
@@ -45,23 +46,12 @@ class FoamFile(
|
|
45
46
|
) -> Union["FoamFile.Data", "FoamFile.SubDict"]:
|
46
47
|
return self._file[(*self._keywords, keyword)]
|
47
48
|
|
48
|
-
def
|
49
|
+
def __setitem__(
|
49
50
|
self,
|
50
51
|
keyword: str,
|
51
|
-
data:
|
52
|
-
*,
|
53
|
-
assume_field: bool = False,
|
54
|
-
assume_dimensions: bool = False,
|
52
|
+
data: "FoamFile._SetData",
|
55
53
|
) -> None:
|
56
|
-
self._file.
|
57
|
-
(*self._keywords, keyword),
|
58
|
-
data,
|
59
|
-
assume_field=assume_field,
|
60
|
-
assume_dimensions=assume_dimensions,
|
61
|
-
)
|
62
|
-
|
63
|
-
def __setitem__(self, keyword: str, value: "FoamFile._SetData") -> None:
|
64
|
-
self._setitem(keyword, value)
|
54
|
+
self._file[(*self._keywords, keyword)] = data
|
65
55
|
|
66
56
|
def __delitem__(self, keyword: str) -> None:
|
67
57
|
del self._file[(*self._keywords, keyword)]
|
@@ -84,7 +74,7 @@ class FoamFile(
|
|
84
74
|
super().clear()
|
85
75
|
|
86
76
|
def __repr__(self) -> str:
|
87
|
-
return f"{type(self).__qualname__}({self._file}, {self._keywords})"
|
77
|
+
return f"{type(self).__qualname__}('{self._file}', {self._keywords})"
|
88
78
|
|
89
79
|
def as_dict(self) -> FoamDict._Dict:
|
90
80
|
"""Return a nested dict representation of the dictionary."""
|
@@ -113,7 +103,11 @@ class FoamFile(
|
|
113
103
|
else:
|
114
104
|
return value # type: ignore [return-value]
|
115
105
|
|
116
|
-
|
106
|
+
@property
|
107
|
+
def _binary(self) -> bool:
|
108
|
+
return self.get(("FoamFile", "format"), None) == "binary"
|
109
|
+
|
110
|
+
def __setitem__(
|
117
111
|
self,
|
118
112
|
keywords: Union[str, Tuple[str, ...]],
|
119
113
|
data: "FoamFile._SetData",
|
@@ -124,6 +118,16 @@ class FoamFile(
|
|
124
118
|
if not isinstance(keywords, tuple):
|
125
119
|
keywords = (keywords,)
|
126
120
|
|
121
|
+
kind = Kind.DEFAULT
|
122
|
+
if keywords == ("internalField",) or (
|
123
|
+
len(keywords) == 3
|
124
|
+
and keywords[0] == "boundaryField"
|
125
|
+
and keywords[2] == "value"
|
126
|
+
):
|
127
|
+
kind = Kind.BINARY_FIELD if self._binary else Kind.FIELD
|
128
|
+
elif keywords == ("dimensions",):
|
129
|
+
kind = Kind.DIMENSIONS
|
130
|
+
|
127
131
|
contents, parsed = self._read()
|
128
132
|
|
129
133
|
if isinstance(data, Mapping):
|
@@ -134,7 +138,11 @@ class FoamFile(
|
|
134
138
|
start, end = parsed.entry_location(keywords, missing_ok=True)
|
135
139
|
|
136
140
|
self._write(
|
137
|
-
|
141
|
+
contents[:start]
|
142
|
+
+ b"\n"
|
143
|
+
+ dumpb({keywords[-1]: {}})
|
144
|
+
+ b"\n"
|
145
|
+
+ contents[end:]
|
138
146
|
)
|
139
147
|
|
140
148
|
for k, v in data.items():
|
@@ -143,16 +151,13 @@ class FoamFile(
|
|
143
151
|
start, end = parsed.entry_location(keywords, missing_ok=True)
|
144
152
|
|
145
153
|
self._write(
|
146
|
-
|
154
|
+
contents[:start]
|
155
|
+
+ b"\n"
|
156
|
+
+ dumpb({keywords[-1]: data}, kind=kind)
|
157
|
+
+ b"\n"
|
158
|
+
+ contents[end:]
|
147
159
|
)
|
148
160
|
|
149
|
-
def __setitem__(
|
150
|
-
self,
|
151
|
-
keywords: Union[str, Tuple[str, ...]],
|
152
|
-
data: "FoamFile._SetData",
|
153
|
-
) -> None:
|
154
|
-
self._setitem(keywords, data)
|
155
|
-
|
156
161
|
def __delitem__(self, keywords: Union[str, Tuple[str, ...]]) -> None:
|
157
162
|
if not isinstance(keywords, tuple):
|
158
163
|
keywords = (keywords,)
|
@@ -194,10 +199,142 @@ class FoamFile(
|
|
194
199
|
def __fspath__(self) -> str:
|
195
200
|
return str(self.path)
|
196
201
|
|
197
|
-
def __repr__(self) -> str:
|
198
|
-
return f"{type(self).__name__}({self.path})"
|
199
|
-
|
200
202
|
def as_dict(self) -> FoamDict._Dict:
|
201
203
|
"""Return a nested dict representation of the file."""
|
202
204
|
_, parsed = self._read()
|
203
205
|
return parsed.as_dict()
|
206
|
+
|
207
|
+
|
208
|
+
class FoamFieldFile(FoamFile):
|
209
|
+
"""An OpenFOAM dictionary file representing a field as a mutable mapping."""
|
210
|
+
|
211
|
+
class BoundariesSubDict(FoamFile.SubDict):
|
212
|
+
def __getitem__(self, keyword: str) -> "FoamFieldFile.BoundarySubDict":
|
213
|
+
value = super().__getitem__(keyword)
|
214
|
+
if not isinstance(value, FoamFieldFile.BoundarySubDict):
|
215
|
+
assert not isinstance(value, FoamFile.SubDict)
|
216
|
+
raise TypeError(f"boundary {keyword} is not a dictionary")
|
217
|
+
return value
|
218
|
+
|
219
|
+
class BoundarySubDict(FoamFile.SubDict):
|
220
|
+
"""An OpenFOAM dictionary representing a boundary condition as a mutable mapping."""
|
221
|
+
|
222
|
+
@property
|
223
|
+
def type(self) -> str:
|
224
|
+
"""Alias of `self["type"]`."""
|
225
|
+
ret = self["type"]
|
226
|
+
if not isinstance(ret, str):
|
227
|
+
raise TypeError("type is not a string")
|
228
|
+
return ret
|
229
|
+
|
230
|
+
@type.setter
|
231
|
+
def type(self, data: str) -> None:
|
232
|
+
self["type"] = data
|
233
|
+
|
234
|
+
@property
|
235
|
+
def value(
|
236
|
+
self,
|
237
|
+
) -> Union[
|
238
|
+
int,
|
239
|
+
float,
|
240
|
+
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
241
|
+
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
242
|
+
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
243
|
+
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
244
|
+
]:
|
245
|
+
"""Alias of `self["value"]`."""
|
246
|
+
ret = self["value"]
|
247
|
+
if not isinstance(ret, (int, float, Sequence)):
|
248
|
+
raise TypeError("value is not a field")
|
249
|
+
return cast(
|
250
|
+
Union[
|
251
|
+
int, float, Sequence[Union[int, float, Sequence[Union[int, float]]]]
|
252
|
+
],
|
253
|
+
ret,
|
254
|
+
)
|
255
|
+
|
256
|
+
@value.setter
|
257
|
+
def value(
|
258
|
+
self,
|
259
|
+
value: Union[
|
260
|
+
int,
|
261
|
+
float,
|
262
|
+
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
263
|
+
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
264
|
+
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
265
|
+
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
266
|
+
],
|
267
|
+
) -> None:
|
268
|
+
self["value"] = value
|
269
|
+
|
270
|
+
@value.deleter
|
271
|
+
def value(self) -> None:
|
272
|
+
del self["value"]
|
273
|
+
|
274
|
+
def __getitem__(
|
275
|
+
self, keywords: Union[str, Tuple[str, ...]]
|
276
|
+
) -> Union[FoamFile.Data, FoamFile.SubDict]:
|
277
|
+
if not isinstance(keywords, tuple):
|
278
|
+
keywords = (keywords,)
|
279
|
+
|
280
|
+
ret = super().__getitem__(keywords)
|
281
|
+
if keywords[0] == "boundaryField" and isinstance(ret, FoamFile.SubDict):
|
282
|
+
if len(keywords) == 1:
|
283
|
+
ret = FoamFieldFile.BoundariesSubDict(self, keywords)
|
284
|
+
elif len(keywords) == 2:
|
285
|
+
ret = FoamFieldFile.BoundarySubDict(self, keywords)
|
286
|
+
return ret
|
287
|
+
|
288
|
+
@property
|
289
|
+
def dimensions(self) -> Union[FoamFile.DimensionSet, Sequence[Union[int, float]]]:
|
290
|
+
"""Alias of `self["dimensions"]`."""
|
291
|
+
ret = self["dimensions"]
|
292
|
+
if not isinstance(ret, FoamFile.DimensionSet):
|
293
|
+
raise TypeError("dimensions is not a DimensionSet")
|
294
|
+
return ret
|
295
|
+
|
296
|
+
@dimensions.setter
|
297
|
+
def dimensions(
|
298
|
+
self, value: Union[FoamFile.DimensionSet, Sequence[Union[int, float]]]
|
299
|
+
) -> None:
|
300
|
+
self["dimensions"] = value
|
301
|
+
|
302
|
+
@property
|
303
|
+
def internal_field(
|
304
|
+
self,
|
305
|
+
) -> Union[
|
306
|
+
int,
|
307
|
+
float,
|
308
|
+
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
309
|
+
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
310
|
+
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
311
|
+
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
312
|
+
]:
|
313
|
+
"""Alias of `self["internalField"]`."""
|
314
|
+
ret = self["internalField"]
|
315
|
+
if not isinstance(ret, (int, float, Sequence)):
|
316
|
+
raise TypeError("internalField is not a field")
|
317
|
+
return cast(Union[int, float, Sequence[Union[int, float]]], ret)
|
318
|
+
|
319
|
+
@internal_field.setter
|
320
|
+
def internal_field(
|
321
|
+
self,
|
322
|
+
value: Union[
|
323
|
+
int,
|
324
|
+
float,
|
325
|
+
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
326
|
+
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
327
|
+
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
328
|
+
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
329
|
+
],
|
330
|
+
) -> None:
|
331
|
+
self["internalField"] = value
|
332
|
+
|
333
|
+
@property
|
334
|
+
def boundary_field(self) -> "FoamFieldFile.BoundariesSubDict":
|
335
|
+
"""Alias of `self["boundaryField"]`."""
|
336
|
+
ret = self["boundaryField"]
|
337
|
+
if not isinstance(ret, FoamFieldFile.BoundariesSubDict):
|
338
|
+
assert not isinstance(ret, FoamFile.SubDict)
|
339
|
+
raise TypeError("boundaryField is not a dictionary")
|
340
|
+
return ret
|
foamlib/_files/_io.py
CHANGED
@@ -25,7 +25,7 @@ class FoamFileIO:
|
|
25
25
|
elif not self.path.is_file():
|
26
26
|
raise FileNotFoundError(self.path)
|
27
27
|
|
28
|
-
self.__contents: Optional[
|
28
|
+
self.__contents: Optional[bytes] = None
|
29
29
|
self.__parsed: Optional[Parsed] = None
|
30
30
|
self.__defer_io = 0
|
31
31
|
self.__dirty = False
|
@@ -48,9 +48,9 @@ class FoamFileIO:
|
|
48
48
|
self._write(self.__contents)
|
49
49
|
assert not self.__dirty
|
50
50
|
|
51
|
-
def _read(self) -> Tuple[
|
51
|
+
def _read(self) -> Tuple[bytes, Parsed]:
|
52
52
|
if not self.__defer_io:
|
53
|
-
contents = self.path.
|
53
|
+
contents = self.path.read_bytes()
|
54
54
|
if contents != self.__contents:
|
55
55
|
self.__contents = contents
|
56
56
|
self.__parsed = None
|
@@ -63,11 +63,14 @@ class FoamFileIO:
|
|
63
63
|
|
64
64
|
return self.__contents, deepcopy(self.__parsed)
|
65
65
|
|
66
|
-
def _write(self, contents:
|
66
|
+
def _write(self, contents: bytes) -> None:
|
67
67
|
self.__contents = contents
|
68
68
|
self.__parsed = None
|
69
69
|
if not self.__defer_io:
|
70
|
-
self.path.
|
70
|
+
self.path.write_bytes(contents)
|
71
71
|
self.__dirty = False
|
72
72
|
else:
|
73
73
|
self.__dirty = True
|
74
|
+
|
75
|
+
def __repr__(self) -> str:
|
76
|
+
return f"{type(self).__qualname__}('{self.path}')"
|
foamlib/_files/_parsing.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import array
|
1
2
|
import sys
|
2
3
|
from typing import Tuple, Union
|
3
4
|
|
@@ -12,6 +13,7 @@ else:
|
|
12
13
|
from typing import Any as EllipsisType
|
13
14
|
|
14
15
|
from pyparsing import (
|
16
|
+
CharsNotIn,
|
15
17
|
Dict,
|
16
18
|
Forward,
|
17
19
|
Group,
|
@@ -74,6 +76,56 @@ def _dictionary_of(
|
|
74
76
|
return Dict(Group(keyword_entry)[len], asdict=not located)
|
75
77
|
|
76
78
|
|
79
|
+
_binary_contents = Forward()
|
80
|
+
|
81
|
+
|
82
|
+
def _binary_field_parse_action(tks: ParseResults) -> None:
|
83
|
+
global _binary_contents
|
84
|
+
|
85
|
+
kind, count = tks
|
86
|
+
if kind == "scalar":
|
87
|
+
elsize = 1
|
88
|
+
elif kind == "vector":
|
89
|
+
elsize = 3
|
90
|
+
elif kind == "symmTensor":
|
91
|
+
elsize = 6
|
92
|
+
elif kind == "tensor":
|
93
|
+
elsize = 9
|
94
|
+
|
95
|
+
def unpack(
|
96
|
+
tks: ParseResults,
|
97
|
+
) -> Sequence[Union[Sequence[float], Sequence[Sequence[float]]]]:
|
98
|
+
bytes_ = tks[0].encode("latin-1")
|
99
|
+
|
100
|
+
arr = array.array("d", bytes_)
|
101
|
+
|
102
|
+
if elsize != 1:
|
103
|
+
all = [arr[i : i + elsize].tolist() for i in range(0, len(arr), elsize)]
|
104
|
+
else:
|
105
|
+
all = arr.tolist()
|
106
|
+
|
107
|
+
return [all]
|
108
|
+
|
109
|
+
_binary_contents <<= CharsNotIn(exact=count * elsize * 8).set_parse_action(unpack)
|
110
|
+
|
111
|
+
tks.clear() # type: ignore [no-untyped-call]
|
112
|
+
|
113
|
+
|
114
|
+
_BINARY_FIELD = (
|
115
|
+
(
|
116
|
+
Keyword("nonuniform").suppress()
|
117
|
+
+ Literal("List").suppress()
|
118
|
+
+ Literal("<").suppress()
|
119
|
+
+ common.identifier
|
120
|
+
+ Literal(">").suppress()
|
121
|
+
+ common.integer
|
122
|
+
+ Literal("(").suppress()
|
123
|
+
).set_parse_action(_binary_field_parse_action, call_during_try=True)
|
124
|
+
+ _binary_contents
|
125
|
+
+ Literal(")").suppress()
|
126
|
+
)
|
127
|
+
|
128
|
+
|
77
129
|
_SWITCH = (
|
78
130
|
Keyword("yes") | Keyword("true") | Keyword("on") | Keyword("y") | Keyword("t")
|
79
131
|
).set_parse_action(lambda: True) | (
|
@@ -87,8 +139,10 @@ _IDENTIFIER = Word(identchars + "$", printables, exclude_chars=";")
|
|
87
139
|
_DIMENSIONED = (Opt(_IDENTIFIER) + _DIMENSIONS + _TENSOR).set_parse_action(
|
88
140
|
lambda tks: FoamDict.Dimensioned(*reversed(tks.as_list()))
|
89
141
|
)
|
90
|
-
_FIELD = (
|
91
|
-
Keyword("
|
142
|
+
_FIELD = (
|
143
|
+
(Keyword("uniform").suppress() + _TENSOR)
|
144
|
+
| (Keyword("nonuniform").suppress() + _list_of(_TENSOR))
|
145
|
+
| _BINARY_FIELD
|
92
146
|
)
|
93
147
|
_TOKEN = QuotedString('"', unquote_results=False) | _IDENTIFIER
|
94
148
|
_DATA = Forward()
|
@@ -109,16 +163,19 @@ _FILE = (
|
|
109
163
|
.ignore(c_style_comment)
|
110
164
|
.ignore(cpp_style_comment)
|
111
165
|
.ignore(Literal("#include") + ... + LineEnd()) # type: ignore [no-untyped-call]
|
166
|
+
.parse_with_tabs()
|
112
167
|
)
|
113
168
|
|
114
169
|
|
115
170
|
class Parsed(Mapping[Tuple[str, ...], Union[FoamDict.Data, EllipsisType]]):
|
116
|
-
def __init__(self, contents:
|
171
|
+
def __init__(self, contents: bytes) -> None:
|
117
172
|
self._parsed: MutableMapping[
|
118
173
|
Tuple[str, ...],
|
119
174
|
Tuple[int, Union[FoamDict.Data, EllipsisType], int],
|
120
175
|
] = {}
|
121
|
-
for parse_result in _FILE.parse_string(
|
176
|
+
for parse_result in _FILE.parse_string(
|
177
|
+
contents.decode("latin-1"), parse_all=True
|
178
|
+
):
|
122
179
|
self._parsed.update(self._flatten_result(parse_result))
|
123
180
|
|
124
181
|
@staticmethod
|
foamlib/_files/_serialization.py
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
import array
|
2
|
+
import itertools
|
1
3
|
import sys
|
4
|
+
from enum import Enum, auto
|
2
5
|
|
3
6
|
if sys.version_info >= (3, 9):
|
4
7
|
from collections.abc import Mapping
|
@@ -16,84 +19,99 @@ except ModuleNotFoundError:
|
|
16
19
|
numpy = False
|
17
20
|
|
18
21
|
|
19
|
-
|
22
|
+
class Kind(Enum):
|
23
|
+
DEFAULT = auto()
|
24
|
+
LIST_ENTRY = auto()
|
25
|
+
FIELD = auto()
|
26
|
+
BINARY_FIELD = auto()
|
27
|
+
DIMENSIONS = auto()
|
28
|
+
|
29
|
+
|
30
|
+
def dumpb(
|
20
31
|
data: FoamDict._SetData,
|
21
32
|
*,
|
22
|
-
|
23
|
-
|
24
|
-
assume_data_entries: bool = False,
|
25
|
-
) -> str:
|
33
|
+
kind: Kind = Kind.DEFAULT,
|
34
|
+
) -> bytes:
|
26
35
|
if numpy and isinstance(data, np.ndarray):
|
27
|
-
return
|
28
|
-
data.tolist(),
|
29
|
-
assume_field=assume_field,
|
30
|
-
assume_dimensions=assume_dimensions,
|
31
|
-
)
|
36
|
+
return dumpb(data.tolist(), kind=kind)
|
32
37
|
|
33
38
|
elif isinstance(data, Mapping):
|
34
39
|
entries = []
|
35
40
|
for k, v in data.items():
|
36
|
-
|
37
|
-
v,
|
38
|
-
assume_field=assume_field,
|
39
|
-
assume_dimensions=assume_dimensions,
|
40
|
-
assume_data_entries=True,
|
41
|
-
)
|
41
|
+
b = dumpb(v, kind=kind)
|
42
42
|
if isinstance(v, Mapping):
|
43
|
-
entries.append(
|
44
|
-
elif
|
45
|
-
entries.append(
|
43
|
+
entries.append(dumpb(k) + b"\n" + b"{\n" + b + b"\n}")
|
44
|
+
elif b:
|
45
|
+
entries.append(dumpb(k) + b" " + b + b";")
|
46
46
|
else:
|
47
|
-
entries.append(
|
48
|
-
|
47
|
+
entries.append(dumpb(k) + b";")
|
48
|
+
|
49
|
+
return b"\n".join(entries)
|
49
50
|
|
50
51
|
elif isinstance(data, FoamDict.DimensionSet) or (
|
51
|
-
|
52
|
+
kind == Kind.DIMENSIONS and is_sequence(data) and len(data) == 7
|
52
53
|
):
|
53
|
-
return
|
54
|
+
return b"[" + b" ".join(dumpb(v) for v in data) + b"]"
|
54
55
|
|
55
|
-
elif
|
56
|
-
|
56
|
+
elif (kind == Kind.FIELD or kind == Kind.BINARY_FIELD) and (
|
57
|
+
isinstance(data, (int, float))
|
58
|
+
or is_sequence(data)
|
59
|
+
and data
|
60
|
+
and isinstance(data[0], (int, float))
|
61
|
+
and len(data) in (3, 6, 9)
|
62
|
+
):
|
63
|
+
return b"uniform " + dumpb(data)
|
57
64
|
|
58
|
-
elif
|
59
|
-
if isinstance(data[0], (int, float))
|
60
|
-
|
61
|
-
elif isinstance(data[0], (int, float)):
|
62
|
-
return f"nonuniform List<scalar> {len(data)}{dumps(data)}"
|
65
|
+
elif (kind == Kind.FIELD or kind == Kind.BINARY_FIELD) and is_sequence(data):
|
66
|
+
if isinstance(data[0], (int, float)):
|
67
|
+
tensor_kind = b"scalar"
|
63
68
|
elif len(data[0]) == 3:
|
64
|
-
|
69
|
+
tensor_kind = b"vector"
|
65
70
|
elif len(data[0]) == 6:
|
66
|
-
|
71
|
+
tensor_kind = b"symmTensor"
|
67
72
|
elif len(data[0]) == 9:
|
68
|
-
|
73
|
+
tensor_kind = b"tensor"
|
69
74
|
else:
|
70
|
-
return
|
71
|
-
data,
|
72
|
-
assume_dimensions=assume_dimensions,
|
73
|
-
assume_data_entries=assume_data_entries,
|
74
|
-
)
|
75
|
+
return dumpb(data)
|
75
76
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
77
|
+
if kind == Kind.BINARY_FIELD:
|
78
|
+
if tensor_kind == b"scalar":
|
79
|
+
contents = b"(" + array.array("d", data).tobytes() + b")"
|
80
|
+
else:
|
81
|
+
contents = (
|
82
|
+
b"("
|
83
|
+
+ array.array("d", itertools.chain.from_iterable(data)).tobytes()
|
84
|
+
+ b")"
|
85
|
+
)
|
86
|
+
else:
|
87
|
+
contents = dumpb(data)
|
88
|
+
|
89
|
+
return b"nonuniform List<" + tensor_kind + b"> " + dumpb(len(data)) + contents
|
90
|
+
|
91
|
+
elif kind != Kind.LIST_ENTRY and isinstance(data, tuple):
|
92
|
+
return b" ".join(dumpb(v) for v in data)
|
81
93
|
|
82
94
|
elif isinstance(data, FoamDict.Dimensioned):
|
83
95
|
if data.name is not None:
|
84
|
-
return
|
96
|
+
return (
|
97
|
+
dumpb(data.name)
|
98
|
+
+ b" "
|
99
|
+
+ dumpb(data.dimensions, kind=Kind.DIMENSIONS)
|
100
|
+
+ b" "
|
101
|
+
+ dumpb(data.value)
|
102
|
+
)
|
85
103
|
else:
|
86
104
|
return (
|
87
|
-
|
105
|
+
dumpb(data.dimensions, kind=Kind.DIMENSIONS) + b" " + dumpb(data.value)
|
88
106
|
)
|
89
107
|
|
90
108
|
elif is_sequence(data):
|
91
|
-
return
|
109
|
+
return b"(" + b" ".join(dumpb(v, kind=Kind.LIST_ENTRY) for v in data) + b")"
|
92
110
|
|
93
111
|
elif data is True:
|
94
|
-
return "yes"
|
112
|
+
return b"yes"
|
95
113
|
elif data is False:
|
96
|
-
return "no"
|
114
|
+
return b"no"
|
97
115
|
|
98
116
|
else:
|
99
|
-
return str(data)
|
117
|
+
return str(data).encode("latin-1")
|
foamlib/_util.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import asyncio
|
2
|
+
import os
|
2
3
|
import subprocess
|
3
4
|
import sys
|
4
5
|
from pathlib import Path
|
@@ -47,12 +48,20 @@ def _check(
|
|
47
48
|
warn(f"Command {cmd} printed to stderr.\n{stderr}", CalledProcessWarning)
|
48
49
|
|
49
50
|
|
51
|
+
def _env(cwd: Optional[Union[str, Path]] = None) -> Optional[Mapping[str, str]]:
|
52
|
+
if cwd is not None:
|
53
|
+
env = os.environ.copy()
|
54
|
+
env["PWD"] = str(cwd)
|
55
|
+
return env
|
56
|
+
else:
|
57
|
+
return None
|
58
|
+
|
59
|
+
|
50
60
|
def run_process(
|
51
61
|
cmd: Union[Sequence[Union[str, Path]], str, Path],
|
52
62
|
*,
|
53
63
|
check: bool = True,
|
54
64
|
cwd: Union[None, str, Path] = None,
|
55
|
-
env: Union[None, Mapping[str, str]] = None,
|
56
65
|
) -> None:
|
57
66
|
shell = not is_sequence(cmd)
|
58
67
|
|
@@ -65,8 +74,8 @@ def run_process(
|
|
65
74
|
proc = subprocess.run(
|
66
75
|
cmd,
|
67
76
|
cwd=cwd,
|
68
|
-
env=
|
69
|
-
stdout=
|
77
|
+
env=_env(cwd),
|
78
|
+
stdout=None,
|
70
79
|
stderr=subprocess.PIPE if check else subprocess.DEVNULL,
|
71
80
|
text=True,
|
72
81
|
shell=shell,
|
@@ -81,13 +90,12 @@ async def run_process_async(
|
|
81
90
|
*,
|
82
91
|
check: bool = True,
|
83
92
|
cwd: Union[None, str, Path] = None,
|
84
|
-
env: Union[None, Mapping[str, str]] = None,
|
85
93
|
) -> None:
|
86
94
|
if not is_sequence(cmd):
|
87
95
|
proc = await asyncio.create_subprocess_shell(
|
88
96
|
str(cmd),
|
89
97
|
cwd=cwd,
|
90
|
-
env=
|
98
|
+
env=_env(cwd),
|
91
99
|
stdout=asyncio.subprocess.DEVNULL,
|
92
100
|
stderr=asyncio.subprocess.PIPE if check else asyncio.subprocess.DEVNULL,
|
93
101
|
)
|
@@ -98,7 +106,7 @@ async def run_process_async(
|
|
98
106
|
proc = await asyncio.create_subprocess_exec(
|
99
107
|
*cmd,
|
100
108
|
cwd=cwd,
|
101
|
-
env=
|
109
|
+
env=_env(cwd),
|
102
110
|
stdout=asyncio.subprocess.DEVNULL,
|
103
111
|
stderr=asyncio.subprocess.PIPE if check else asyncio.subprocess.DEVNULL,
|
104
112
|
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: foamlib
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.5
|
4
4
|
Summary: A Python interface for interacting with OpenFOAM
|
5
5
|
Author-email: "Gabriel S. Gerlero" <ggerlero@cimec.unl.edu.ar>
|
6
6
|
Project-URL: Homepage, https://github.com/gerlero/foamlib
|
@@ -58,11 +58,11 @@ Requires-Dist: numpy <2,>=1 ; extra == 'typing'
|
|
58
58
|
|
59
59
|
**foamlib** provides a simple, modern and ergonomic Python interface for interacting with [OpenFOAM](https://www.openfoam.com).
|
60
60
|
|
61
|
-
It offers the following classes
|
61
|
+
It offers the following classes:
|
62
62
|
|
63
|
+
* [`FoamFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFile) (and [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile)): read-write access to OpenFOAM configuration and field files as if they were Python `dict`s, using `foamlib`'s own parser. Supports both ASCII and binary field formats.
|
63
64
|
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamCase): a class for manipulating, executing and accessing the results of OpenFOAM cases.
|
64
65
|
* [`AsyncFoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.AsyncFoamCase): variant of `FoamCase` with asynchronous methods for running multiple cases at once.
|
65
|
-
* [`FoamFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFile): read-write access to OpenFOAM configuration and field files as if they were Python `dict`s.
|
66
66
|
|
67
67
|
## Get started
|
68
68
|
|
@@ -130,6 +130,16 @@ async def run_case():
|
|
130
130
|
asyncio.run(run_case())
|
131
131
|
```
|
132
132
|
|
133
|
+
### Parse a field using the [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile) class directly
|
134
|
+
|
135
|
+
```python
|
136
|
+
from foamlib import FoamFieldFile
|
137
|
+
|
138
|
+
U = FoamFieldFile(Path(my_pitz) / "0/U")
|
139
|
+
|
140
|
+
print(U.internal_field)
|
141
|
+
```
|
142
|
+
|
133
143
|
## Documentation
|
134
144
|
|
135
145
|
For more information, check out the [documentation](https://foamlib.readthedocs.io/).
|
@@ -0,0 +1,15 @@
|
|
1
|
+
foamlib/__init__.py,sha256=Zvz69We30bHHGeRvmwmUvLTCPDoYxSHNsMGfJm8NTro,431
|
2
|
+
foamlib/_cases.py,sha256=ELwX-Gr3ZB11axG6coHqXDyGh9Xb7kgAfYkhCsEGZy4,20278
|
3
|
+
foamlib/_util.py,sha256=hh5gTJqEvQcqbt0_tA2xMceyqtAIaqNd78jvePdAQ7w,3037
|
4
|
+
foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
foamlib/_files/__init__.py,sha256=vDkPj8u8bX_I_m2YfeKvXBgwg8D1ufyFCfHGHKN3JPQ,140
|
6
|
+
foamlib/_files/_base.py,sha256=YA5a-i5HZuA3JslCD6r-DwZzpSA8r42dqSXef286Ako,2050
|
7
|
+
foamlib/_files/_files.py,sha256=JcOVP3eu9QYCOPt_DfobigKsd0VqgJRfEVytMOwES_g,10815
|
8
|
+
foamlib/_files/_io.py,sha256=So9rG6iW77sRK2xFz5KHX6AFtYc2L19voAwn-_NmQow,2075
|
9
|
+
foamlib/_files/_parsing.py,sha256=-zSpEDjuPxzOdsLWaeQl7j6FZHyw2-jXNgOCXkcGskU,7308
|
10
|
+
foamlib/_files/_serialization.py,sha256=bGit_qcQvbGd20yuPdAXfx7d9ArmHa_tSAPYPPecgCg,3266
|
11
|
+
foamlib-0.3.5.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
|
12
|
+
foamlib-0.3.5.dist-info/METADATA,sha256=5NbPf_3gASyHvck8fOHMawq0W70o0GqEtO6tL42se-o,5037
|
13
|
+
foamlib-0.3.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
14
|
+
foamlib-0.3.5.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
|
15
|
+
foamlib-0.3.5.dist-info/RECORD,,
|
foamlib/_files/_fields.py
DELETED
@@ -1,165 +0,0 @@
|
|
1
|
-
import sys
|
2
|
-
from typing import Any, Tuple, Union, cast
|
3
|
-
|
4
|
-
if sys.version_info >= (3, 9):
|
5
|
-
from collections.abc import Sequence
|
6
|
-
else:
|
7
|
-
from typing import Sequence
|
8
|
-
|
9
|
-
from ._files import FoamFile
|
10
|
-
|
11
|
-
try:
|
12
|
-
import numpy as np
|
13
|
-
except ModuleNotFoundError:
|
14
|
-
pass
|
15
|
-
|
16
|
-
|
17
|
-
class FoamFieldFile(FoamFile):
|
18
|
-
"""An OpenFOAM dictionary file representing a field as a mutable mapping."""
|
19
|
-
|
20
|
-
class BoundariesSubDict(FoamFile.SubDict):
|
21
|
-
def __getitem__(self, keyword: str) -> "FoamFieldFile.BoundarySubDict":
|
22
|
-
value = super().__getitem__(keyword)
|
23
|
-
if not isinstance(value, FoamFieldFile.BoundarySubDict):
|
24
|
-
assert not isinstance(value, FoamFile.SubDict)
|
25
|
-
raise TypeError(f"boundary {keyword} is not a dictionary")
|
26
|
-
return value
|
27
|
-
|
28
|
-
class BoundarySubDict(FoamFile.SubDict):
|
29
|
-
"""An OpenFOAM dictionary representing a boundary condition as a mutable mapping."""
|
30
|
-
|
31
|
-
def __setitem__(
|
32
|
-
self,
|
33
|
-
keyword: str,
|
34
|
-
data: FoamFile._SetData,
|
35
|
-
) -> None:
|
36
|
-
if keyword == "value":
|
37
|
-
self._setitem(keyword, data, assume_field=True)
|
38
|
-
else:
|
39
|
-
self._setitem(keyword, data)
|
40
|
-
|
41
|
-
@property
|
42
|
-
def type(self) -> str:
|
43
|
-
"""Alias of `self["type"]`."""
|
44
|
-
ret = self["type"]
|
45
|
-
if not isinstance(ret, str):
|
46
|
-
raise TypeError("type is not a string")
|
47
|
-
return ret
|
48
|
-
|
49
|
-
@type.setter
|
50
|
-
def type(self, data: str) -> None:
|
51
|
-
self["type"] = data
|
52
|
-
|
53
|
-
@property
|
54
|
-
def value(
|
55
|
-
self,
|
56
|
-
) -> Union[
|
57
|
-
int,
|
58
|
-
float,
|
59
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
60
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
61
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
62
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
63
|
-
]:
|
64
|
-
"""Alias of `self["value"]`."""
|
65
|
-
ret = self["value"]
|
66
|
-
if not isinstance(ret, (int, float, Sequence)):
|
67
|
-
raise TypeError("value is not a field")
|
68
|
-
return cast(Union[int, float, Sequence[Union[int, float]]], ret)
|
69
|
-
|
70
|
-
@value.setter
|
71
|
-
def value(
|
72
|
-
self,
|
73
|
-
value: Union[
|
74
|
-
int,
|
75
|
-
float,
|
76
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
77
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
78
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
79
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
80
|
-
],
|
81
|
-
) -> None:
|
82
|
-
self["value"] = value
|
83
|
-
|
84
|
-
@value.deleter
|
85
|
-
def value(self) -> None:
|
86
|
-
del self["value"]
|
87
|
-
|
88
|
-
def __getitem__(
|
89
|
-
self, keywords: Union[str, Tuple[str, ...]]
|
90
|
-
) -> Union[FoamFile.Data, FoamFile.SubDict]:
|
91
|
-
if not isinstance(keywords, tuple):
|
92
|
-
keywords = (keywords,)
|
93
|
-
|
94
|
-
ret = super().__getitem__(keywords)
|
95
|
-
if keywords[0] == "boundaryField" and isinstance(ret, FoamFile.SubDict):
|
96
|
-
if len(keywords) == 1:
|
97
|
-
ret = FoamFieldFile.BoundariesSubDict(self, keywords)
|
98
|
-
elif len(keywords) == 2:
|
99
|
-
ret = FoamFieldFile.BoundarySubDict(self, keywords)
|
100
|
-
return ret
|
101
|
-
|
102
|
-
def __setitem__(self, keywords: Union[str, Tuple[str, ...]], value: Any) -> None:
|
103
|
-
if not isinstance(keywords, tuple):
|
104
|
-
keywords = (keywords,)
|
105
|
-
|
106
|
-
if keywords == ("internalField",):
|
107
|
-
self._setitem(keywords, value, assume_field=True)
|
108
|
-
elif keywords == ("dimensions",):
|
109
|
-
self._setitem(keywords, value, assume_dimensions=True)
|
110
|
-
else:
|
111
|
-
self._setitem(keywords, value)
|
112
|
-
|
113
|
-
@property
|
114
|
-
def dimensions(self) -> FoamFile.DimensionSet:
|
115
|
-
"""Alias of `self["dimensions"]`."""
|
116
|
-
ret = self["dimensions"]
|
117
|
-
if not isinstance(ret, FoamFile.DimensionSet):
|
118
|
-
raise TypeError("dimensions is not a DimensionSet")
|
119
|
-
return ret
|
120
|
-
|
121
|
-
@dimensions.setter
|
122
|
-
def dimensions(
|
123
|
-
self, value: Union[FoamFile.DimensionSet, Sequence[Union[int, float]]]
|
124
|
-
) -> None:
|
125
|
-
self["dimensions"] = value
|
126
|
-
|
127
|
-
@property
|
128
|
-
def internal_field(
|
129
|
-
self,
|
130
|
-
) -> Union[
|
131
|
-
int,
|
132
|
-
float,
|
133
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
134
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
135
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
136
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
137
|
-
]:
|
138
|
-
"""Alias of `self["internalField"]`."""
|
139
|
-
ret = self["internalField"]
|
140
|
-
if not isinstance(ret, (int, float, Sequence)):
|
141
|
-
raise TypeError("internalField is not a field")
|
142
|
-
return cast(Union[int, float, Sequence[Union[int, float]]], ret)
|
143
|
-
|
144
|
-
@internal_field.setter
|
145
|
-
def internal_field(
|
146
|
-
self,
|
147
|
-
value: Union[
|
148
|
-
int,
|
149
|
-
float,
|
150
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
151
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
152
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
153
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
154
|
-
],
|
155
|
-
) -> None:
|
156
|
-
self["internalField"] = value
|
157
|
-
|
158
|
-
@property
|
159
|
-
def boundary_field(self) -> "FoamFieldFile.BoundariesSubDict":
|
160
|
-
"""Alias of `self["boundaryField"]`."""
|
161
|
-
ret = self["boundaryField"]
|
162
|
-
if not isinstance(ret, FoamFieldFile.BoundariesSubDict):
|
163
|
-
assert not isinstance(ret, FoamFile.SubDict)
|
164
|
-
raise TypeError("boundaryField is not a dictionary")
|
165
|
-
return ret
|
foamlib-0.3.3.dist-info/RECORD
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
foamlib/__init__.py,sha256=SMS_z3NGbCYTLLD0Gs1a7TwVVu2zHzCxHsy1CMiag5M,431
|
2
|
-
foamlib/_cases.py,sha256=K5WxuwM7A3o99l1S0Lgzr1X2TAPa8B-bz4U27k7hRDM,20563
|
3
|
-
foamlib/_util.py,sha256=0HJ9n8QG9K7jC_xUDzOJo_NA2DBCJKJRLpmd5Yu42kU,2901
|
4
|
-
foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
foamlib/_files/__init__.py,sha256=m4y_7wFV2Voly1aJrTYALjT3S1Aq7EbaijxdGFbJrmU,160
|
6
|
-
foamlib/_files/_base.py,sha256=YA5a-i5HZuA3JslCD6r-DwZzpSA8r42dqSXef286Ako,2050
|
7
|
-
foamlib/_files/_fields.py,sha256=jVHOHEV70i6QrWzqhF_W5CywUZyJxN5Eh5S1MrNn1G0,5632
|
8
|
-
foamlib/_files/_files.py,sha256=aS8VDGifnDSX40HdgT512fuhQ9iGlPls3p133d64Rak,5975
|
9
|
-
foamlib/_files/_io.py,sha256=alxMyxQh0zb6BZYqomZwOo9dQujMpRuS5yfpIKBEnaM,1976
|
10
|
-
foamlib/_files/_parsing.py,sha256=v8pjHR9vRekMsgDwtF2NJz61AVP_13wGt5FmkSHQmpc,5960
|
11
|
-
foamlib/_files/_serialization.py,sha256=H9STIpUxEBRwXh5WnqtjicCkGTpTYSwfWUwbVJf9x9A,2961
|
12
|
-
foamlib-0.3.3.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
|
13
|
-
foamlib-0.3.3.dist-info/METADATA,sha256=GybyB4yBaja4NjTeGYT6QE-Pzx_qMLCLl6NmLfnrRiQ,4650
|
14
|
-
foamlib-0.3.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
15
|
-
foamlib-0.3.3.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
|
16
|
-
foamlib-0.3.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|