foamlib 0.6.10__py3-none-any.whl → 0.6.11__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/_files/_base.py +34 -26
- foamlib/_files/_files.py +60 -91
- foamlib/_files/_io.py +24 -34
- foamlib/_files/_parsing.py +57 -10
- foamlib/_files/_serialization.py +1 -1
- {foamlib-0.6.10.dist-info → foamlib-0.6.11.dist-info}/METADATA +1 -1
- {foamlib-0.6.10.dist-info → foamlib-0.6.11.dist-info}/RECORD +11 -11
- {foamlib-0.6.10.dist-info → foamlib-0.6.11.dist-info}/WHEEL +1 -1
- {foamlib-0.6.10.dist-info → foamlib-0.6.11.dist-info}/LICENSE.txt +0 -0
- {foamlib-0.6.10.dist-info → foamlib-0.6.11.dist-info}/top_level.txt +0 -0
foamlib/__init__.py
CHANGED
foamlib/_files/_base.py
CHANGED
@@ -6,35 +6,46 @@ if TYPE_CHECKING:
|
|
6
6
|
import numpy as np
|
7
7
|
|
8
8
|
if sys.version_info >= (3, 9):
|
9
|
-
from collections.abc import Mapping, Sequence
|
9
|
+
from collections.abc import Mapping, MutableMapping, Sequence
|
10
10
|
else:
|
11
|
-
from typing import Mapping, Sequence
|
11
|
+
from typing import Mapping, MutableMapping, Sequence
|
12
12
|
|
13
13
|
|
14
14
|
class FoamFileBase:
|
15
15
|
class DimensionSet(NamedTuple):
|
16
|
-
mass:
|
17
|
-
length:
|
18
|
-
time:
|
19
|
-
temperature:
|
20
|
-
moles:
|
21
|
-
current:
|
22
|
-
luminous_intensity:
|
16
|
+
mass: float = 0
|
17
|
+
length: float = 0
|
18
|
+
time: float = 0
|
19
|
+
temperature: float = 0
|
20
|
+
moles: float = 0
|
21
|
+
current: float = 0
|
22
|
+
luminous_intensity: float = 0
|
23
23
|
|
24
24
|
def __repr__(self) -> str:
|
25
25
|
return f"{type(self).__qualname__}({', '.join(f'{n}={v}' for n, v in zip(self._fields, self) if v != 0)})"
|
26
26
|
|
27
|
+
_Tensor = Union[
|
28
|
+
float,
|
29
|
+
Sequence[float],
|
30
|
+
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
31
|
+
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
32
|
+
]
|
33
|
+
|
27
34
|
@dataclass
|
28
35
|
class Dimensioned:
|
29
|
-
value:
|
30
|
-
dimensions: Union["FoamFileBase.DimensionSet", Sequence[
|
36
|
+
value: "FoamFileBase._Tensor" = 0
|
37
|
+
dimensions: Union["FoamFileBase.DimensionSet", Sequence[float]] = ()
|
31
38
|
name: Optional[str] = None
|
32
39
|
|
33
40
|
def __post_init__(self) -> None:
|
34
41
|
if not isinstance(self.dimensions, FoamFileBase.DimensionSet):
|
35
42
|
self.dimensions = FoamFileBase.DimensionSet(*self.dimensions)
|
36
43
|
|
37
|
-
|
44
|
+
_Field = Union[
|
45
|
+
_Tensor, Sequence[_Tensor], "np.ndarray[Tuple[int, int], np.dtype[np.generic]]"
|
46
|
+
]
|
47
|
+
|
48
|
+
_DataEntry = Union[
|
38
49
|
str,
|
39
50
|
int,
|
40
51
|
float,
|
@@ -42,25 +53,22 @@ class FoamFileBase:
|
|
42
53
|
Dimensioned,
|
43
54
|
DimensionSet,
|
44
55
|
Sequence["Data"],
|
56
|
+
_Tensor,
|
57
|
+
_Field,
|
58
|
+
]
|
59
|
+
|
60
|
+
Data = Union[
|
61
|
+
_DataEntry,
|
45
62
|
Mapping[str, "Data"],
|
46
63
|
]
|
47
64
|
"""
|
48
65
|
A value that can be stored in an OpenFOAM file.
|
49
66
|
"""
|
50
67
|
|
68
|
+
_MutableData = Union[
|
69
|
+
_DataEntry,
|
70
|
+
MutableMapping[str, "_MutableData"],
|
71
|
+
]
|
72
|
+
|
51
73
|
_Dict = Dict[str, Union["Data", "_Dict"]]
|
52
74
|
_File = Dict[Optional[str], Union["Data", "_Dict"]]
|
53
|
-
|
54
|
-
_SetData = Union[
|
55
|
-
str,
|
56
|
-
int,
|
57
|
-
float,
|
58
|
-
bool,
|
59
|
-
Dimensioned,
|
60
|
-
DimensionSet,
|
61
|
-
Sequence["_SetData"],
|
62
|
-
Mapping[str, "_SetData"],
|
63
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
64
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
65
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
66
|
-
]
|
foamlib/_files/_files.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import sys
|
2
|
-
from
|
2
|
+
from copy import deepcopy
|
3
|
+
from typing import Any, Optional, Tuple, Union, cast
|
3
4
|
|
4
5
|
if sys.version_info >= (3, 8):
|
5
6
|
from typing import Literal
|
@@ -16,15 +17,12 @@ from ._io import FoamFileIO
|
|
16
17
|
from ._serialization import Kind, dumps
|
17
18
|
from ._util import is_sequence
|
18
19
|
|
19
|
-
if TYPE_CHECKING:
|
20
|
-
import numpy as np
|
21
|
-
|
22
20
|
|
23
21
|
class FoamFile(
|
24
22
|
FoamFileBase,
|
25
23
|
MutableMapping[
|
26
24
|
Optional[Union[str, Tuple[str, ...]]],
|
27
|
-
|
25
|
+
FoamFileBase._MutableData,
|
28
26
|
],
|
29
27
|
FoamFileIO,
|
30
28
|
):
|
@@ -37,7 +35,7 @@ class FoamFile(
|
|
37
35
|
"""
|
38
36
|
|
39
37
|
class SubDict(
|
40
|
-
MutableMapping[str,
|
38
|
+
MutableMapping[str, FoamFileBase._MutableData],
|
41
39
|
):
|
42
40
|
"""An OpenFOAM dictionary within a file as a mutable mapping."""
|
43
41
|
|
@@ -47,13 +45,13 @@ class FoamFile(
|
|
47
45
|
|
48
46
|
def __getitem__(
|
49
47
|
self, keyword: str
|
50
|
-
) -> Union[
|
48
|
+
) -> Union[FoamFileBase._DataEntry, "FoamFile.SubDict"]:
|
51
49
|
return self._file[(*self._keywords, keyword)]
|
52
50
|
|
53
51
|
def __setitem__(
|
54
52
|
self,
|
55
53
|
keyword: str,
|
56
|
-
data:
|
54
|
+
data: FoamFileBase.Data,
|
57
55
|
) -> None:
|
58
56
|
self._file[(*self._keywords, keyword)] = data
|
59
57
|
|
@@ -98,8 +96,8 @@ class FoamFile(
|
|
98
96
|
def version(self) -> float:
|
99
97
|
"""Alias of `self["FoamFile", "version"]`."""
|
100
98
|
ret = self["FoamFile", "version"]
|
101
|
-
if not isinstance(ret, float):
|
102
|
-
raise TypeError("version is not a
|
99
|
+
if not isinstance(ret, (int, float)):
|
100
|
+
raise TypeError("version is not a number")
|
103
101
|
return ret
|
104
102
|
|
105
103
|
@version.setter
|
@@ -158,22 +156,24 @@ class FoamFile(
|
|
158
156
|
|
159
157
|
def __getitem__(
|
160
158
|
self, keywords: Optional[Union[str, Tuple[str, ...]]]
|
161
|
-
) -> Union[
|
159
|
+
) -> Union[FoamFileBase._DataEntry, "FoamFile.SubDict"]:
|
162
160
|
if not keywords:
|
163
161
|
keywords = ()
|
164
162
|
elif not isinstance(keywords, tuple):
|
165
163
|
keywords = (keywords,)
|
166
164
|
|
167
|
-
|
165
|
+
parsed = self._get_parsed()
|
168
166
|
|
169
167
|
value = parsed[keywords]
|
170
168
|
|
169
|
+
assert not isinstance(value, Mapping)
|
170
|
+
|
171
171
|
if value is ...:
|
172
172
|
return FoamFile.SubDict(self, keywords)
|
173
|
-
return value
|
173
|
+
return deepcopy(value)
|
174
174
|
|
175
175
|
def __setitem__(
|
176
|
-
self, keywords: Optional[Union[str, Tuple[str, ...]]], data:
|
176
|
+
self, keywords: Optional[Union[str, Tuple[str, ...]]], data: FoamFileBase.Data
|
177
177
|
) -> None:
|
178
178
|
with self:
|
179
179
|
if not keywords:
|
@@ -230,20 +230,28 @@ class FoamFile(
|
|
230
230
|
self[keywords] = data
|
231
231
|
|
232
232
|
else:
|
233
|
-
|
233
|
+
parsed = self._get_parsed(missing_ok=True)
|
234
234
|
|
235
235
|
start, end = parsed.entry_location(keywords, missing_ok=True)
|
236
236
|
|
237
|
-
before =
|
238
|
-
if
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
if
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
237
|
+
before = b""
|
238
|
+
if parsed.contents[:start] and not parsed.contents[:start].endswith(
|
239
|
+
b"\n"
|
240
|
+
):
|
241
|
+
before = b"\n"
|
242
|
+
if (
|
243
|
+
parsed.contents[:start]
|
244
|
+
and len(keywords) <= 1
|
245
|
+
and not parsed.contents[:start].endswith(b"\n\n")
|
246
|
+
):
|
247
|
+
before = b"\n\n"
|
248
|
+
|
249
|
+
after = b""
|
250
|
+
if parsed.contents[end:].startswith(b"}"):
|
251
|
+
after = b" " * (len(keywords) - 2)
|
252
|
+
if not parsed.contents[end:] or not parsed.contents[end:].startswith(
|
253
|
+
b"\n"
|
254
|
+
):
|
247
255
|
after = b"\n" + after
|
248
256
|
|
249
257
|
indentation = b" " * (len(keywords) - 1)
|
@@ -252,7 +260,9 @@ class FoamFile(
|
|
252
260
|
if isinstance(data, (FoamFile, FoamFile.SubDict)):
|
253
261
|
data = data.as_dict()
|
254
262
|
|
255
|
-
|
263
|
+
parsed.put(
|
264
|
+
keywords,
|
265
|
+
...,
|
256
266
|
before
|
257
267
|
+ indentation
|
258
268
|
+ dumps(keywords[-1])
|
@@ -261,25 +271,27 @@ class FoamFile(
|
|
261
271
|
+ b"{\n"
|
262
272
|
+ indentation
|
263
273
|
+ b"}"
|
264
|
-
+ after
|
274
|
+
+ after,
|
265
275
|
)
|
266
276
|
|
267
277
|
for k, v in data.items():
|
268
278
|
self[(*keywords, k)] = v
|
269
279
|
|
270
280
|
elif keywords:
|
271
|
-
|
281
|
+
parsed.put(
|
282
|
+
keywords,
|
283
|
+
data,
|
272
284
|
before
|
273
285
|
+ indentation
|
274
286
|
+ dumps(keywords[-1])
|
275
287
|
+ b" "
|
276
288
|
+ dumps(data, kind=kind)
|
277
289
|
+ b";"
|
278
|
-
+ after
|
290
|
+
+ after,
|
279
291
|
)
|
280
292
|
|
281
293
|
else:
|
282
|
-
|
294
|
+
parsed.put(keywords, data, before + dumps(data, kind=kind) + after)
|
283
295
|
|
284
296
|
def __delitem__(self, keywords: Optional[Union[str, Tuple[str, ...]]]) -> None:
|
285
297
|
if not keywords:
|
@@ -287,15 +299,13 @@ class FoamFile(
|
|
287
299
|
elif not isinstance(keywords, tuple):
|
288
300
|
keywords = (keywords,)
|
289
301
|
|
290
|
-
|
291
|
-
|
292
|
-
start, end = parsed.entry_location(keywords)
|
293
|
-
|
294
|
-
self._write(contents[:start] + contents[end:])
|
302
|
+
with self:
|
303
|
+
del self._get_parsed()[keywords]
|
295
304
|
|
296
305
|
def _iter(self, keywords: Tuple[str, ...] = ()) -> Iterator[Optional[str]]:
|
297
|
-
|
298
|
-
|
306
|
+
yield from (
|
307
|
+
k[-1] if k else None for k in self._get_parsed() if k[:-1] == keywords
|
308
|
+
)
|
299
309
|
|
300
310
|
def __iter__(self) -> Iterator[Optional[str]]:
|
301
311
|
yield from (k for k in self._iter() if k != "FoamFile")
|
@@ -306,9 +316,7 @@ class FoamFile(
|
|
306
316
|
elif not isinstance(keywords, tuple):
|
307
317
|
keywords = (keywords,)
|
308
318
|
|
309
|
-
|
310
|
-
|
311
|
-
return keywords in parsed
|
319
|
+
return keywords in self._get_parsed()
|
312
320
|
|
313
321
|
def __len__(self) -> int:
|
314
322
|
return len(list(iter(self)))
|
@@ -330,11 +338,10 @@ class FoamFile(
|
|
330
338
|
|
331
339
|
:param include_header: Whether to include the "FoamFile" header in the output.
|
332
340
|
"""
|
333
|
-
|
334
|
-
d = parsed.as_dict()
|
341
|
+
d = self._get_parsed().as_dict()
|
335
342
|
if not include_header:
|
336
343
|
d.pop("FoamFile", None)
|
337
|
-
return d
|
344
|
+
return deepcopy(d)
|
338
345
|
|
339
346
|
|
340
347
|
class FoamFieldFile(FoamFile):
|
@@ -366,36 +373,17 @@ class FoamFieldFile(FoamFile):
|
|
366
373
|
@property
|
367
374
|
def value(
|
368
375
|
self,
|
369
|
-
) ->
|
370
|
-
int,
|
371
|
-
float,
|
372
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
373
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
374
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
375
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
376
|
-
]:
|
376
|
+
) -> FoamFile._Field:
|
377
377
|
"""Alias of `self["value"]`."""
|
378
|
-
ret = self["value"]
|
379
|
-
if not isinstance(ret, (int, float, Sequence)):
|
380
|
-
raise TypeError("value is not a field")
|
381
378
|
return cast(
|
382
|
-
|
383
|
-
|
384
|
-
],
|
385
|
-
ret,
|
379
|
+
FoamFile._Field,
|
380
|
+
self["value"],
|
386
381
|
)
|
387
382
|
|
388
383
|
@value.setter
|
389
384
|
def value(
|
390
385
|
self,
|
391
|
-
value:
|
392
|
-
int,
|
393
|
-
float,
|
394
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
395
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
396
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
397
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
398
|
-
],
|
386
|
+
value: FoamFile._Field,
|
399
387
|
) -> None:
|
400
388
|
self["value"] = value
|
401
389
|
|
@@ -405,7 +393,7 @@ class FoamFieldFile(FoamFile):
|
|
405
393
|
|
406
394
|
def __getitem__(
|
407
395
|
self, keywords: Optional[Union[str, Tuple[str, ...]]]
|
408
|
-
) -> Union[
|
396
|
+
) -> Union[FoamFileBase._DataEntry, FoamFile.SubDict]:
|
409
397
|
if not keywords:
|
410
398
|
keywords = ()
|
411
399
|
elif not isinstance(keywords, tuple):
|
@@ -420,7 +408,7 @@ class FoamFieldFile(FoamFile):
|
|
420
408
|
return ret
|
421
409
|
|
422
410
|
@property
|
423
|
-
def dimensions(self) -> Union[FoamFile.DimensionSet, Sequence[
|
411
|
+
def dimensions(self) -> Union[FoamFile.DimensionSet, Sequence[float]]:
|
424
412
|
"""Alias of `self["dimensions"]`."""
|
425
413
|
ret = self["dimensions"]
|
426
414
|
if not isinstance(ret, FoamFile.DimensionSet):
|
@@ -428,39 +416,20 @@ class FoamFieldFile(FoamFile):
|
|
428
416
|
return ret
|
429
417
|
|
430
418
|
@dimensions.setter
|
431
|
-
def dimensions(
|
432
|
-
self, value: Union[FoamFile.DimensionSet, Sequence[Union[int, float]]]
|
433
|
-
) -> None:
|
419
|
+
def dimensions(self, value: Union[FoamFile.DimensionSet, Sequence[float]]) -> None:
|
434
420
|
self["dimensions"] = value
|
435
421
|
|
436
422
|
@property
|
437
423
|
def internal_field(
|
438
424
|
self,
|
439
|
-
) ->
|
440
|
-
int,
|
441
|
-
float,
|
442
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
443
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
444
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
445
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
446
|
-
]:
|
425
|
+
) -> FoamFile._Field:
|
447
426
|
"""Alias of `self["internalField"]`."""
|
448
|
-
|
449
|
-
if not isinstance(ret, (int, float, Sequence)):
|
450
|
-
raise TypeError("internalField is not a field")
|
451
|
-
return cast(Union[int, float, Sequence[Union[int, float]]], ret)
|
427
|
+
return cast(FoamFile._Field, self["internalField"])
|
452
428
|
|
453
429
|
@internal_field.setter
|
454
430
|
def internal_field(
|
455
431
|
self,
|
456
|
-
value:
|
457
|
-
int,
|
458
|
-
float,
|
459
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
460
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
461
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
462
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
463
|
-
],
|
432
|
+
value: FoamFile._Field,
|
464
433
|
) -> None:
|
465
434
|
self["internalField"] = value
|
466
435
|
|
foamlib/_files/_io.py
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
import gzip
|
2
2
|
import sys
|
3
|
-
from copy import deepcopy
|
4
3
|
from pathlib import Path
|
5
4
|
from types import TracebackType
|
6
5
|
from typing import (
|
7
6
|
TYPE_CHECKING,
|
8
7
|
Optional,
|
9
|
-
Tuple,
|
10
8
|
Type,
|
11
9
|
Union,
|
12
10
|
)
|
@@ -26,14 +24,13 @@ class FoamFileIO:
|
|
26
24
|
def __init__(self, path: Union["os.PathLike[str]", str]) -> None:
|
27
25
|
self.path = Path(path).absolute()
|
28
26
|
|
29
|
-
self.__contents: Optional[bytes] = None
|
30
27
|
self.__parsed: Optional[Parsed] = None
|
28
|
+
self.__missing: Optional[bool] = None
|
31
29
|
self.__defer_io = 0
|
32
|
-
self.__dirty = False
|
33
30
|
|
34
31
|
def __enter__(self) -> Self:
|
35
32
|
if self.__defer_io == 0:
|
36
|
-
self.
|
33
|
+
self._get_parsed(missing_ok=True)
|
37
34
|
self.__defer_io += 1
|
38
35
|
return self
|
39
36
|
|
@@ -44,47 +41,40 @@ class FoamFileIO:
|
|
44
41
|
exc_tb: Optional[TracebackType],
|
45
42
|
) -> None:
|
46
43
|
self.__defer_io -= 1
|
47
|
-
if self.__defer_io == 0
|
48
|
-
assert self.
|
49
|
-
self.
|
44
|
+
if self.__defer_io == 0:
|
45
|
+
assert self.__parsed is not None
|
46
|
+
if self.__parsed.modified:
|
47
|
+
contents = self.__parsed.contents
|
48
|
+
|
49
|
+
if self.path.suffix == ".gz":
|
50
|
+
contents = gzip.compress(contents)
|
50
51
|
|
51
|
-
|
52
|
+
self.path.write_bytes(contents)
|
53
|
+
self.__parsed.modified = False
|
54
|
+
self.__missing = False
|
55
|
+
|
56
|
+
def _get_parsed(self, *, missing_ok: bool = False) -> Parsed:
|
52
57
|
if not self.__defer_io:
|
53
58
|
try:
|
54
59
|
contents = self.path.read_bytes()
|
55
60
|
except FileNotFoundError:
|
56
|
-
|
61
|
+
self.__missing = True
|
62
|
+
contents = b""
|
57
63
|
else:
|
58
|
-
|
64
|
+
self.__missing = False
|
59
65
|
if self.path.suffix == ".gz":
|
60
66
|
contents = gzip.decompress(contents)
|
61
67
|
|
62
|
-
if contents !=
|
63
|
-
self.
|
64
|
-
self.__parsed = None
|
68
|
+
if self.__parsed is None or self.__parsed.contents != contents:
|
69
|
+
self.__parsed = Parsed(contents)
|
65
70
|
|
66
|
-
|
67
|
-
|
68
|
-
return b"", Parsed(b"")
|
69
|
-
raise FileNotFoundError(self.path)
|
71
|
+
assert self.__parsed is not None
|
72
|
+
assert self.__missing is not None
|
70
73
|
|
71
|
-
if self.__parsed
|
72
|
-
|
73
|
-
self.__parsed = parsed
|
74
|
-
|
75
|
-
return self.__contents, deepcopy(self.__parsed)
|
76
|
-
|
77
|
-
def _write(self, contents: bytes) -> None:
|
78
|
-
self.__contents = contents
|
79
|
-
self.__parsed = None
|
80
|
-
if not self.__defer_io:
|
81
|
-
if self.path.suffix == ".gz":
|
82
|
-
contents = gzip.compress(contents)
|
74
|
+
if self.__missing and not self.__parsed.modified and not missing_ok:
|
75
|
+
raise FileNotFoundError(self.path)
|
83
76
|
|
84
|
-
|
85
|
-
self.__dirty = False
|
86
|
-
else:
|
87
|
-
self.__dirty = True
|
77
|
+
return self.__parsed
|
88
78
|
|
89
79
|
def __repr__(self) -> str:
|
90
80
|
return f"{type(self).__qualname__}('{self.path}')"
|
foamlib/_files/_parsing.py
CHANGED
@@ -207,28 +207,29 @@ _FILE = (
|
|
207
207
|
)
|
208
208
|
|
209
209
|
|
210
|
-
class Parsed(Mapping[Tuple[str, ...], Union[FoamFileBase.
|
210
|
+
class Parsed(Mapping[Tuple[str, ...], Union[FoamFileBase._DataEntry, EllipsisType]]):
|
211
211
|
def __init__(self, contents: bytes) -> None:
|
212
212
|
self._parsed: MutableMapping[
|
213
213
|
Tuple[str, ...],
|
214
|
-
Tuple[int, Union[FoamFileBase.
|
214
|
+
Tuple[int, Union[FoamFileBase._DataEntry, EllipsisType], int],
|
215
215
|
] = {}
|
216
|
-
self._end = len(contents)
|
217
|
-
|
218
216
|
for parse_result in _FILE.parse_string(
|
219
217
|
contents.decode("latin-1"), parse_all=True
|
220
218
|
):
|
221
219
|
self._parsed.update(self._flatten_result(parse_result))
|
222
220
|
|
221
|
+
self.contents = contents
|
222
|
+
self.modified = False
|
223
|
+
|
223
224
|
@staticmethod
|
224
225
|
def _flatten_result(
|
225
226
|
parse_result: ParseResults, *, _keywords: Tuple[str, ...] = ()
|
226
227
|
) -> Mapping[
|
227
|
-
Tuple[str, ...], Tuple[int, Union[FoamFileBase.
|
228
|
+
Tuple[str, ...], Tuple[int, Union[FoamFileBase._DataEntry, EllipsisType], int]
|
228
229
|
]:
|
229
230
|
ret: MutableMapping[
|
230
231
|
Tuple[str, ...],
|
231
|
-
Tuple[int, Union[FoamFileBase.
|
232
|
+
Tuple[int, Union[FoamFileBase._DataEntry, EllipsisType], int],
|
232
233
|
] = {}
|
233
234
|
start = parse_result.locn_start
|
234
235
|
assert isinstance(start, int)
|
@@ -256,13 +257,58 @@ class Parsed(Mapping[Tuple[str, ...], Union[FoamFileBase.Data, EllipsisType]]):
|
|
256
257
|
|
257
258
|
def __getitem__(
|
258
259
|
self, keywords: Union[str, Tuple[str, ...]]
|
259
|
-
) -> Union[FoamFileBase.
|
260
|
+
) -> Union[FoamFileBase._DataEntry, EllipsisType]:
|
260
261
|
if isinstance(keywords, str):
|
261
262
|
keywords = (keywords,)
|
262
263
|
|
263
264
|
_, data, _ = self._parsed[keywords]
|
264
265
|
return data
|
265
266
|
|
267
|
+
def put(
|
268
|
+
self,
|
269
|
+
keywords: Tuple[str, ...],
|
270
|
+
data: Union[FoamFileBase._DataEntry, EllipsisType],
|
271
|
+
content: bytes,
|
272
|
+
) -> None:
|
273
|
+
start, end = self.entry_location(keywords, missing_ok=True)
|
274
|
+
|
275
|
+
diff = len(content) - (end - start)
|
276
|
+
for k, (s, d, e) in self._parsed.items():
|
277
|
+
if s > end:
|
278
|
+
self._parsed[k] = (s + diff, d, e + diff)
|
279
|
+
elif e > start:
|
280
|
+
self._parsed[k] = (s, d, e + diff)
|
281
|
+
|
282
|
+
self._parsed[keywords] = (start, data, end + diff)
|
283
|
+
|
284
|
+
self.contents = self.contents[:start] + content + self.contents[end:]
|
285
|
+
self.modified = True
|
286
|
+
|
287
|
+
for k in list(self._parsed):
|
288
|
+
if keywords != k and keywords == k[: len(keywords)]:
|
289
|
+
del self._parsed[k]
|
290
|
+
|
291
|
+
def __delitem__(self, keywords: Union[str, Tuple[str, ...]]) -> None:
|
292
|
+
if isinstance(keywords, str):
|
293
|
+
keywords = (keywords,)
|
294
|
+
|
295
|
+
start, end = self.entry_location(keywords)
|
296
|
+
del self._parsed[keywords]
|
297
|
+
|
298
|
+
for k in list(self._parsed):
|
299
|
+
if keywords == k[: len(keywords)]:
|
300
|
+
del self._parsed[k]
|
301
|
+
|
302
|
+
diff = end - start
|
303
|
+
for k, (s, d, e) in self._parsed.items():
|
304
|
+
if s > end:
|
305
|
+
self._parsed[k] = (s - diff, d, e - diff)
|
306
|
+
elif e > start:
|
307
|
+
self._parsed[k] = (s, d, e - diff)
|
308
|
+
|
309
|
+
self.contents = self.contents[:start] + self.contents[end:]
|
310
|
+
self.modified = True
|
311
|
+
|
266
312
|
def __contains__(self, keywords: object) -> bool:
|
267
313
|
return keywords in self._parsed
|
268
314
|
|
@@ -280,10 +326,11 @@ class Parsed(Mapping[Tuple[str, ...], Union[FoamFileBase.Data, EllipsisType]]):
|
|
280
326
|
except KeyError:
|
281
327
|
if missing_ok:
|
282
328
|
if len(keywords) > 1:
|
283
|
-
|
284
|
-
end
|
329
|
+
assert self[keywords[:-1]] is ...
|
330
|
+
start, end = self.entry_location(keywords[:-1])
|
331
|
+
end = self.contents.rindex(b"}", start, end)
|
285
332
|
else:
|
286
|
-
end = self.
|
333
|
+
end = len(self.contents)
|
287
334
|
|
288
335
|
start = end
|
289
336
|
else:
|
foamlib/_files/_serialization.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
foamlib/__init__.py,sha256=
|
1
|
+
foamlib/__init__.py,sha256=tS4b8eyl8WWPCCt7EmgXM2lcx8V1Zead47kwB3zJlNY,487
|
2
2
|
foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
foamlib/_cases/__init__.py,sha256=wTUHcUgU1CBgpu0cUMtksQ5VKG6B8CFu9xc3dWwsQuo,358
|
4
4
|
foamlib/_cases/_async.py,sha256=oQ2XnD9sansJLJDuUl3_vHaUM4L9hq2G97IcRjQAOPY,7920
|
@@ -9,14 +9,14 @@ foamlib/_cases/_subprocess.py,sha256=tzsBGe44EnQw3GWqRW1ktEZ4sNQ1sSHdJ_89zIfF5L0
|
|
9
9
|
foamlib/_cases/_sync.py,sha256=ENvn8zseRh6YOjAgqXHzmKhKFYXdzGIW5NoMHS_NKPY,6049
|
10
10
|
foamlib/_cases/_util.py,sha256=GNndpqw3Jg_S-Hxzl5vwRgD0czcTNb9NYHMhcfBoMBg,1493
|
11
11
|
foamlib/_files/__init__.py,sha256=-UqB9YTH6mrJfXCX00kPTAAY20XG64u1MGPw_1ewLVs,148
|
12
|
-
foamlib/_files/_base.py,sha256=
|
13
|
-
foamlib/_files/_files.py,sha256=
|
14
|
-
foamlib/_files/_io.py,sha256=
|
15
|
-
foamlib/_files/_parsing.py,sha256=
|
16
|
-
foamlib/_files/_serialization.py,sha256=
|
12
|
+
foamlib/_files/_base.py,sha256=A8084rU92w9Hh2BZAEIdE31qvm15fto1qOyQJhrP5DI,1945
|
13
|
+
foamlib/_files/_files.py,sha256=rvhb9mZFg1z6JSpb02E_8B2YD7Zmt5hh2v7rq19qC_c,14712
|
14
|
+
foamlib/_files/_io.py,sha256=07gaGhoJuXDB9i4AxvnIT_Np71RAU2ut2G5Lcyx8TaU,2244
|
15
|
+
foamlib/_files/_parsing.py,sha256=pqwWzlZwCTe7PxncYywO3OWd9Ppl9Oq8JYVpofxKJsY,11046
|
16
|
+
foamlib/_files/_serialization.py,sha256=Gy9v3iZGD-RF3pS7rauft7fpT33UIzRuOm0XH4rFHvA,3337
|
17
17
|
foamlib/_files/_util.py,sha256=UMzXmTFgvbp46w6k3oEZJoYC98pFgEK6LN5uLOwrlCg,397
|
18
|
-
foamlib-0.6.
|
19
|
-
foamlib-0.6.
|
20
|
-
foamlib-0.6.
|
21
|
-
foamlib-0.6.
|
22
|
-
foamlib-0.6.
|
18
|
+
foamlib-0.6.11.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
|
19
|
+
foamlib-0.6.11.dist-info/METADATA,sha256=VGwnlinUiBszBq9RzNnRWvWx0hkO9ziOY4jaKNmoJwc,7742
|
20
|
+
foamlib-0.6.11.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
21
|
+
foamlib-0.6.11.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
|
22
|
+
foamlib-0.6.11.dist-info/RECORD,,
|
File without changes
|
File without changes
|