foamlib 0.6.11__py3-none-any.whl → 0.6.13__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/_async.py +23 -23
- foamlib/_cases/_base.py +25 -26
- foamlib/_cases/_run.py +52 -58
- foamlib/_cases/_slurm.py +7 -5
- foamlib/_cases/_subprocess.py +15 -13
- foamlib/_cases/_sync.py +25 -27
- foamlib/_cases/_util.py +13 -10
- foamlib/_files/_base.py +5 -3
- foamlib/_files/_files.py +139 -103
- foamlib/_files/_io.py +9 -10
- foamlib/_files/_parsing.py +96 -51
- foamlib/_files/_serialization.py +121 -28
- foamlib/_files/_util.py +8 -3
- {foamlib-0.6.11.dist-info → foamlib-0.6.13.dist-info}/METADATA +1 -1
- foamlib-0.6.13.dist-info/RECORD +22 -0
- foamlib-0.6.11.dist-info/RECORD +0 -22
- {foamlib-0.6.11.dist-info → foamlib-0.6.13.dist-info}/LICENSE.txt +0 -0
- {foamlib-0.6.11.dist-info → foamlib-0.6.13.dist-info}/WHEEL +0 -0
- {foamlib-0.6.11.dist-info → foamlib-0.6.13.dist-info}/top_level.txt +0 -0
foamlib/_cases/_sync.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import shutil
|
2
4
|
import sys
|
3
|
-
from
|
4
|
-
from typing import TYPE_CHECKING, Any, Callable, Optional, Type, Union, overload
|
5
|
+
from typing import TYPE_CHECKING, Any, Callable, overload
|
5
6
|
|
6
7
|
if sys.version_info >= (3, 9):
|
7
8
|
from collections.abc import Collection, Sequence
|
@@ -13,7 +14,6 @@ if sys.version_info >= (3, 11):
|
|
13
14
|
else:
|
14
15
|
from typing_extensions import Self
|
15
16
|
|
16
|
-
from .._files import FoamFieldFile
|
17
17
|
from ._base import FoamCaseBase
|
18
18
|
from ._run import FoamCaseRunBase
|
19
19
|
from ._subprocess import run_sync
|
@@ -21,6 +21,9 @@ from ._util import ValuedGenerator
|
|
21
21
|
|
22
22
|
if TYPE_CHECKING:
|
23
23
|
import os
|
24
|
+
from types import TracebackType
|
25
|
+
|
26
|
+
from .._files import FoamFieldFile
|
24
27
|
|
25
28
|
|
26
29
|
class FoamCase(FoamCaseRunBase):
|
@@ -36,7 +39,7 @@ class FoamCase(FoamCaseRunBase):
|
|
36
39
|
|
37
40
|
class TimeDirectory(FoamCaseRunBase.TimeDirectory):
|
38
41
|
@property
|
39
|
-
def _case(self) ->
|
42
|
+
def _case(self) -> FoamCase:
|
40
43
|
return FoamCase(self.path.parent)
|
41
44
|
|
42
45
|
def cell_centers(self) -> FoamFieldFile:
|
@@ -50,7 +53,7 @@ class FoamCase(FoamCaseRunBase):
|
|
50
53
|
|
51
54
|
@staticmethod
|
52
55
|
def _run(
|
53
|
-
cmd:
|
56
|
+
cmd: Sequence[str | os.PathLike[str]] | str,
|
54
57
|
*,
|
55
58
|
cpus: int,
|
56
59
|
**kwargs: Any,
|
@@ -58,34 +61,29 @@ class FoamCase(FoamCaseRunBase):
|
|
58
61
|
run_sync(cmd, **kwargs)
|
59
62
|
|
60
63
|
@staticmethod
|
61
|
-
def _rmtree(
|
62
|
-
path: Union["os.PathLike[str]", str], *, ignore_errors: bool = False
|
63
|
-
) -> None:
|
64
|
+
def _rmtree(path: os.PathLike[str] | str, *, ignore_errors: bool = False) -> None:
|
64
65
|
shutil.rmtree(path, ignore_errors=ignore_errors)
|
65
66
|
|
66
67
|
@staticmethod
|
67
68
|
def _copytree(
|
68
|
-
src:
|
69
|
-
dest:
|
69
|
+
src: os.PathLike[str] | str,
|
70
|
+
dest: os.PathLike[str] | str,
|
70
71
|
*,
|
71
72
|
symlinks: bool = False,
|
72
|
-
ignore:
|
73
|
-
|
74
|
-
] = None,
|
73
|
+
ignore: Callable[[os.PathLike[str] | str, Collection[str]], Collection[str]]
|
74
|
+
| None = None,
|
75
75
|
) -> None:
|
76
76
|
shutil.copytree(src, dest, symlinks=symlinks, ignore=ignore)
|
77
77
|
|
78
78
|
@overload
|
79
|
-
def __getitem__(
|
80
|
-
self, index: Union[int, float, str]
|
81
|
-
) -> "FoamCase.TimeDirectory": ...
|
79
|
+
def __getitem__(self, index: int | float | str) -> FoamCase.TimeDirectory: ...
|
82
80
|
|
83
81
|
@overload
|
84
|
-
def __getitem__(self, index: slice) -> Sequence[
|
82
|
+
def __getitem__(self, index: slice) -> Sequence[FoamCase.TimeDirectory]: ...
|
85
83
|
|
86
84
|
def __getitem__(
|
87
|
-
self, index:
|
88
|
-
) ->
|
85
|
+
self, index: int | slice | float | str
|
86
|
+
) -> FoamCase.TimeDirectory | Sequence[FoamCase.TimeDirectory]:
|
89
87
|
ret = super().__getitem__(index)
|
90
88
|
if isinstance(ret, FoamCaseBase.TimeDirectory):
|
91
89
|
return FoamCase.TimeDirectory(ret)
|
@@ -96,9 +94,9 @@ class FoamCase(FoamCaseRunBase):
|
|
96
94
|
|
97
95
|
def __exit__(
|
98
96
|
self,
|
99
|
-
exc_type:
|
100
|
-
exc_val:
|
101
|
-
exc_tb:
|
97
|
+
exc_type: type[BaseException] | None,
|
98
|
+
exc_val: BaseException | None,
|
99
|
+
exc_tb: TracebackType | None,
|
102
100
|
) -> None:
|
103
101
|
self._rmtree(self.path)
|
104
102
|
|
@@ -117,10 +115,10 @@ class FoamCase(FoamCaseRunBase):
|
|
117
115
|
|
118
116
|
def run(
|
119
117
|
self,
|
120
|
-
cmd:
|
118
|
+
cmd: Sequence[str | os.PathLike[str]] | str | None = None,
|
121
119
|
*,
|
122
|
-
parallel:
|
123
|
-
cpus:
|
120
|
+
parallel: bool | None = None,
|
121
|
+
cpus: int | None = None,
|
124
122
|
check: bool = True,
|
125
123
|
log: bool = True,
|
126
124
|
) -> None:
|
@@ -158,7 +156,7 @@ class FoamCase(FoamCaseRunBase):
|
|
158
156
|
for _ in self._restore_0_dir_calls():
|
159
157
|
pass
|
160
158
|
|
161
|
-
def copy(self, dst:
|
159
|
+
def copy(self, dst: os.PathLike[str] | str | None = None) -> Self:
|
162
160
|
"""
|
163
161
|
Make a copy of this case.
|
164
162
|
|
@@ -173,7 +171,7 @@ class FoamCase(FoamCaseRunBase):
|
|
173
171
|
|
174
172
|
return calls.value
|
175
173
|
|
176
|
-
def clone(self, dst:
|
174
|
+
def clone(self, dst: os.PathLike[str] | str | None = None) -> Self:
|
177
175
|
"""
|
178
176
|
Clone this case (make a clean copy).
|
179
177
|
|
foamlib/_cases/_util.py
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import functools
|
2
4
|
import sys
|
3
|
-
from types import TracebackType
|
4
5
|
from typing import (
|
6
|
+
TYPE_CHECKING,
|
5
7
|
Any,
|
6
8
|
AsyncContextManager,
|
7
9
|
Callable,
|
8
10
|
Generic,
|
9
|
-
Optional,
|
10
|
-
Type,
|
11
11
|
TypeVar,
|
12
12
|
)
|
13
13
|
|
14
|
+
if TYPE_CHECKING:
|
15
|
+
from types import TracebackType
|
16
|
+
|
14
17
|
if sys.version_info >= (3, 9):
|
15
18
|
from collections.abc import Generator
|
16
19
|
else:
|
@@ -23,7 +26,7 @@ R = TypeVar("R")
|
|
23
26
|
|
24
27
|
|
25
28
|
class ValuedGenerator(Generic[Y, S, R]):
|
26
|
-
def __init__(self, generator: Generator[Y, S, R]):
|
29
|
+
def __init__(self, generator: Generator[Y, S, R]) -> None:
|
27
30
|
self._generator = generator
|
28
31
|
|
29
32
|
def __iter__(self) -> Generator[Y, S, R]:
|
@@ -32,7 +35,7 @@ class ValuedGenerator(Generic[Y, S, R]):
|
|
32
35
|
|
33
36
|
|
34
37
|
class _AwaitableAsyncContextManager(Generic[R]):
|
35
|
-
def __init__(self, cm:
|
38
|
+
def __init__(self, cm: AsyncContextManager[R]) -> None:
|
36
39
|
self._cm = cm
|
37
40
|
|
38
41
|
def __await__(self) -> Generator[Any, Any, R]:
|
@@ -43,15 +46,15 @@ class _AwaitableAsyncContextManager(Generic[R]):
|
|
43
46
|
|
44
47
|
async def __aexit__(
|
45
48
|
self,
|
46
|
-
exc_type:
|
47
|
-
exc_val:
|
48
|
-
exc_tb:
|
49
|
-
) ->
|
49
|
+
exc_type: type[BaseException] | None,
|
50
|
+
exc_val: BaseException | None,
|
51
|
+
exc_tb: TracebackType | None,
|
52
|
+
) -> bool | None:
|
50
53
|
return await self._cm.__aexit__(exc_type, exc_val, exc_tb)
|
51
54
|
|
52
55
|
|
53
56
|
def awaitableasynccontextmanager(
|
54
|
-
cm: Callable[...,
|
57
|
+
cm: Callable[..., AsyncContextManager[R]],
|
55
58
|
) -> Callable[..., _AwaitableAsyncContextManager[R]]:
|
56
59
|
@functools.wraps(cm)
|
57
60
|
def f(*args: Any, **kwargs: Any) -> _AwaitableAsyncContextManager[R]:
|
foamlib/_files/_base.py
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import sys
|
2
4
|
from dataclasses import dataclass
|
3
5
|
from typing import TYPE_CHECKING, Dict, NamedTuple, Optional, Tuple, Union
|
@@ -33,9 +35,9 @@ class FoamFileBase:
|
|
33
35
|
|
34
36
|
@dataclass
|
35
37
|
class Dimensioned:
|
36
|
-
value:
|
37
|
-
dimensions:
|
38
|
-
name:
|
38
|
+
value: FoamFileBase._Tensor = 0
|
39
|
+
dimensions: FoamFileBase.DimensionSet | Sequence[float] = ()
|
40
|
+
name: str | None = None
|
39
41
|
|
40
42
|
def __post_init__(self) -> None:
|
41
43
|
if not isinstance(self.dimensions, FoamFileBase.DimensionSet):
|
foamlib/_files/_files.py
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import os
|
1
4
|
import sys
|
2
5
|
from copy import deepcopy
|
3
6
|
from typing import Any, Optional, Tuple, Union, cast
|
@@ -14,7 +17,7 @@ else:
|
|
14
17
|
|
15
18
|
from ._base import FoamFileBase
|
16
19
|
from ._io import FoamFileIO
|
17
|
-
from ._serialization import Kind, dumps
|
20
|
+
from ._serialization import Kind, dumps, normalize
|
18
21
|
from ._util import is_sequence
|
19
22
|
|
20
23
|
|
@@ -39,13 +42,13 @@ class FoamFile(
|
|
39
42
|
):
|
40
43
|
"""An OpenFOAM dictionary within a file as a mutable mapping."""
|
41
44
|
|
42
|
-
def __init__(self, _file:
|
45
|
+
def __init__(self, _file: FoamFile, _keywords: tuple[str, ...]) -> None:
|
43
46
|
self._file = _file
|
44
47
|
self._keywords = _keywords
|
45
48
|
|
46
49
|
def __getitem__(
|
47
50
|
self, keyword: str
|
48
|
-
) ->
|
51
|
+
) -> FoamFileBase._DataEntry | FoamFile.SubDict:
|
49
52
|
return self._file[(*self._keywords, keyword)]
|
50
53
|
|
51
54
|
def __setitem__(
|
@@ -97,7 +100,8 @@ class FoamFile(
|
|
97
100
|
"""Alias of `self["FoamFile", "version"]`."""
|
98
101
|
ret = self["FoamFile", "version"]
|
99
102
|
if not isinstance(ret, (int, float)):
|
100
|
-
|
103
|
+
msg = "version is not a number"
|
104
|
+
raise TypeError(msg)
|
101
105
|
return ret
|
102
106
|
|
103
107
|
@version.setter
|
@@ -109,9 +113,11 @@ class FoamFile(
|
|
109
113
|
"""Alias of `self["FoamFile", "format"]`."""
|
110
114
|
ret = self["FoamFile", "format"]
|
111
115
|
if not isinstance(ret, str):
|
112
|
-
|
116
|
+
msg = "format is not a string"
|
117
|
+
raise TypeError(msg)
|
113
118
|
if ret not in ("ascii", "binary"):
|
114
|
-
|
119
|
+
msg = "format is not 'ascii' or 'binary'"
|
120
|
+
raise ValueError(msg)
|
115
121
|
return cast(Literal["ascii", "binary"], ret)
|
116
122
|
|
117
123
|
@format.setter
|
@@ -123,7 +129,8 @@ class FoamFile(
|
|
123
129
|
"""Alias of `self["FoamFile", "class"]`."""
|
124
130
|
ret = self["FoamFile", "class"]
|
125
131
|
if not isinstance(ret, str):
|
126
|
-
|
132
|
+
msg = "class is not a string"
|
133
|
+
raise TypeError(msg)
|
127
134
|
return ret
|
128
135
|
|
129
136
|
@class_.setter
|
@@ -135,7 +142,8 @@ class FoamFile(
|
|
135
142
|
"""Alias of `self["FoamFile", "location"]`."""
|
136
143
|
ret = self["FoamFile", "location"]
|
137
144
|
if not isinstance(ret, str):
|
138
|
-
|
145
|
+
msg = "location is not a string"
|
146
|
+
raise TypeError(msg)
|
139
147
|
return ret
|
140
148
|
|
141
149
|
@location.setter
|
@@ -147,7 +155,8 @@ class FoamFile(
|
|
147
155
|
"""Alias of `self["FoamFile", "object"]`."""
|
148
156
|
ret = self["FoamFile", "object"]
|
149
157
|
if not isinstance(ret, str):
|
150
|
-
|
158
|
+
msg = "object is not a string"
|
159
|
+
raise TypeError(msg)
|
151
160
|
return ret
|
152
161
|
|
153
162
|
@object_.setter
|
@@ -155,8 +164,8 @@ class FoamFile(
|
|
155
164
|
self["FoamFile", "object"] = value
|
156
165
|
|
157
166
|
def __getitem__(
|
158
|
-
self, keywords:
|
159
|
-
) ->
|
167
|
+
self, keywords: str | tuple[str, ...] | None
|
168
|
+
) -> FoamFileBase._DataEntry | FoamFile.SubDict:
|
160
169
|
if not keywords:
|
161
170
|
keywords = ()
|
162
171
|
elif not isinstance(keywords, tuple):
|
@@ -173,14 +182,14 @@ class FoamFile(
|
|
173
182
|
return deepcopy(value)
|
174
183
|
|
175
184
|
def __setitem__(
|
176
|
-
self, keywords:
|
185
|
+
self, keywords: str | tuple[str, ...] | None, data: FoamFileBase.Data
|
177
186
|
) -> None:
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
keywords = (keywords,)
|
187
|
+
if not keywords:
|
188
|
+
keywords = ()
|
189
|
+
elif not isinstance(keywords, tuple):
|
190
|
+
keywords = (keywords,)
|
183
191
|
|
192
|
+
with self:
|
184
193
|
try:
|
185
194
|
write_header = (
|
186
195
|
not self and "FoamFile" not in self and keywords != ("FoamFile",)
|
@@ -208,92 +217,115 @@ class FoamFile(
|
|
208
217
|
or keywords[2].endswith("Gradient")
|
209
218
|
)
|
210
219
|
):
|
211
|
-
|
220
|
+
if self.format == "binary":
|
221
|
+
arch = self.get(("FoamFile", "arch"), default=None)
|
222
|
+
assert arch is None or isinstance(arch, str)
|
223
|
+
if (arch is not None and "scalar=32" in arch) or (
|
224
|
+
arch is None
|
225
|
+
and os.environ.get("WM_PRECISION_OPTION", default="DP") == "SP"
|
226
|
+
):
|
227
|
+
kind = Kind.SINGLE_PRECISION_BINARY_FIELD
|
228
|
+
else:
|
229
|
+
kind = Kind.DOUBLE_PRECISION_BINARY_FIELD
|
230
|
+
else:
|
231
|
+
kind = Kind.ASCII_FIELD
|
212
232
|
elif keywords == ("dimensions",):
|
213
233
|
kind = Kind.DIMENSIONS
|
214
234
|
|
215
235
|
if (
|
216
|
-
kind
|
236
|
+
kind
|
237
|
+
in (
|
238
|
+
Kind.ASCII_FIELD,
|
239
|
+
Kind.DOUBLE_PRECISION_BINARY_FIELD,
|
240
|
+
Kind.SINGLE_PRECISION_BINARY_FIELD,
|
241
|
+
)
|
217
242
|
) and self.class_ == "dictionary":
|
218
|
-
if
|
219
|
-
class_ = "volScalarField"
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
243
|
+
if isinstance(data, (int, float)):
|
244
|
+
self.class_ = "volScalarField"
|
245
|
+
|
246
|
+
elif is_sequence(data) and data:
|
247
|
+
if isinstance(data[0], (int, float)):
|
248
|
+
if len(data) == 3:
|
249
|
+
self.class_ = "volVectorField"
|
250
|
+
elif len(data) == 6:
|
251
|
+
self.class_ = "volSymmTensorField"
|
252
|
+
elif len(data) == 9:
|
253
|
+
self.class_ = "volTensorField"
|
254
|
+
elif (
|
255
|
+
is_sequence(data[0])
|
256
|
+
and data[0]
|
257
|
+
and isinstance(data[0][0], (int, float))
|
258
|
+
):
|
259
|
+
if len(data[0]) == 3:
|
260
|
+
self.class_ = "volVectorField"
|
261
|
+
elif len(data[0]) == 6:
|
262
|
+
self.class_ = "volSymmTensorField"
|
263
|
+
elif len(data[0]) == 9:
|
264
|
+
self.class_ = "volTensorField"
|
265
|
+
|
266
|
+
parsed = self._get_parsed(missing_ok=True)
|
267
|
+
|
268
|
+
start, end = parsed.entry_location(keywords, missing_ok=True)
|
269
|
+
|
270
|
+
if start and not parsed.contents[:start].endswith(b"\n\n"):
|
271
|
+
if parsed.contents[:start].endswith(b"\n"):
|
272
|
+
before = b"\n" if len(keywords) <= 1 else b""
|
226
273
|
else:
|
227
|
-
|
228
|
-
|
229
|
-
self.class_ = class_
|
230
|
-
self[keywords] = data
|
231
|
-
|
274
|
+
before = b"\n\n" if len(keywords) <= 1 else b"\n"
|
232
275
|
else:
|
233
|
-
parsed = self._get_parsed(missing_ok=True)
|
234
|
-
|
235
|
-
start, end = parsed.entry_location(keywords, missing_ok=True)
|
236
|
-
|
237
276
|
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
277
|
|
278
|
+
if not parsed.contents[end:].strip() or parsed.contents[end:].startswith(
|
279
|
+
b"}"
|
280
|
+
):
|
281
|
+
after = b"\n" + b" " * (len(keywords) - 2)
|
282
|
+
else:
|
249
283
|
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
|
-
):
|
255
|
-
after = b"\n" + after
|
256
|
-
|
257
|
-
indentation = b" " * (len(keywords) - 1)
|
258
|
-
|
259
|
-
if isinstance(data, Mapping):
|
260
|
-
if isinstance(data, (FoamFile, FoamFile.SubDict)):
|
261
|
-
data = data.as_dict()
|
262
|
-
|
263
|
-
parsed.put(
|
264
|
-
keywords,
|
265
|
-
...,
|
266
|
-
before
|
267
|
-
+ indentation
|
268
|
-
+ dumps(keywords[-1])
|
269
|
-
+ b"\n"
|
270
|
-
+ indentation
|
271
|
-
+ b"{\n"
|
272
|
-
+ indentation
|
273
|
-
+ b"}"
|
274
|
-
+ after,
|
275
|
-
)
|
276
|
-
|
277
|
-
for k, v in data.items():
|
278
|
-
self[(*keywords, k)] = v
|
279
|
-
|
280
|
-
elif keywords:
|
281
|
-
parsed.put(
|
282
|
-
keywords,
|
283
|
-
data,
|
284
|
-
before
|
285
|
-
+ indentation
|
286
|
-
+ dumps(keywords[-1])
|
287
|
-
+ b" "
|
288
|
-
+ dumps(data, kind=kind)
|
289
|
-
+ b";"
|
290
|
-
+ after,
|
291
|
-
)
|
292
284
|
|
293
|
-
|
294
|
-
|
285
|
+
indentation = b" " * (len(keywords) - 1)
|
286
|
+
|
287
|
+
if isinstance(data, Mapping):
|
288
|
+
if isinstance(data, (FoamFile, FoamFile.SubDict)):
|
289
|
+
data = data.as_dict()
|
290
|
+
|
291
|
+
parsed.put(
|
292
|
+
keywords,
|
293
|
+
...,
|
294
|
+
before
|
295
|
+
+ indentation
|
296
|
+
+ dumps(keywords[-1])
|
297
|
+
+ b"\n"
|
298
|
+
+ indentation
|
299
|
+
+ b"{\n"
|
300
|
+
+ indentation
|
301
|
+
+ b"}"
|
302
|
+
+ after,
|
303
|
+
)
|
304
|
+
|
305
|
+
for k, v in data.items():
|
306
|
+
self[(*keywords, k)] = v
|
307
|
+
|
308
|
+
elif keywords:
|
309
|
+
parsed.put(
|
310
|
+
keywords,
|
311
|
+
normalize(data, kind=kind),
|
312
|
+
before
|
313
|
+
+ indentation
|
314
|
+
+ dumps(keywords[-1])
|
315
|
+
+ b" "
|
316
|
+
+ dumps(data, kind=kind)
|
317
|
+
+ b";"
|
318
|
+
+ after,
|
319
|
+
)
|
320
|
+
|
321
|
+
else:
|
322
|
+
parsed.put(
|
323
|
+
(),
|
324
|
+
normalize(data, kind=kind),
|
325
|
+
before + dumps(data, kind=kind) + after,
|
326
|
+
)
|
295
327
|
|
296
|
-
def __delitem__(self, keywords:
|
328
|
+
def __delitem__(self, keywords: str | tuple[str, ...] | None) -> None:
|
297
329
|
if not keywords:
|
298
330
|
keywords = ()
|
299
331
|
elif not isinstance(keywords, tuple):
|
@@ -302,12 +334,12 @@ class FoamFile(
|
|
302
334
|
with self:
|
303
335
|
del self._get_parsed()[keywords]
|
304
336
|
|
305
|
-
def _iter(self, keywords:
|
337
|
+
def _iter(self, keywords: tuple[str, ...] = ()) -> Iterator[str | None]:
|
306
338
|
yield from (
|
307
339
|
k[-1] if k else None for k in self._get_parsed() if k[:-1] == keywords
|
308
340
|
)
|
309
341
|
|
310
|
-
def __iter__(self) -> Iterator[
|
342
|
+
def __iter__(self) -> Iterator[str | None]:
|
311
343
|
yield from (k for k in self._iter() if k != "FoamFile")
|
312
344
|
|
313
345
|
def __contains__(self, keywords: object) -> bool:
|
@@ -348,11 +380,12 @@ class FoamFieldFile(FoamFile):
|
|
348
380
|
"""An OpenFOAM dictionary file representing a field as a mutable mapping."""
|
349
381
|
|
350
382
|
class BoundariesSubDict(FoamFile.SubDict):
|
351
|
-
def __getitem__(self, keyword: str) ->
|
383
|
+
def __getitem__(self, keyword: str) -> FoamFieldFile.BoundarySubDict:
|
352
384
|
value = super().__getitem__(keyword)
|
353
385
|
if not isinstance(value, FoamFieldFile.BoundarySubDict):
|
354
386
|
assert not isinstance(value, FoamFile.SubDict)
|
355
|
-
|
387
|
+
msg = f"boundary {keyword} is not a dictionary"
|
388
|
+
raise TypeError(msg)
|
356
389
|
return value
|
357
390
|
|
358
391
|
class BoundarySubDict(FoamFile.SubDict):
|
@@ -363,7 +396,8 @@ class FoamFieldFile(FoamFile):
|
|
363
396
|
"""Alias of `self["type"]`."""
|
364
397
|
ret = self["type"]
|
365
398
|
if not isinstance(ret, str):
|
366
|
-
|
399
|
+
msg = "type is not a string"
|
400
|
+
raise TypeError(msg)
|
367
401
|
return ret
|
368
402
|
|
369
403
|
@type.setter
|
@@ -392,8 +426,8 @@ class FoamFieldFile(FoamFile):
|
|
392
426
|
del self["value"]
|
393
427
|
|
394
428
|
def __getitem__(
|
395
|
-
self, keywords:
|
396
|
-
) ->
|
429
|
+
self, keywords: str | tuple[str, ...] | None
|
430
|
+
) -> FoamFileBase._DataEntry | FoamFile.SubDict:
|
397
431
|
if not keywords:
|
398
432
|
keywords = ()
|
399
433
|
elif not isinstance(keywords, tuple):
|
@@ -408,15 +442,16 @@ class FoamFieldFile(FoamFile):
|
|
408
442
|
return ret
|
409
443
|
|
410
444
|
@property
|
411
|
-
def dimensions(self) ->
|
445
|
+
def dimensions(self) -> FoamFile.DimensionSet | Sequence[float]:
|
412
446
|
"""Alias of `self["dimensions"]`."""
|
413
447
|
ret = self["dimensions"]
|
414
448
|
if not isinstance(ret, FoamFile.DimensionSet):
|
415
|
-
|
449
|
+
msg = "dimensions is not a DimensionSet"
|
450
|
+
raise TypeError(msg)
|
416
451
|
return ret
|
417
452
|
|
418
453
|
@dimensions.setter
|
419
|
-
def dimensions(self, value:
|
454
|
+
def dimensions(self, value: FoamFile.DimensionSet | Sequence[float]) -> None:
|
420
455
|
self["dimensions"] = value
|
421
456
|
|
422
457
|
@property
|
@@ -434,12 +469,13 @@ class FoamFieldFile(FoamFile):
|
|
434
469
|
self["internalField"] = value
|
435
470
|
|
436
471
|
@property
|
437
|
-
def boundary_field(self) ->
|
472
|
+
def boundary_field(self) -> FoamFieldFile.BoundariesSubDict:
|
438
473
|
"""Alias of `self["boundaryField"]`."""
|
439
474
|
ret = self["boundaryField"]
|
440
475
|
if not isinstance(ret, FoamFieldFile.BoundariesSubDict):
|
441
476
|
assert not isinstance(ret, FoamFile.SubDict)
|
442
|
-
|
477
|
+
msg = "boundaryField is not a dictionary"
|
478
|
+
raise TypeError(msg)
|
443
479
|
return ret
|
444
480
|
|
445
481
|
@boundary_field.setter
|
foamlib/_files/_io.py
CHANGED
@@ -1,12 +1,10 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import gzip
|
2
4
|
import sys
|
3
5
|
from pathlib import Path
|
4
|
-
from types import TracebackType
|
5
6
|
from typing import (
|
6
7
|
TYPE_CHECKING,
|
7
|
-
Optional,
|
8
|
-
Type,
|
9
|
-
Union,
|
10
8
|
)
|
11
9
|
|
12
10
|
if sys.version_info >= (3, 11):
|
@@ -18,14 +16,15 @@ from ._parsing import Parsed
|
|
18
16
|
|
19
17
|
if TYPE_CHECKING:
|
20
18
|
import os
|
19
|
+
from types import TracebackType
|
21
20
|
|
22
21
|
|
23
22
|
class FoamFileIO:
|
24
|
-
def __init__(self, path:
|
23
|
+
def __init__(self, path: os.PathLike[str] | str) -> None:
|
25
24
|
self.path = Path(path).absolute()
|
26
25
|
|
27
|
-
self.__parsed:
|
28
|
-
self.__missing:
|
26
|
+
self.__parsed: Parsed | None = None
|
27
|
+
self.__missing: bool | None = None
|
29
28
|
self.__defer_io = 0
|
30
29
|
|
31
30
|
def __enter__(self) -> Self:
|
@@ -36,9 +35,9 @@ class FoamFileIO:
|
|
36
35
|
|
37
36
|
def __exit__(
|
38
37
|
self,
|
39
|
-
exc_type:
|
40
|
-
exc_val:
|
41
|
-
exc_tb:
|
38
|
+
exc_type: type[BaseException] | None,
|
39
|
+
exc_val: BaseException | None,
|
40
|
+
exc_tb: TracebackType | None,
|
42
41
|
) -> None:
|
43
42
|
self.__defer_io -= 1
|
44
43
|
if self.__defer_io == 0:
|