foamlib 0.2.5__py3-none-any.whl → 0.2.7__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 CHANGED
@@ -1,7 +1,9 @@
1
- __version__ = "0.2.5"
1
+ """A Python interface for interacting with OpenFOAM."""
2
2
 
3
- from ._cases import FoamCase, AsyncFoamCase, FoamCaseBase
4
- from ._dictionaries import FoamFile, FoamFieldFile, FoamDictionaryBase
3
+ __version__ = "0.2.7"
4
+
5
+ from ._cases import AsyncFoamCase, FoamCase, FoamCaseBase
6
+ from ._dictionaries import FoamDictionaryBase, FoamFieldFile, FoamFile
5
7
 
6
8
  __all__ = [
7
9
  "FoamCase",
foamlib/_cases.py CHANGED
@@ -1,11 +1,10 @@
1
- import sys
2
- import os
3
1
  import asyncio
4
2
  import multiprocessing
3
+ import os
5
4
  import shutil
6
-
7
- from pathlib import Path
5
+ import sys
8
6
  from contextlib import asynccontextmanager
7
+ from pathlib import Path
9
8
  from typing import (
10
9
  Optional,
11
10
  Union,
@@ -14,22 +13,22 @@ from typing import (
14
13
 
15
14
  if sys.version_info >= (3, 9):
16
15
  from collections.abc import (
17
- Collection,
18
- Mapping,
19
- Set,
20
- Sequence,
21
16
  AsyncGenerator,
22
17
  Callable,
18
+ Collection,
23
19
  Iterator,
20
+ Mapping,
21
+ Sequence,
22
+ Set,
24
23
  )
25
24
  else:
26
- from typing import Collection, Mapping, Sequence, AsyncGenerator, Callable, Iterator
27
25
  from typing import AbstractSet as Set
26
+ from typing import AsyncGenerator, Callable, Collection, Iterator, Mapping, Sequence
28
27
 
29
28
  import aioshutil
30
29
 
31
- from ._util import is_sequence, run_process, run_process_async, CalledProcessError
32
- from ._dictionaries import FoamFile, FoamFieldFile
30
+ from ._dictionaries import FoamFieldFile, FoamFile
31
+ from ._util import CalledProcessError, is_sequence, run_process, run_process_async
33
32
 
34
33
 
35
34
  class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
@@ -54,16 +53,12 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
54
53
 
55
54
  @property
56
55
  def time(self) -> float:
57
- """
58
- The time that corresponds to this directory.
59
- """
56
+ """The time that corresponds to this directory."""
60
57
  return float(self.path.name)
61
58
 
62
59
  @property
63
60
  def name(self) -> str:
64
- """
65
- The name of this time directory.
66
- """
61
+ """The name of this time directory."""
67
62
  return self.path.name
68
63
 
69
64
  def __getitem__(self, key: str) -> FoamFieldFile:
@@ -172,9 +167,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
172
167
  return ignore
173
168
 
174
169
  def _clean_script(self) -> Optional[Path]:
175
- """
176
- Return the path to the (All)clean script, or None if no clean script is found.
177
- """
170
+ """Return the path to the (All)clean script, or None if no clean script is found."""
178
171
  clean = self.path / "clean"
179
172
  all_clean = self.path / "Allclean"
180
173
 
@@ -186,9 +179,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
186
179
  return None
187
180
 
188
181
  def _run_script(self, *, parallel: Optional[bool]) -> Optional[Path]:
189
- """
190
- Return the path to the (All)run script, or None if no run script is found.
191
- """
182
+ """Return the path to the (All)run script, or None if no run script is found."""
192
183
  run = self.path / "run"
193
184
  run_parallel = self.path / "run-parallel"
194
185
  all_run = self.path / "Allrun"
@@ -213,9 +204,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
213
204
  return None
214
205
 
215
206
  def _env(self) -> Mapping[str, str]:
216
- """
217
- Return the environment variables for this case.
218
- """
207
+ """Return the environment variables for this case."""
219
208
  env = os.environ.copy()
220
209
  env["PWD"] = str(self.path)
221
210
  return env
@@ -237,22 +226,16 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
237
226
 
238
227
  @property
239
228
  def name(self) -> str:
240
- """
241
- The name of the case.
242
- """
229
+ """The name of the case."""
243
230
  return self.path.name
244
231
 
245
232
  def file(self, path: Union[Path, str]) -> FoamFile:
246
- """
247
- Return a FoamFile object for the given path in the case.
248
- """
233
+ """Return a FoamFile object for the given path in the case."""
249
234
  return FoamFile(self.path / path)
250
235
 
251
236
  @property
252
237
  def _nsubdomains(self) -> Optional[int]:
253
- """
254
- Return the number of subdomains as set in the decomposeParDict, or None if no decomposeParDict is found.
255
- """
238
+ """Return the number of subdomains as set in the decomposeParDict, or None if no decomposeParDict is found."""
256
239
  try:
257
240
  nsubdomains = self.decompose_par_dict["numberOfSubdomains"]
258
241
  if not isinstance(nsubdomains, int):
@@ -265,16 +248,12 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
265
248
 
266
249
  @property
267
250
  def _nprocessors(self) -> int:
268
- """
269
- Return the number of processor directories in the case.
270
- """
251
+ """Return the number of processor directories in the case."""
271
252
  return len(list(self.path.glob("processor*")))
272
253
 
273
254
  @property
274
255
  def application(self) -> str:
275
- """
276
- The application name as set in the controlDict.
277
- """
256
+ """The application name as set in the controlDict."""
278
257
  application = self.control_dict["application"]
279
258
  if not isinstance(application, str):
280
259
  raise TypeError(f"application in {self.control_dict} is not a string")
@@ -282,51 +261,37 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
282
261
 
283
262
  @property
284
263
  def control_dict(self) -> FoamFile:
285
- """
286
- The controlDict file.
287
- """
264
+ """The controlDict file."""
288
265
  return self.file("system/controlDict")
289
266
 
290
267
  @property
291
268
  def fv_schemes(self) -> FoamFile:
292
- """
293
- The fvSchemes file.
294
- """
269
+ """The fvSchemes file."""
295
270
  return self.file("system/fvSchemes")
296
271
 
297
272
  @property
298
273
  def fv_solution(self) -> FoamFile:
299
- """
300
- The fvSolution file.
301
- """
274
+ """The fvSolution file."""
302
275
  return self.file("system/fvSolution")
303
276
 
304
277
  @property
305
278
  def decompose_par_dict(self) -> FoamFile:
306
- """
307
- The decomposeParDict file.
308
- """
279
+ """The decomposeParDict file."""
309
280
  return self.file("system/decomposeParDict")
310
281
 
311
282
  @property
312
283
  def block_mesh_dict(self) -> FoamFile:
313
- """
314
- The blockMeshDict file.
315
- """
284
+ """The blockMeshDict file."""
316
285
  return self.file("system/blockMeshDict")
317
286
 
318
287
  @property
319
288
  def transport_properties(self) -> FoamFile:
320
- """
321
- The transportProperties file.
322
- """
289
+ """The transportProperties file."""
323
290
  return self.file("constant/transportProperties")
324
291
 
325
292
  @property
326
293
  def turbulence_properties(self) -> FoamFile:
327
- """
328
- The turbulenceProperties file.
329
- """
294
+ """The turbulenceProperties file."""
330
295
  return self.file("constant/turbulenceProperties")
331
296
 
332
297
  def __fspath__(self) -> str:
@@ -399,7 +364,7 @@ class FoamCase(FoamCaseBase):
399
364
  )
400
365
  except CalledProcessError as e:
401
366
  raise RuntimeError(
402
- f"{e.cmd} failed with return code {e.returncode}\n{e.stderr.decode()}"
367
+ f"{e.cmd} failed with return code {e.returncode}\n{e.stderr}"
403
368
  ) from None
404
369
 
405
370
  else:
@@ -432,21 +397,15 @@ class FoamCase(FoamCaseBase):
432
397
  )
433
398
 
434
399
  def block_mesh(self, *, check: bool = True) -> None:
435
- """
436
- Run blockMesh on this case.
437
- """
400
+ """Run blockMesh on this case."""
438
401
  self.run(["blockMesh"], check=check)
439
402
 
440
403
  def decompose_par(self, *, check: bool = True) -> None:
441
- """
442
- Decompose this case for parallel running.
443
- """
404
+ """Decompose this case for parallel running."""
444
405
  self.run(["decomposePar"], check=check)
445
406
 
446
407
  def reconstruct_par(self, *, check: bool = True) -> None:
447
- """
448
- Reconstruct this case after parallel running.
449
- """
408
+ """Reconstruct this case after parallel running."""
450
409
  self.run(["reconstructPar"], check=check)
451
410
 
452
411
  def copy(self, dest: Union[Path, str]) -> "FoamCase":
@@ -574,7 +533,7 @@ class AsyncFoamCase(FoamCaseBase):
574
533
  )
575
534
  except CalledProcessError as e:
576
535
  raise RuntimeError(
577
- f"{e.cmd} failed with return code {e.returncode}\n{e.stderr.decode()}"
536
+ f"{e.cmd} failed with return code {e.returncode}\n{e.stderr}"
578
537
  ) from None
579
538
 
580
539
  else:
@@ -624,21 +583,15 @@ class AsyncFoamCase(FoamCaseBase):
624
583
  )
625
584
 
626
585
  async def block_mesh(self, *, check: bool = True) -> None:
627
- """
628
- Run blockMesh on this case.
629
- """
586
+ """Run blockMesh on this case."""
630
587
  await self.run(["blockMesh"], check=check)
631
588
 
632
589
  async def decompose_par(self, *, check: bool = True) -> None:
633
- """
634
- Decompose this case for parallel running.
635
- """
590
+ """Decompose this case for parallel running."""
636
591
  await self.run(["decomposePar"], check=check)
637
592
 
638
593
  async def reconstruct_par(self, *, check: bool = True) -> None:
639
- """
640
- Reconstruct this case after parallel running.
641
- """
594
+ """Reconstruct this case after parallel running."""
642
595
  await self.run(["reconstructPar"], check=check)
643
596
 
644
597
  async def copy(self, dest: Union[Path, str]) -> "AsyncFoamCase":
@@ -1,5 +1,5 @@
1
- from ._files import FoamFile, FoamFieldFile
2
1
  from ._base import FoamDictionaryBase
2
+ from ._files import FoamFieldFile, FoamFile
3
3
 
4
4
  __all__ = [
5
5
  "FoamFile",
@@ -1,13 +1,18 @@
1
1
  import sys
2
-
3
2
  from abc import abstractmethod
4
3
  from dataclasses import dataclass
5
4
  from typing import Dict, NamedTuple, Optional, Union
6
5
 
7
6
  if sys.version_info >= (3, 9):
8
- from collections.abc import Sequence
7
+ from collections.abc import Mapping, Sequence
9
8
  else:
10
- from typing import Sequence
9
+ from typing import Mapping, Sequence
10
+
11
+ try:
12
+ import numpy as np
13
+ from numpy.typing import NDArray
14
+ except ModuleNotFoundError:
15
+ pass
11
16
 
12
17
 
13
18
  class FoamDictionaryBase:
@@ -40,11 +45,13 @@ class FoamDictionaryBase:
40
45
  A value that can be stored in an OpenFOAM dictionary.
41
46
  """
42
47
 
43
- _Dict = Dict[str, Union["FoamDictionaryBase.Value", "_Dict"]]
48
+ _Dict = Dict[str, Union["Value", "_Dict"]]
44
49
 
45
50
  @abstractmethod
46
51
  def as_dict(self) -> _Dict:
47
- """
48
- Return a nested dict representation of the dictionary.
49
- """
52
+ """Return a nested dict representation of the dictionary."""
50
53
  raise NotImplementedError
54
+
55
+ _SetValue = Union[Value, "NDArray[np.generic]"]
56
+
57
+ _SetMapping = Mapping[str, Union["_SetValue", "_SetMapping"]]
@@ -1,10 +1,11 @@
1
1
  import sys
2
-
3
2
  from pathlib import Path
3
+ from types import TracebackType
4
4
  from typing import (
5
5
  Any,
6
6
  Optional,
7
7
  Tuple,
8
+ Type,
8
9
  Union,
9
10
  cast,
10
11
  )
@@ -49,7 +50,12 @@ class _FoamFileBase:
49
50
  self.__defer_io += 1
50
51
  return self
51
52
 
52
- def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
53
+ def __exit__(
54
+ self,
55
+ exc_type: Optional[Type[BaseException]],
56
+ exc_val: Optional[BaseException],
57
+ exc_tb: Optional[TracebackType],
58
+ ) -> None:
53
59
  self.__defer_io -= 1
54
60
  if self.__defer_io == 0 and self.__dirty:
55
61
  assert self.__contents is not None
@@ -99,9 +105,7 @@ class FoamFile(
99
105
  FoamDictionaryBase,
100
106
  MutableMapping[str, Union["FoamFile.Value", "FoamFile.Dictionary"]],
101
107
  ):
102
- """
103
- An OpenFOAM dictionary within a file as a mutable mapping.
104
- """
108
+ """An OpenFOAM dictionary within a file as a mutable mapping."""
105
109
 
106
110
  def __init__(self, _file: "FoamFile", _keywords: Sequence[str]) -> None:
107
111
  self._file = _file
@@ -127,7 +131,11 @@ class FoamFile(
127
131
  assume_dimensions=assume_dimensions,
128
132
  )
129
133
 
130
- def __setitem__(self, keyword: str, value: Any) -> None:
134
+ def __setitem__(
135
+ self,
136
+ keyword: str,
137
+ value: Union["FoamFile._SetValue", "FoamFile._SetMapping"],
138
+ ) -> None:
131
139
  self._setitem(keyword, value)
132
140
 
133
141
  def __delitem__(self, keyword: str) -> None:
@@ -154,9 +162,7 @@ class FoamFile(
154
162
  return f"{type(self).__qualname__}({self._file}, {self._keywords})"
155
163
 
156
164
  def as_dict(self) -> FoamDictionaryBase._Dict:
157
- """
158
- Return a nested dict representation of the dictionary.
159
- """
165
+ """Return a nested dict representation of the dictionary."""
160
166
  ret = self._file.as_dict()
161
167
 
162
168
  for k in self._keywords:
@@ -185,7 +191,7 @@ class FoamFile(
185
191
  def _setitem(
186
192
  self,
187
193
  keywords: Union[str, Tuple[str, ...]],
188
- value: Any,
194
+ value: Union["FoamFile._SetValue", "FoamFile._SetMapping"],
189
195
  *,
190
196
  assume_field: bool = False,
191
197
  assume_dimensions: bool = False,
@@ -215,7 +221,11 @@ class FoamFile(
215
221
  f"{contents[:start]}\n{serialize_entry(keywords[-1], value, assume_field=assume_field, assume_dimensions=assume_dimensions)}\n{contents[end:]}"
216
222
  )
217
223
 
218
- def __setitem__(self, keywords: Union[str, Tuple[str, ...]], value: Any) -> None:
224
+ def __setitem__(
225
+ self,
226
+ keywords: Union[str, Tuple[str, ...]],
227
+ value: Union["FoamFile._SetValue", "FoamFile._SetMapping"],
228
+ ) -> None:
219
229
  self._setitem(keywords, value)
220
230
 
221
231
  def __delitem__(self, keywords: Union[str, Tuple[str, ...]]) -> None:
@@ -264,9 +274,7 @@ class FoamFile(
264
274
  return f"{type(self).__name__}({self.path})"
265
275
 
266
276
  def as_dict(self) -> FoamDictionaryBase._Dict:
267
- """
268
- Return a nested dict representation of the file.
269
- """
277
+ """Return a nested dict representation of the file."""
270
278
  _, parsed = self._read()
271
279
  return as_dict(parsed)
272
280
 
@@ -281,7 +289,11 @@ class FoamFieldFile(FoamFile):
281
289
  class BoundaryDictionary(FoamFile.Dictionary):
282
290
  """An OpenFOAM dictionary representing a boundary condition as a mutable mapping."""
283
291
 
284
- def __setitem__(self, key: str, value: Any) -> None:
292
+ def __setitem__(
293
+ self,
294
+ key: str,
295
+ value: Union[FoamFile._SetValue, FoamFile._SetMapping],
296
+ ) -> None:
285
297
  if key == "value":
286
298
  self._setitem(key, value, assume_field=True)
287
299
  else:
@@ -289,9 +301,7 @@ class FoamFieldFile(FoamFile):
289
301
 
290
302
  @property
291
303
  def type(self) -> str:
292
- """
293
- Alias of `self["type"]`.
294
- """
304
+ """Alias of `self["type"]`."""
295
305
  ret = self["type"]
296
306
  if not isinstance(ret, str):
297
307
  raise TypeError("type is not a string")
@@ -310,9 +320,7 @@ class FoamFieldFile(FoamFile):
310
320
  Sequence[Union[int, float, Sequence[Union[int, float]]]],
311
321
  "NDArray[np.generic]",
312
322
  ]:
313
- """
314
- Alias of `self["value"]`.
315
- """
323
+ """Alias of `self["value"]`."""
316
324
  ret = self["value"]
317
325
  if not isinstance(ret, (int, float, Sequence)):
318
326
  raise TypeError("value is not a field")
@@ -361,9 +369,7 @@ class FoamFieldFile(FoamFile):
361
369
 
362
370
  @property
363
371
  def dimensions(self) -> FoamFile.DimensionSet:
364
- """
365
- Alias of `self["dimensions"]`.
366
- """
372
+ """Alias of `self["dimensions"]`."""
367
373
  ret = self["dimensions"]
368
374
  if not isinstance(ret, FoamFile.DimensionSet):
369
375
  raise TypeError("dimensions is not a DimensionSet")
@@ -384,9 +390,7 @@ class FoamFieldFile(FoamFile):
384
390
  Sequence[Union[int, float, Sequence[Union[int, float]]]],
385
391
  "NDArray[np.generic]",
386
392
  ]:
387
- """
388
- Alias of `self["internalField"]`.
389
- """
393
+ """Alias of `self["internalField"]`."""
390
394
  ret = self["internalField"]
391
395
  if not isinstance(ret, (int, float, Sequence)):
392
396
  raise TypeError("internalField is not a field")
@@ -406,9 +410,7 @@ class FoamFieldFile(FoamFile):
406
410
 
407
411
  @property
408
412
  def boundary_field(self) -> "FoamFieldFile.BoundariesDictionary":
409
- """
410
- Alias of `self["boundaryField"]`.
411
- """
413
+ """Alias of `self["boundaryField"]`."""
412
414
  ret = self["boundaryField"]
413
415
  if not isinstance(ret, FoamFieldFile.BoundariesDictionary):
414
416
  assert not isinstance(ret, FoamFile.Dictionary)
@@ -1,5 +1,4 @@
1
1
  import sys
2
-
3
2
  from typing import Optional, Tuple
4
3
 
5
4
  if sys.version_info >= (3, 9):
@@ -16,8 +15,8 @@ from pyparsing import (
16
15
  Literal,
17
16
  Located,
18
17
  Opt,
19
- ParseResults,
20
18
  ParserElement,
19
+ ParseResults,
21
20
  QuotedString,
22
21
  Word,
23
22
  c_style_comment,
@@ -29,8 +28,11 @@ from pyparsing import (
29
28
 
30
29
  from ._base import FoamDictionaryBase
31
30
 
32
- _YES = Keyword("yes").set_parse_action(lambda: True)
33
- _NO = Keyword("no").set_parse_action(lambda: False)
31
+ _SWITCH = (
32
+ Keyword("yes") | Keyword("true") | Keyword("on") | Keyword("y") | Keyword("t")
33
+ ).set_parse_action(lambda: True) | (
34
+ Keyword("no") | Keyword("false") | Keyword("off") | Keyword("n") | Keyword("f")
35
+ ).set_parse_action(lambda: False)
34
36
  _DIMENSIONS = (
35
37
  Literal("[").suppress() + common.number * 7 + Literal("]").suppress()
36
38
  ).set_parse_action(lambda tks: FoamDictionaryBase.DimensionSet(*tks))
@@ -65,9 +67,7 @@ _FIELD = (Keyword("uniform").suppress() + _TENSOR) | (
65
67
  _TOKEN = QuotedString('"', unquote_results=False) | _IDENTIFIER
66
68
  _ITEM = Forward()
67
69
  _LIST = _list_of(_ITEM)
68
- _ITEM <<= (
69
- _FIELD | _LIST | _DIMENSIONED | _DIMENSIONS | common.number | _YES | _NO | _TOKEN
70
- )
70
+ _ITEM <<= _FIELD | _LIST | _DIMENSIONED | _DIMENSIONS | common.number | _SWITCH | _TOKEN
71
71
  _TOKENS = (
72
72
  QuotedString('"', unquote_results=False) | Word(printables.replace(";", ""))
73
73
  )[2, ...].set_parse_action(lambda tks: " ".join(tks))
@@ -131,9 +131,7 @@ def get_value(
131
131
  parsed: Parsed,
132
132
  keywords: Tuple[str, ...],
133
133
  ) -> Optional[FoamDictionaryBase.Value]:
134
- """
135
- Value of an entry.
136
- """
134
+ """Value of an entry."""
137
135
  _, value, _ = parsed[keywords]
138
136
  return value
139
137
 
@@ -144,9 +142,7 @@ def get_entry_locn(
144
142
  *,
145
143
  missing_ok: bool = False,
146
144
  ) -> Tuple[int, int]:
147
- """
148
- Location of an entry or where it should be inserted.
149
- """
145
+ """Location of an entry or where it should be inserted."""
150
146
  try:
151
147
  start, _, end = parsed[keywords]
152
148
  except KeyError:
@@ -165,9 +161,7 @@ def get_entry_locn(
165
161
 
166
162
 
167
163
  def as_dict(parsed: Parsed) -> FoamDictionaryBase._Dict:
168
- """
169
- Return a nested dict representation of the file.
170
- """
164
+ """Return a nested dict representation of the file."""
171
165
  ret: FoamDictionaryBase._Dict = {}
172
166
  for keywords, (_, value, _) in parsed.items():
173
167
  r = ret
@@ -1,18 +1,19 @@
1
1
  import sys
2
-
3
2
  from contextlib import suppress
4
- from typing import Any
3
+ from typing import Union
5
4
 
6
5
  if sys.version_info >= (3, 9):
7
6
  from collections.abc import Mapping
8
7
  else:
9
8
  from typing import Mapping
10
9
 
11
- from ._base import FoamDictionaryBase
12
10
  from .._util import is_sequence
11
+ from ._base import FoamDictionaryBase
13
12
 
14
13
 
15
- def _serialize_bool(value: Any) -> str:
14
+ def _serialize_switch(
15
+ value: Union[FoamDictionaryBase._SetValue, FoamDictionaryBase._SetMapping],
16
+ ) -> str:
16
17
  if value is True:
17
18
  return "yes"
18
19
  elif value is False:
@@ -21,24 +22,28 @@ def _serialize_bool(value: Any) -> str:
21
22
  raise TypeError(f"Not a bool: {type(value)}")
22
23
 
23
24
 
24
- def _serialize_list(value: Any) -> str:
25
+ def _serialize_list(
26
+ value: Union[FoamDictionaryBase._SetValue, FoamDictionaryBase._SetMapping],
27
+ ) -> str:
25
28
  if is_sequence(value):
26
29
  return f"({' '.join(_serialize_value(v) for v in value)})"
27
30
  else:
28
31
  raise TypeError(f"Not a valid sequence: {type(value)}")
29
32
 
30
33
 
31
- def _serialize_field(value: Any) -> str:
34
+ def _serialize_field(
35
+ value: Union[FoamDictionaryBase._SetValue, FoamDictionaryBase._SetMapping],
36
+ ) -> str:
32
37
  if is_sequence(value):
33
38
  try:
34
39
  s = _serialize_list(value)
35
40
  except TypeError:
36
41
  raise TypeError(f"Not a valid field: {type(value)}") from None
37
42
  else:
38
- if len(value) < 10:
43
+ if not is_sequence(value[0]) and len(value) < 10:
39
44
  return f"uniform {s}"
40
45
  else:
41
- if isinstance(value[0], (int, float)):
46
+ if not is_sequence(value[0]):
42
47
  kind = "scalar"
43
48
  elif len(value[0]) == 3:
44
49
  kind = "vector"
@@ -55,14 +60,18 @@ def _serialize_field(value: Any) -> str:
55
60
  return f"uniform {value}"
56
61
 
57
62
 
58
- def _serialize_dimensions(value: Any) -> str:
63
+ def _serialize_dimensions(
64
+ value: Union[FoamDictionaryBase._SetValue, FoamDictionaryBase._SetMapping],
65
+ ) -> str:
59
66
  if is_sequence(value) and len(value) == 7:
60
67
  return f"[{' '.join(str(v) for v in value)}]"
61
68
  else:
62
69
  raise TypeError(f"Not a valid dimension set: {type(value)}")
63
70
 
64
71
 
65
- def _serialize_dimensioned(value: Any) -> str:
72
+ def _serialize_dimensioned(
73
+ value: Union[FoamDictionaryBase._SetValue, FoamDictionaryBase._SetMapping],
74
+ ) -> str:
66
75
  if isinstance(value, FoamDictionaryBase.Dimensioned):
67
76
  if value.name is not None:
68
77
  return f"{value.name} {_serialize_dimensions(value.dimensions)} {_serialize_value(value.value)}"
@@ -73,7 +82,10 @@ def _serialize_dimensioned(value: Any) -> str:
73
82
 
74
83
 
75
84
  def _serialize_value(
76
- value: Any, *, assume_field: bool = False, assume_dimensions: bool = False
85
+ value: Union[FoamDictionaryBase._SetValue, FoamDictionaryBase._SetMapping],
86
+ *,
87
+ assume_field: bool = False,
88
+ assume_dimensions: bool = False,
77
89
  ) -> str:
78
90
  if isinstance(value, FoamDictionaryBase.DimensionSet) or assume_dimensions:
79
91
  with suppress(TypeError):
@@ -90,12 +102,14 @@ def _serialize_value(
90
102
  return _serialize_list(value)
91
103
 
92
104
  with suppress(TypeError):
93
- return _serialize_bool(value)
105
+ return _serialize_switch(value)
94
106
 
95
107
  return str(value)
96
108
 
97
109
 
98
- def _serialize_dictionary(value: Any) -> str:
110
+ def _serialize_dictionary(
111
+ value: Union[FoamDictionaryBase._SetValue, FoamDictionaryBase._SetMapping],
112
+ ) -> str:
99
113
  if isinstance(value, Mapping):
100
114
  return "\n".join(serialize_entry(k, v) for k, v in value.items())
101
115
  else:
@@ -104,7 +118,7 @@ def _serialize_dictionary(value: Any) -> str:
104
118
 
105
119
  def serialize_entry(
106
120
  keyword: str,
107
- value: Any,
121
+ value: Union[FoamDictionaryBase._SetValue, FoamDictionaryBase._SetMapping],
108
122
  *,
109
123
  assume_field: bool = False,
110
124
  assume_dimensions: bool = False,
foamlib/_util.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import asyncio
2
- import sys
3
2
  import subprocess
4
-
3
+ import sys
5
4
  from pathlib import Path
6
5
  from typing import Any, Union
7
6
 
@@ -36,6 +35,11 @@ def is_sequence(
36
35
 
37
36
  CalledProcessError = subprocess.CalledProcessError
38
37
 
38
+ if sys.version_info >= (3, 9):
39
+ CompletedProcess = subprocess.CompletedProcess[str]
40
+ else:
41
+ CompletedProcess = subprocess.CompletedProcess
42
+
39
43
 
40
44
  def run_process(
41
45
  cmd: Union[Sequence[Union[str, Path]], str, Path],
@@ -43,7 +47,7 @@ def run_process(
43
47
  check: bool = True,
44
48
  cwd: Union[None, str, Path] = None,
45
49
  env: Union[None, Mapping[str, str]] = None,
46
- ) -> "subprocess.CompletedProcess[bytes]":
50
+ ) -> CompletedProcess:
47
51
  shell = not is_sequence(cmd)
48
52
 
49
53
  if sys.version_info < (3, 8):
@@ -56,7 +60,9 @@ def run_process(
56
60
  cmd,
57
61
  cwd=cwd,
58
62
  env=env,
59
- capture_output=True,
63
+ stdout=asyncio.subprocess.DEVNULL,
64
+ stderr=asyncio.subprocess.PIPE,
65
+ text=True,
60
66
  shell=shell,
61
67
  check=check,
62
68
  )
@@ -70,13 +76,13 @@ async def run_process_async(
70
76
  check: bool = True,
71
77
  cwd: Union[None, str, Path] = None,
72
78
  env: Union[None, Mapping[str, str]] = None,
73
- ) -> "subprocess.CompletedProcess[bytes]":
79
+ ) -> CompletedProcess:
74
80
  if not is_sequence(cmd):
75
81
  proc = await asyncio.create_subprocess_shell(
76
82
  str(cmd),
77
83
  cwd=cwd,
78
84
  env=env,
79
- stdout=asyncio.subprocess.PIPE,
85
+ stdout=asyncio.subprocess.DEVNULL,
80
86
  stderr=asyncio.subprocess.PIPE,
81
87
  )
82
88
 
@@ -87,15 +93,16 @@ async def run_process_async(
87
93
  *cmd,
88
94
  cwd=cwd,
89
95
  env=env,
90
- stdout=asyncio.subprocess.PIPE,
96
+ stdout=asyncio.subprocess.DEVNULL,
91
97
  stderr=asyncio.subprocess.PIPE,
92
98
  )
93
99
 
94
100
  stdout, stderr = await proc.communicate()
95
101
 
102
+ assert stdout is None
96
103
  assert proc.returncode is not None
97
104
 
98
- ret = subprocess.CompletedProcess(cmd, proc.returncode, stdout, stderr)
105
+ ret = CompletedProcess(cmd, proc.returncode, None, stderr.decode())
99
106
 
100
107
  if check:
101
108
  ret.check_returncode()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foamlib
3
- Version: 0.2.5
3
+ Version: 0.2.7
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
@@ -0,0 +1,14 @@
1
+ foamlib/__init__.py,sha256=ZWFEP5x2m2c9zMrODOS9_vL4bf6FPnK7BY-DTLXu3JU,344
2
+ foamlib/_cases.py,sha256=SjDTVauOlcrtyvnt5uxWGSu2RYZ0lhKRmvMnuRnRuzI,20973
3
+ foamlib/_util.py,sha256=PBTpBwt_j1GXASncSDZUR8pH2u_h8UyJXm8GeFKebTY,2552
4
+ foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ foamlib/_dictionaries/__init__.py,sha256=vxGpA7uaEbJwKFGOYdLFR6R9jcUj_HW60YzZBMjNXRo,160
6
+ foamlib/_dictionaries/_base.py,sha256=i_RRwJYP11fG-e9jAqH2lN5wz4BOPNWs_frqyLInSrc,1809
7
+ foamlib/_dictionaries/_files.py,sha256=ZIIImssk9Xqgx8kYz_mr2e3IHGze1J96BvDQxQeNVaA,12912
8
+ foamlib/_dictionaries/_parsing.py,sha256=s6t9JJxAjsSp3ypeQNeskgtYWsbb52iBjrVDTUv56jc,5008
9
+ foamlib/_dictionaries/_serialization.py,sha256=kaec7AzGOERmPAeMP3Li1ZU7jyectsUS5WHgQbeT-2Y,4045
10
+ foamlib-0.2.7.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
11
+ foamlib-0.2.7.dist-info/METADATA,sha256=wwLtfgXWX2iXnqLI7jVNZHIpoVE52ZDpWvhibNc6wmA,4650
12
+ foamlib-0.2.7.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
13
+ foamlib-0.2.7.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
14
+ foamlib-0.2.7.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- foamlib/__init__.py,sha256=ncl1G6iN85s3zP7aVBqzekY5wHCoOn8dpJxXW2e36vI,287
2
- foamlib/_cases.py,sha256=SbMaaKdhYbgmgdxWZNB7j47P04QxZ3VVq4sP9HbTLpA,21422
3
- foamlib/_util.py,sha256=ICs_Bc2jXpxzOUos6Cnl0blUwz1P6r1f1swP8k9Bex0,2347
4
- foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- foamlib/_dictionaries/__init__.py,sha256=6UWBGe1t7cq-d6WWQrVm0Xpi7Whpkr-mkTWgAM4NwcE,160
6
- foamlib/_dictionaries/_base.py,sha256=0Qic347JzJBMgBc0gHfuAGmQMWYGEn7IfJ9vKd4pm_I,1606
7
- foamlib/_dictionaries/_files.py,sha256=Qyw04I5hqGRkHR7KWGmMdX6LyVtat1zKf50bo7CRIoU,12626
8
- foamlib/_dictionaries/_parsing.py,sha256=w7AOyoPPghsG06WK_1fXU-udU_F8J_zuvV9eIf07P8M,4905
9
- foamlib/_dictionaries/_serialization.py,sha256=8YInaQ0HnlDe4RnwocvTlJJkVFR7XDqGsuN4ABAyUCE,3452
10
- foamlib-0.2.5.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
11
- foamlib-0.2.5.dist-info/METADATA,sha256=PuzWIZKasSyaUKpO0H_g67r6wqLyswQyOzzelaiHLpQ,4650
12
- foamlib-0.2.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
13
- foamlib-0.2.5.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
14
- foamlib-0.2.5.dist-info/RECORD,,