foamlib 0.6.11__py3-none-any.whl → 0.6.12__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 +116 -101
- foamlib/_files/_io.py +9 -10
- foamlib/_files/_parsing.py +21 -25
- foamlib/_files/_serialization.py +19 -11
- foamlib/_files/_util.py +8 -3
- {foamlib-0.6.11.dist-info → foamlib-0.6.12.dist-info}/METADATA +1 -1
- foamlib-0.6.12.dist-info/RECORD +22 -0
- foamlib-0.6.11.dist-info/RECORD +0 -22
- {foamlib-0.6.11.dist-info → foamlib-0.6.12.dist-info}/LICENSE.txt +0 -0
- {foamlib-0.6.11.dist-info → foamlib-0.6.12.dist-info}/WHEEL +0 -0
- {foamlib-0.6.11.dist-info → foamlib-0.6.12.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,5 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import sys
|
2
4
|
from copy import deepcopy
|
3
5
|
from typing import Any, Optional, Tuple, Union, cast
|
@@ -39,13 +41,13 @@ class FoamFile(
|
|
39
41
|
):
|
40
42
|
"""An OpenFOAM dictionary within a file as a mutable mapping."""
|
41
43
|
|
42
|
-
def __init__(self, _file:
|
44
|
+
def __init__(self, _file: FoamFile, _keywords: tuple[str, ...]) -> None:
|
43
45
|
self._file = _file
|
44
46
|
self._keywords = _keywords
|
45
47
|
|
46
48
|
def __getitem__(
|
47
49
|
self, keyword: str
|
48
|
-
) ->
|
50
|
+
) -> FoamFileBase._DataEntry | FoamFile.SubDict:
|
49
51
|
return self._file[(*self._keywords, keyword)]
|
50
52
|
|
51
53
|
def __setitem__(
|
@@ -97,7 +99,8 @@ class FoamFile(
|
|
97
99
|
"""Alias of `self["FoamFile", "version"]`."""
|
98
100
|
ret = self["FoamFile", "version"]
|
99
101
|
if not isinstance(ret, (int, float)):
|
100
|
-
|
102
|
+
msg = "version is not a number"
|
103
|
+
raise TypeError(msg)
|
101
104
|
return ret
|
102
105
|
|
103
106
|
@version.setter
|
@@ -109,9 +112,11 @@ class FoamFile(
|
|
109
112
|
"""Alias of `self["FoamFile", "format"]`."""
|
110
113
|
ret = self["FoamFile", "format"]
|
111
114
|
if not isinstance(ret, str):
|
112
|
-
|
115
|
+
msg = "format is not a string"
|
116
|
+
raise TypeError(msg)
|
113
117
|
if ret not in ("ascii", "binary"):
|
114
|
-
|
118
|
+
msg = "format is not 'ascii' or 'binary'"
|
119
|
+
raise ValueError(msg)
|
115
120
|
return cast(Literal["ascii", "binary"], ret)
|
116
121
|
|
117
122
|
@format.setter
|
@@ -123,7 +128,8 @@ class FoamFile(
|
|
123
128
|
"""Alias of `self["FoamFile", "class"]`."""
|
124
129
|
ret = self["FoamFile", "class"]
|
125
130
|
if not isinstance(ret, str):
|
126
|
-
|
131
|
+
msg = "class is not a string"
|
132
|
+
raise TypeError(msg)
|
127
133
|
return ret
|
128
134
|
|
129
135
|
@class_.setter
|
@@ -135,7 +141,8 @@ class FoamFile(
|
|
135
141
|
"""Alias of `self["FoamFile", "location"]`."""
|
136
142
|
ret = self["FoamFile", "location"]
|
137
143
|
if not isinstance(ret, str):
|
138
|
-
|
144
|
+
msg = "location is not a string"
|
145
|
+
raise TypeError(msg)
|
139
146
|
return ret
|
140
147
|
|
141
148
|
@location.setter
|
@@ -147,7 +154,8 @@ class FoamFile(
|
|
147
154
|
"""Alias of `self["FoamFile", "object"]`."""
|
148
155
|
ret = self["FoamFile", "object"]
|
149
156
|
if not isinstance(ret, str):
|
150
|
-
|
157
|
+
msg = "object is not a string"
|
158
|
+
raise TypeError(msg)
|
151
159
|
return ret
|
152
160
|
|
153
161
|
@object_.setter
|
@@ -155,8 +163,8 @@ class FoamFile(
|
|
155
163
|
self["FoamFile", "object"] = value
|
156
164
|
|
157
165
|
def __getitem__(
|
158
|
-
self, keywords:
|
159
|
-
) ->
|
166
|
+
self, keywords: str | tuple[str, ...] | None
|
167
|
+
) -> FoamFileBase._DataEntry | FoamFile.SubDict:
|
160
168
|
if not keywords:
|
161
169
|
keywords = ()
|
162
170
|
elif not isinstance(keywords, tuple):
|
@@ -173,14 +181,14 @@ class FoamFile(
|
|
173
181
|
return deepcopy(value)
|
174
182
|
|
175
183
|
def __setitem__(
|
176
|
-
self, keywords:
|
184
|
+
self, keywords: str | tuple[str, ...] | None, data: FoamFileBase.Data
|
177
185
|
) -> None:
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
keywords = (keywords,)
|
186
|
+
if not keywords:
|
187
|
+
keywords = ()
|
188
|
+
elif not isinstance(keywords, tuple):
|
189
|
+
keywords = (keywords,)
|
183
190
|
|
191
|
+
with self:
|
184
192
|
try:
|
185
193
|
write_header = (
|
186
194
|
not self and "FoamFile" not in self and keywords != ("FoamFile",)
|
@@ -213,87 +221,90 @@ class FoamFile(
|
|
213
221
|
kind = Kind.DIMENSIONS
|
214
222
|
|
215
223
|
if (
|
216
|
-
kind
|
224
|
+
kind in (Kind.FIELD, Kind.BINARY_FIELD)
|
217
225
|
) and self.class_ == "dictionary":
|
218
|
-
if
|
219
|
-
class_ = "volScalarField"
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
+
if isinstance(data, (int, float)):
|
227
|
+
self.class_ = "volScalarField"
|
228
|
+
|
229
|
+
elif is_sequence(data) and data:
|
230
|
+
if isinstance(data[0], (int, float)):
|
231
|
+
if len(data) == 3:
|
232
|
+
self.class_ = "volVectorField"
|
233
|
+
elif len(data) == 6:
|
234
|
+
self.class_ = "volSymmTensorField"
|
235
|
+
elif len(data) == 9:
|
236
|
+
self.class_ = "volTensorField"
|
237
|
+
elif (
|
238
|
+
is_sequence(data[0])
|
239
|
+
and data[0]
|
240
|
+
and isinstance(data[0][0], (int, float))
|
241
|
+
):
|
242
|
+
if len(data[0]) == 3:
|
243
|
+
self.class_ = "volVectorField"
|
244
|
+
elif len(data[0]) == 6:
|
245
|
+
self.class_ = "volSymmTensorField"
|
246
|
+
elif len(data[0]) == 9:
|
247
|
+
self.class_ = "volTensorField"
|
248
|
+
|
249
|
+
parsed = self._get_parsed(missing_ok=True)
|
250
|
+
|
251
|
+
start, end = parsed.entry_location(keywords, missing_ok=True)
|
252
|
+
|
253
|
+
if start and not parsed.contents[:start].endswith(b"\n\n"):
|
254
|
+
if parsed.contents[:start].endswith(b"\n"):
|
255
|
+
before = b"\n" if len(keywords) <= 1 else b""
|
226
256
|
else:
|
227
|
-
|
228
|
-
|
229
|
-
self.class_ = class_
|
230
|
-
self[keywords] = data
|
231
|
-
|
257
|
+
before = b"\n\n" if len(keywords) <= 1 else b"\n"
|
232
258
|
else:
|
233
|
-
parsed = self._get_parsed(missing_ok=True)
|
234
|
-
|
235
|
-
start, end = parsed.entry_location(keywords, missing_ok=True)
|
236
|
-
|
237
259
|
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
260
|
|
261
|
+
if not parsed.contents[end:].strip() or parsed.contents[end:].startswith(
|
262
|
+
b"}"
|
263
|
+
):
|
264
|
+
after = b"\n" + b" " * (len(keywords) - 2)
|
265
|
+
else:
|
249
266
|
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
267
|
|
293
|
-
|
294
|
-
|
268
|
+
indentation = b" " * (len(keywords) - 1)
|
269
|
+
|
270
|
+
if isinstance(data, Mapping):
|
271
|
+
if isinstance(data, (FoamFile, FoamFile.SubDict)):
|
272
|
+
data = data.as_dict()
|
273
|
+
|
274
|
+
parsed.put(
|
275
|
+
keywords,
|
276
|
+
...,
|
277
|
+
before
|
278
|
+
+ indentation
|
279
|
+
+ dumps(keywords[-1])
|
280
|
+
+ b"\n"
|
281
|
+
+ indentation
|
282
|
+
+ b"{\n"
|
283
|
+
+ indentation
|
284
|
+
+ b"}"
|
285
|
+
+ after,
|
286
|
+
)
|
287
|
+
|
288
|
+
for k, v in data.items():
|
289
|
+
self[(*keywords, k)] = v
|
290
|
+
|
291
|
+
elif keywords:
|
292
|
+
parsed.put(
|
293
|
+
keywords,
|
294
|
+
deepcopy(data),
|
295
|
+
before
|
296
|
+
+ indentation
|
297
|
+
+ dumps(keywords[-1])
|
298
|
+
+ b" "
|
299
|
+
+ dumps(data, kind=kind)
|
300
|
+
+ b";"
|
301
|
+
+ after,
|
302
|
+
)
|
303
|
+
|
304
|
+
else:
|
305
|
+
parsed.put((), deepcopy(data), before + dumps(data, kind=kind) + after)
|
295
306
|
|
296
|
-
def __delitem__(self, keywords:
|
307
|
+
def __delitem__(self, keywords: str | tuple[str, ...] | None) -> None:
|
297
308
|
if not keywords:
|
298
309
|
keywords = ()
|
299
310
|
elif not isinstance(keywords, tuple):
|
@@ -302,12 +313,12 @@ class FoamFile(
|
|
302
313
|
with self:
|
303
314
|
del self._get_parsed()[keywords]
|
304
315
|
|
305
|
-
def _iter(self, keywords:
|
316
|
+
def _iter(self, keywords: tuple[str, ...] = ()) -> Iterator[str | None]:
|
306
317
|
yield from (
|
307
318
|
k[-1] if k else None for k in self._get_parsed() if k[:-1] == keywords
|
308
319
|
)
|
309
320
|
|
310
|
-
def __iter__(self) -> Iterator[
|
321
|
+
def __iter__(self) -> Iterator[str | None]:
|
311
322
|
yield from (k for k in self._iter() if k != "FoamFile")
|
312
323
|
|
313
324
|
def __contains__(self, keywords: object) -> bool:
|
@@ -348,11 +359,12 @@ class FoamFieldFile(FoamFile):
|
|
348
359
|
"""An OpenFOAM dictionary file representing a field as a mutable mapping."""
|
349
360
|
|
350
361
|
class BoundariesSubDict(FoamFile.SubDict):
|
351
|
-
def __getitem__(self, keyword: str) ->
|
362
|
+
def __getitem__(self, keyword: str) -> FoamFieldFile.BoundarySubDict:
|
352
363
|
value = super().__getitem__(keyword)
|
353
364
|
if not isinstance(value, FoamFieldFile.BoundarySubDict):
|
354
365
|
assert not isinstance(value, FoamFile.SubDict)
|
355
|
-
|
366
|
+
msg = f"boundary {keyword} is not a dictionary"
|
367
|
+
raise TypeError(msg)
|
356
368
|
return value
|
357
369
|
|
358
370
|
class BoundarySubDict(FoamFile.SubDict):
|
@@ -363,7 +375,8 @@ class FoamFieldFile(FoamFile):
|
|
363
375
|
"""Alias of `self["type"]`."""
|
364
376
|
ret = self["type"]
|
365
377
|
if not isinstance(ret, str):
|
366
|
-
|
378
|
+
msg = "type is not a string"
|
379
|
+
raise TypeError(msg)
|
367
380
|
return ret
|
368
381
|
|
369
382
|
@type.setter
|
@@ -392,8 +405,8 @@ class FoamFieldFile(FoamFile):
|
|
392
405
|
del self["value"]
|
393
406
|
|
394
407
|
def __getitem__(
|
395
|
-
self, keywords:
|
396
|
-
) ->
|
408
|
+
self, keywords: str | tuple[str, ...] | None
|
409
|
+
) -> FoamFileBase._DataEntry | FoamFile.SubDict:
|
397
410
|
if not keywords:
|
398
411
|
keywords = ()
|
399
412
|
elif not isinstance(keywords, tuple):
|
@@ -408,15 +421,16 @@ class FoamFieldFile(FoamFile):
|
|
408
421
|
return ret
|
409
422
|
|
410
423
|
@property
|
411
|
-
def dimensions(self) ->
|
424
|
+
def dimensions(self) -> FoamFile.DimensionSet | Sequence[float]:
|
412
425
|
"""Alias of `self["dimensions"]`."""
|
413
426
|
ret = self["dimensions"]
|
414
427
|
if not isinstance(ret, FoamFile.DimensionSet):
|
415
|
-
|
428
|
+
msg = "dimensions is not a DimensionSet"
|
429
|
+
raise TypeError(msg)
|
416
430
|
return ret
|
417
431
|
|
418
432
|
@dimensions.setter
|
419
|
-
def dimensions(self, value:
|
433
|
+
def dimensions(self, value: FoamFile.DimensionSet | Sequence[float]) -> None:
|
420
434
|
self["dimensions"] = value
|
421
435
|
|
422
436
|
@property
|
@@ -434,12 +448,13 @@ class FoamFieldFile(FoamFile):
|
|
434
448
|
self["internalField"] = value
|
435
449
|
|
436
450
|
@property
|
437
|
-
def boundary_field(self) ->
|
451
|
+
def boundary_field(self) -> FoamFieldFile.BoundariesSubDict:
|
438
452
|
"""Alias of `self["boundaryField"]`."""
|
439
453
|
ret = self["boundaryField"]
|
440
454
|
if not isinstance(ret, FoamFieldFile.BoundariesSubDict):
|
441
455
|
assert not isinstance(ret, FoamFile.SubDict)
|
442
|
-
|
456
|
+
msg = "boundaryField is not a dictionary"
|
457
|
+
raise TypeError(msg)
|
443
458
|
return ret
|
444
459
|
|
445
460
|
@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:
|