foamlib 1.4.0__tar.gz → 1.4.2__tar.gz

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.
Files changed (35) hide show
  1. {foamlib-1.4.0 → foamlib-1.4.2}/PKG-INFO +1 -1
  2. {foamlib-1.4.0 → foamlib-1.4.2}/pyproject.toml +1 -1
  3. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_cases/base.py +4 -2
  4. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/_common.py +5 -5
  5. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/_parsing/_grammar.py +2 -1
  6. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/_serialization.py +3 -3
  7. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/files.py +94 -27
  8. {foamlib-1.4.0 → foamlib-1.4.2}/LICENSE.txt +0 -0
  9. {foamlib-1.4.0 → foamlib-1.4.2}/README.md +0 -0
  10. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/__init__.py +0 -0
  11. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_cases/__init__.py +0 -0
  12. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_cases/_run.py +0 -0
  13. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_cases/_subprocess.py +0 -0
  14. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_cases/_util.py +0 -0
  15. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_cases/async_.py +0 -0
  16. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_cases/slurm.py +0 -0
  17. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_cases/sync.py +0 -0
  18. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/__init__.py +0 -0
  19. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/_io.py +0 -0
  20. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/_parsing/__init__.py +0 -0
  21. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/_parsing/_elements.py +0 -0
  22. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/_parsing/parsing.py +0 -0
  23. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/_typing.py +0 -0
  24. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/_util.py +0 -0
  25. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/_files/types.py +0 -0
  26. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/postprocessing/__init__.py +0 -0
  27. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/postprocessing/load_tables.py +0 -0
  28. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/postprocessing/table_reader.py +0 -0
  29. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/preprocessing/__init__.py +0 -0
  30. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/preprocessing/case_modifier.py +0 -0
  31. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/preprocessing/grid_parameter_sweep.py +0 -0
  32. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/preprocessing/of_dict.py +0 -0
  33. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/preprocessing/parameter_study.py +0 -0
  34. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/preprocessing/system.py +0 -0
  35. {foamlib-1.4.0 → foamlib-1.4.2}/src/foamlib/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: foamlib
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: Pythonic interface for working with OpenFOAM
5
5
  Author: Gabriel S. Gerlero
6
6
  Author-email: Gabriel S. Gerlero <ggerlero@cimec.unl.edu.ar>
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "foamlib"
7
- version = "1.4.0"
7
+ version = "1.4.2"
8
8
  license = "GPL-3.0-only"
9
9
  license-files = ["LICENSE.txt"]
10
10
  description = "Pythonic interface for working with OpenFOAM"
@@ -16,7 +16,7 @@ import os
16
16
  from .._files import FoamFieldFile, FoamFile
17
17
 
18
18
 
19
- class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
19
+ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"], os.PathLike[str]):
20
20
  """
21
21
  Base class for OpenFOAM cases.
22
22
 
@@ -34,7 +34,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
34
34
  def __init__(self, path: os.PathLike[str] | str = Path()) -> None:
35
35
  self.path = Path(path).absolute()
36
36
 
37
- class TimeDirectory(AbstractSet[FoamFieldFile]):
37
+ class TimeDirectory(AbstractSet[FoamFieldFile], os.PathLike[str]):
38
38
  """
39
39
  A time directory in an OpenFOAM case.
40
40
 
@@ -100,6 +100,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
100
100
  else:
101
101
  (self.path / name).unlink()
102
102
 
103
+ @override
103
104
  def __fspath__(self) -> str:
104
105
  return str(self.path)
105
106
 
@@ -266,6 +267,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
266
267
  """The turbulenceProperties file."""
267
268
  return self.file("constant/turbulenceProperties")
268
269
 
270
+ @override
269
271
  def __fspath__(self) -> str:
270
272
  return str(self.path)
271
273
 
@@ -46,9 +46,9 @@ def dict_from_items(
46
46
  items: Iterable[tuple[object, _V]],
47
47
  /,
48
48
  *,
49
- target: type[File] = ...,
49
+ target: type[SubDict] = ...,
50
50
  check_keys: bool = ...,
51
- ) -> dict[str | None, _V] | MultiDict[str | None, _V]: ...
51
+ ) -> dict[str, _V] | MultiDict[str, _V]: ...
52
52
 
53
53
 
54
54
  @overload
@@ -56,16 +56,16 @@ def dict_from_items(
56
56
  items: Iterable[tuple[object, _V]],
57
57
  /,
58
58
  *,
59
- target: type[SubDict] = ...,
59
+ target: type[File] = ...,
60
60
  check_keys: bool = ...,
61
- ) -> dict[str, _V] | MultiDict[str, _V]: ...
61
+ ) -> dict[str | None, _V] | MultiDict[str | None, _V]: ...
62
62
 
63
63
 
64
64
  def dict_from_items(
65
65
  items: Iterable[tuple[object, _V]],
66
66
  /,
67
67
  *,
68
- target: type[Dict] | type[File] | type[SubDict],
68
+ target: type[Dict] | type[SubDict] | type[File],
69
69
  check_keys: bool = False,
70
70
  ) -> (
71
71
  dict[str, _V]
@@ -150,8 +150,9 @@ DATA <<= _DATA_ENTRY[1, ...].set_parse_action(
150
150
 
151
151
  _STANDALONE_DATA_ENTRY = (
152
152
  ASCIINumericList(dtype=int)
153
- | ASCIIFacesLikeList()
153
+ | ASCIINumericList(dtype=float)
154
154
  | ASCIINumericList(dtype=float, elshape=(3,))
155
+ | ASCIIFacesLikeList()
155
156
  | (
156
157
  (
157
158
  binary_numeric_list(dtype=np.int32)
@@ -187,9 +187,9 @@ def normalized(
187
187
  return data # ty: ignore[invalid-return-type]
188
188
  return data.astype(float, copy=False) # ty: ignore[possibly-missing-attribute]
189
189
 
190
- # Other possible numeric standalone data (n integers)
191
- case [Integral(), *rest], () if not isinstance(data, tuple) and all(
192
- isinstance(r, Integral) for r in rest
190
+ # Other possible numeric standalone data (n integers or floats)
191
+ case [Real(), *rest], () if not isinstance(data, tuple) and all(
192
+ isinstance(r, Real) for r in rest
193
193
  ):
194
194
  return normalized(np.asarray(data), keywords=keywords, format_=format_)
195
195
 
@@ -1,4 +1,5 @@
1
1
  import contextlib
2
+ import os
2
3
  import sys
3
4
  from collections.abc import Collection, Iterable, Iterator, Mapping, Sequence
4
5
  from copy import deepcopy
@@ -20,6 +21,7 @@ from multicollections import MultiDict
20
21
  from multicollections.abc import MutableMultiMapping, with_default
21
22
 
22
23
  from .._files import _common
24
+ from ._common import dict_from_items
23
25
  from ._io import FoamFileIO
24
26
  from ._parsing import parse
25
27
  from ._serialization import dumps, normalized
@@ -44,6 +46,7 @@ class FoamFile(
44
46
  str | tuple[str, ...] | None,
45
47
  "Data | StandaloneData | FoamFile.SubDict | None",
46
48
  ],
49
+ os.PathLike[str],
47
50
  FoamFileIO,
48
51
  ):
49
52
  """
@@ -96,7 +99,7 @@ class FoamFile(
96
99
  Dimensioned = Dimensioned
97
100
  DimensionSet = DimensionSet
98
101
 
99
- class KeysView(multicollections.abc.KeysView["str | None"]):
102
+ class KeysView(multicollections.abc.KeysView[str | None]):
100
103
  def __init__(self, file: "FoamFile", *, include_header: bool = False) -> None:
101
104
  self._file = file
102
105
  self._include_header = include_header
@@ -140,7 +143,7 @@ class FoamFile(
140
143
 
141
144
  class ItemsView(
142
145
  multicollections.abc.ItemsView[
143
- "str | None", "Data | StandaloneData | FoamFile.SubDict | None"
146
+ str | None, "Data | StandaloneData | FoamFile.SubDict | None"
144
147
  ]
145
148
  ):
146
149
  def __init__(
@@ -288,14 +291,19 @@ class FoamFile(
288
291
  def __getitem__(self, keyword: str) -> "Data | FoamFile.SubDict | None": ...
289
292
 
290
293
  @overload
291
- def __getitem__(self, keyword: slice) -> SubDict: ...
294
+ def __getitem__(
295
+ self, keyword: slice
296
+ ) -> (
297
+ dict[str, "Data | FoamFile.SubDict | None"]
298
+ | MultiDict[str, "Data | FoamFile.SubDict | None"]
299
+ ): ...
292
300
 
293
301
  @override
294
302
  def __getitem__(
295
303
  self, keyword: str | slice
296
- ) -> "Data | FoamFile.SubDict | None | SubDict":
304
+ ) -> "Data | FoamFile.SubDict | None | dict[str, Data | FoamFile.SubDict | None] | MultiDict[str, Data | FoamFile.SubDict | None]":
297
305
  if keyword == slice(None):
298
- return self.as_dict()
306
+ return self.as_dict(deep=False)
299
307
 
300
308
  if isinstance(keyword, slice):
301
309
  msg = "Only empty slices (:) are supported"
@@ -420,17 +428,42 @@ class FoamFile(
420
428
  def __repr__(self) -> str:
421
429
  return f"{type(self).__qualname__}('{self._file}', {self._keywords})"
422
430
 
423
- def as_dict(self) -> SubDict:
424
- """Return a nested dict representation of the sub-dictionary."""
425
- file = self._file.as_dict(include_header=True)
431
+ @overload
432
+ def as_dict(self, *, deep: Literal[True] = ...) -> SubDict: ...
433
+
434
+ @overload
435
+ def as_dict(
436
+ self, *, deep: Literal[False] = ...
437
+ ) -> (
438
+ dict[str, "Data | FoamFile.SubDict | None"]
439
+ | MultiDict[str, "Data | FoamFile.SubDict | None"]
440
+ ): ...
441
+
442
+ def as_dict(
443
+ self, *, deep: bool = True
444
+ ) -> (
445
+ SubDict
446
+ | dict[str, "Data | FoamFile.SubDict | None"]
447
+ | MultiDict[str, "Data | FoamFile.SubDict | None"]
448
+ ):
449
+ """
450
+ Return a dict representation of the sub-dictionary.
451
+
452
+ :param deep: Whether to return a nested representation by recursing into
453
+ nested sub-dictionaries.
454
+ """
455
+ if deep:
456
+ file = self._file.as_dict(include_header=True)
426
457
 
427
- ret = file[self._keywords[0]]
428
- assert isinstance(ret, Mapping)
429
- for k in self._keywords[1:]:
430
- ret = ret[k]
458
+ ret = file[self._keywords[0]]
431
459
  assert isinstance(ret, Mapping)
460
+ for k in self._keywords[1:]:
461
+ ret = ret[k]
462
+ assert isinstance(ret, Mapping)
432
463
 
433
- return ret # ty: ignore[invalid-return-type]
464
+ return ret # ty: ignore[invalid-return-type]
465
+
466
+ return dict_from_items(self.items(), target=SubDict)
434
467
 
435
468
  @property
436
469
  def version(self) -> float:
@@ -736,17 +769,20 @@ class FoamFile(
736
769
  def __getitem__(
737
770
  self,
738
771
  keywords: slice,
739
- ) -> File: ...
772
+ ) -> (
773
+ dict[str | None, "Data | StandaloneData | FoamFile.SubDict | None"]
774
+ | MultiDict[str | None, "Data | StandaloneData | FoamFile.SubDict | None"]
775
+ ): ...
740
776
 
741
777
  @override
742
778
  def __getitem__( # ty: ignore[invalid-method-override]
743
779
  self,
744
780
  keywords: str | tuple[str, ...] | None | slice,
745
- ) -> "Data | StandaloneData | FoamFile.SubDict | None | File":
781
+ ) -> "Data | StandaloneData | FoamFile.SubDict | None | dict[str | None, Data | StandaloneData | FoamFile.SubDict | None] | MultiDict[str | None, Data | StandaloneData | FoamFile.SubDict | None]":
746
782
  keywords = FoamFile._normalized_keywords(keywords, slice_ok=True)
747
783
 
748
784
  if keywords == slice(None):
749
- return self.as_dict()
785
+ return self.as_dict(deep=False)
750
786
 
751
787
  assert not isinstance(keywords, slice)
752
788
  parsed = self._get_parsed()
@@ -783,7 +819,7 @@ class FoamFile(
783
819
  def __setitem__( # ty: ignore[invalid-method-override]
784
820
  self,
785
821
  keywords: str | tuple[str, ...] | None | slice,
786
- data: FileLike | DataLike | StandaloneDataLike | SubDictLike | None,
822
+ data: DataLike | StandaloneDataLike | SubDictLike | None | FileLike,
787
823
  ) -> None:
788
824
  keywords = FoamFile._normalized_keywords(keywords, slice_ok=True)
789
825
 
@@ -980,19 +1016,44 @@ class FoamFile(
980
1016
  else:
981
1017
  super().clear()
982
1018
 
1019
+ @override
983
1020
  def __fspath__(self) -> str:
984
1021
  return str(self.path)
985
1022
 
986
- def as_dict(self, *, include_header: bool = False) -> File:
1023
+ @overload
1024
+ def as_dict(
1025
+ self, *, include_header: bool = ..., deep: Literal[True] = ...
1026
+ ) -> File: ...
1027
+
1028
+ @overload
1029
+ def as_dict(
1030
+ self, *, include_header: bool = ..., deep: Literal[False] = ...
1031
+ ) -> (
1032
+ dict[str | None, "Data | StandaloneData | FoamFile.SubDict | None"]
1033
+ | MultiDict[str | None, "Data | StandaloneData | FoamFile.SubDict | None"]
1034
+ ): ...
1035
+
1036
+ def as_dict(
1037
+ self, *, include_header: bool = False, deep: bool = True
1038
+ ) -> (
1039
+ File
1040
+ | dict[str | None, "Data | StandaloneData | FoamFile.SubDict | None"]
1041
+ | MultiDict[str | None, "Data | StandaloneData | FoamFile.SubDict | None"]
1042
+ ):
987
1043
  """
988
- Return a nested dict representation of the file.
1044
+ Return a dict representation of the file.
989
1045
 
990
1046
  :param include_header: Whether to include the "FoamFile" header in the output.
1047
+ :param deep: Whether to return a nested representation by recursing into
1048
+ nested sub-dictionaries.
991
1049
  """
992
- d = self._get_parsed().as_dict()
993
- if not include_header:
994
- d.pop("FoamFile", None)
995
- return deepcopy(d)
1050
+ if deep:
1051
+ d = self._get_parsed().as_dict()
1052
+ if not include_header:
1053
+ d.pop("FoamFile", None)
1054
+ return deepcopy(d)
1055
+
1056
+ return dict_from_items(self.items(include_header=include_header), target=File) # ty: ignore[invalid-return-type]
996
1057
 
997
1058
  @staticmethod
998
1059
  def loads(
@@ -1230,7 +1291,7 @@ class FoamFieldFile(FoamFile):
1230
1291
  def getall(
1231
1292
  self, keywords: str | tuple[str, ...] | None
1232
1293
  ) -> Collection["Data | StandaloneData | FoamFieldFile.SubDict | None"]:
1233
- keywords = FoamFile._normalized_keywords(keywords)
1294
+ keywords = FoamFieldFile._normalized_keywords(keywords)
1234
1295
 
1235
1296
  ret = list(super().getall(keywords))
1236
1297
 
@@ -1250,6 +1311,12 @@ class FoamFieldFile(FoamFile):
1250
1311
  keywords: str | tuple[str],
1251
1312
  ) -> "Data | FoamFieldFile.BoundariesSubDict | None": ...
1252
1313
 
1314
+ @overload
1315
+ def __getitem__(
1316
+ self,
1317
+ keywords: tuple[str, str],
1318
+ ) -> "Data | FoamFieldFile.BoundarySubDict | None": ...
1319
+
1253
1320
  @overload
1254
1321
  def __getitem__(
1255
1322
  self,
@@ -1272,11 +1339,11 @@ class FoamFieldFile(FoamFile):
1272
1339
  def __getitem__( # ty: ignore[invalid-method-override]
1273
1340
  self,
1274
1341
  keywords: str | tuple[str, ...] | None | slice,
1275
- ) -> "Data | StandaloneData | FoamFieldFile.SubDict | None | File":
1276
- keywords = FoamFile._normalized_keywords(keywords, slice_ok=True)
1342
+ ) -> "Data | StandaloneData | FoamFieldFile.SubDict | None | dict[str | None, Data | StandaloneData | FoamFieldFile.SubDict | None] | MultiDict[str | None, Data | StandaloneData | FoamFieldFile.SubDict | None]":
1343
+ keywords = FoamFieldFile._normalized_keywords(keywords, slice_ok=True)
1277
1344
 
1278
1345
  if keywords == slice(None):
1279
- return self.as_dict()
1346
+ return self.as_dict(deep=False)
1280
1347
 
1281
1348
  assert not isinstance(keywords, slice)
1282
1349
  ret = super().__getitem__(keywords)
File without changes
File without changes
File without changes
File without changes