foamlib 0.2.3__tar.gz → 0.2.4__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 (25) hide show
  1. {foamlib-0.2.3 → foamlib-0.2.4}/PKG-INFO +2 -1
  2. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib/__init__.py +1 -1
  3. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib/_dictionaries/_files.py +84 -56
  4. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib/_dictionaries/_serialization.py +25 -5
  5. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib.egg-info/PKG-INFO +2 -1
  6. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib.egg-info/requires.txt +1 -0
  7. {foamlib-0.2.3 → foamlib-0.2.4}/pyproject.toml +1 -0
  8. {foamlib-0.2.3 → foamlib-0.2.4}/LICENSE.txt +0 -0
  9. {foamlib-0.2.3 → foamlib-0.2.4}/README.md +0 -0
  10. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib/_cases.py +0 -0
  11. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib/_dictionaries/__init__.py +0 -0
  12. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib/_dictionaries/_base.py +0 -0
  13. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib/_dictionaries/_parsing.py +0 -0
  14. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib/_subprocesses.py +0 -0
  15. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib/py.typed +0 -0
  16. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib.egg-info/SOURCES.txt +0 -0
  17. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib.egg-info/dependency_links.txt +0 -0
  18. {foamlib-0.2.3 → foamlib-0.2.4}/foamlib.egg-info/top_level.txt +0 -0
  19. {foamlib-0.2.3 → foamlib-0.2.4}/setup.cfg +0 -0
  20. {foamlib-0.2.3 → foamlib-0.2.4}/tests/test_basic.py +0 -0
  21. {foamlib-0.2.3 → foamlib-0.2.4}/tests/test_dictionaries.py +0 -0
  22. {foamlib-0.2.3 → foamlib-0.2.4}/tests/test_flange.py +0 -0
  23. {foamlib-0.2.3 → foamlib-0.2.4}/tests/test_flange_async.py +0 -0
  24. {foamlib-0.2.3 → foamlib-0.2.4}/tests/test_pitz.py +0 -0
  25. {foamlib-0.2.3 → foamlib-0.2.4}/tests/test_pitz_async.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foamlib
3
- Version: 0.2.3
3
+ Version: 0.2.4
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
@@ -27,6 +27,7 @@ Description-Content-Type: text/markdown
27
27
  License-File: LICENSE.txt
28
28
  Requires-Dist: aioshutil<2,>=1
29
29
  Requires-Dist: pyparsing<4,>=3
30
+ Requires-Dist: typing-extensions<5,>=4
30
31
  Provides-Extra: lint
31
32
  Requires-Dist: mypy<2,>=1; extra == "lint"
32
33
  Requires-Dist: pytest<9,>=7; extra == "lint"
@@ -1,4 +1,4 @@
1
- __version__ = "0.2.3"
1
+ __version__ = "0.2.4"
2
2
 
3
3
  from ._cases import FoamCase, AsyncFoamCase, FoamCaseBase
4
4
  from ._dictionaries import FoamFile, FoamFieldFile, FoamDictionaryBase
@@ -11,9 +11,11 @@ from typing import (
11
11
  cast,
12
12
  )
13
13
 
14
+ from typing_extensions import Self
15
+
14
16
  from ._base import FoamDictionaryBase
15
17
  from ._parsing import Parsed, as_dict, get_entry_locn, get_value, parse
16
- from ._serialization import serialize_value
18
+ from ._serialization import serialize_entry
17
19
 
18
20
  try:
19
21
  import numpy as np
@@ -22,9 +24,62 @@ except ModuleNotFoundError:
22
24
  pass
23
25
 
24
26
 
27
+ class _FoamFileBase:
28
+ def __init__(self, path: Union[str, Path]) -> None:
29
+ self.path = Path(path).absolute()
30
+ if self.path.is_dir():
31
+ raise IsADirectoryError(self.path)
32
+ elif not self.path.is_file():
33
+ raise FileNotFoundError(self.path)
34
+
35
+ self.__contents: Optional[str] = None
36
+ self.__parsed: Optional[Parsed] = None
37
+ self.__defer_io = 0
38
+ self.__dirty = False
39
+
40
+ def __enter__(self) -> Self:
41
+ if self.__defer_io == 0:
42
+ self._read()
43
+ self.__defer_io += 1
44
+ return self
45
+
46
+ def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
47
+ self.__defer_io -= 1
48
+ if self.__defer_io == 0 and self.__dirty:
49
+ assert self.__contents is not None
50
+ self._write(self.__contents)
51
+ assert not self.__dirty
52
+
53
+ def _read(self) -> Tuple[str, Parsed]:
54
+ if not self.__defer_io:
55
+ contents = self.path.read_text()
56
+ if contents != self.__contents:
57
+ self.__contents = contents
58
+ self.__parsed = None
59
+
60
+ assert self.__contents is not None
61
+
62
+ if self.__parsed is None:
63
+ self.__parsed = parse(self.__contents)
64
+
65
+ return self.__contents, self.__parsed
66
+
67
+ def _write(self, contents: str) -> None:
68
+ self.__contents = contents
69
+ self.__parsed = None
70
+ if not self.__defer_io:
71
+ self.path.write_text(contents)
72
+ self.__dirty = False
73
+ else:
74
+ self.__dirty = True
75
+
76
+
25
77
  class FoamFile(
78
+ _FoamFileBase,
26
79
  FoamDictionaryBase,
27
- MutableMapping[str, Union["FoamFile.Value", "FoamFile.Dictionary"]],
80
+ MutableMapping[
81
+ Union[str, Tuple[str, ...]], Union["FoamFile.Value", "FoamFile.Dictionary"]
82
+ ],
28
83
  ):
29
84
  """
30
85
  An OpenFOAM dictionary file.
@@ -75,9 +130,20 @@ class FoamFile(
75
130
  def __iter__(self) -> Iterator[str]:
76
131
  return self._file._iter(tuple(self._keywords))
77
132
 
133
+ def __contains__(self, keyword: object) -> bool:
134
+ return (*self._keywords, keyword) in self._file
135
+
78
136
  def __len__(self) -> int:
79
137
  return len(list(iter(self)))
80
138
 
139
+ def update(self, *args: Any, **kwargs: Any) -> None:
140
+ with self._file:
141
+ super().update(*args, **kwargs)
142
+
143
+ def clear(self) -> None:
144
+ with self._file:
145
+ super().clear()
146
+
81
147
  def __repr__(self) -> str:
82
148
  return f"{type(self).__qualname__}({self._file}, {self._keywords})"
83
149
 
@@ -95,54 +161,6 @@ class FoamFile(
95
161
 
96
162
  return ret
97
163
 
98
- def __init__(self, path: Union[str, Path]) -> None:
99
- self.path = Path(path).absolute()
100
- if self.path.is_dir():
101
- raise IsADirectoryError(self.path)
102
- elif not self.path.is_file():
103
- raise FileNotFoundError(self.path)
104
-
105
- self._contents: Optional[str] = None
106
- self._parsed: Optional[Parsed] = None
107
- self._defer_io = 0
108
- self._dirty = False
109
-
110
- def __enter__(self) -> "FoamFile":
111
- if self._defer_io == 0:
112
- self._read()
113
- self._defer_io += 1
114
- return self
115
-
116
- def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
117
- self._defer_io -= 1
118
- if self._defer_io == 0 and self._dirty:
119
- assert self._contents is not None
120
- self._write(self._contents)
121
- assert not self._dirty
122
-
123
- def _read(self) -> Tuple[str, Parsed]:
124
- if not self._defer_io:
125
- contents = self.path.read_text()
126
- if contents != self._contents:
127
- self._contents = contents
128
- self._parsed = None
129
-
130
- assert self._contents is not None
131
-
132
- if self._parsed is None:
133
- self._parsed = parse(self._contents)
134
-
135
- return self._contents, self._parsed
136
-
137
- def _write(self, contents: str) -> None:
138
- self._contents = contents
139
- self._parsed = None
140
- if not self._defer_io:
141
- self.path.write_text(contents)
142
- self._dirty = False
143
- else:
144
- self._dirty = True
145
-
146
164
  def __getitem__(
147
165
  self, keywords: Union[str, Tuple[str, ...]]
148
166
  ) -> Union["FoamFile.Value", "FoamFile.Dictionary"]:
@@ -179,7 +197,7 @@ class FoamFile(
179
197
  start, end = get_entry_locn(parsed, keywords, missing_ok=True)
180
198
 
181
199
  self._write(
182
- f"{contents[:start]} {keywords[-1]} {{\n}}\n {contents[end:]}"
200
+ f"{contents[:start]}\n{serialize_entry(keywords[-1], {})}\n{contents[end:]}"
183
201
  )
184
202
 
185
203
  for k, v in value.items():
@@ -187,12 +205,8 @@ class FoamFile(
187
205
  else:
188
206
  start, end = get_entry_locn(parsed, keywords, missing_ok=True)
189
207
 
190
- value = serialize_value(
191
- value, assume_field=assume_field, assume_dimensions=assume_dimensions
192
- )
193
-
194
208
  self._write(
195
- f"{contents[:start]} {keywords[-1]} {value};\n {contents[end:]}"
209
+ f"{contents[:start]}\n{serialize_entry(keywords[-1], value, assume_field=assume_field, assume_dimensions=assume_dimensions)}\n{contents[end:]}"
196
210
  )
197
211
 
198
212
  def __setitem__(self, keywords: Union[str, Tuple[str, ...]], value: Any) -> None:
@@ -220,9 +234,23 @@ class FoamFile(
220
234
  def __iter__(self) -> Iterator[str]:
221
235
  return self._iter()
222
236
 
237
+ def __contains__(self, keywords: object) -> bool:
238
+ if not isinstance(keywords, tuple):
239
+ keywords = (keywords,)
240
+ _, parsed = self._read()
241
+ return keywords in parsed
242
+
223
243
  def __len__(self) -> int:
224
244
  return len(list(iter(self)))
225
245
 
246
+ def update(self, *args: Any, **kwargs: Any) -> None:
247
+ with self:
248
+ super().update(*args, **kwargs)
249
+
250
+ def clear(self) -> None:
251
+ with self:
252
+ super().clear()
253
+
226
254
  def __fspath__(self) -> str:
227
255
  return str(self.path)
228
256
 
@@ -1,5 +1,5 @@
1
1
  from contextlib import suppress
2
- from typing import Any, Sequence
2
+ from typing import Any, Mapping, Sequence
3
3
 
4
4
  from ._base import FoamDictionaryBase
5
5
 
@@ -31,7 +31,7 @@ def _serialize_bool(value: Any) -> str:
31
31
 
32
32
  def _serialize_list(value: Any) -> str:
33
33
  if _is_sequence(value):
34
- return f"({' '.join(serialize_value(v) for v in value)})"
34
+ return f"({' '.join(_serialize_value(v) for v in value)})"
35
35
  else:
36
36
  raise TypeError(f"Not a valid sequence: {type(value)}")
37
37
 
@@ -73,14 +73,14 @@ def _serialize_dimensions(value: Any) -> str:
73
73
  def _serialize_dimensioned(value: Any) -> str:
74
74
  if isinstance(value, FoamDictionaryBase.Dimensioned):
75
75
  if value.name is not None:
76
- return f"{value.name} {_serialize_dimensions(value.dimensions)} {serialize_value(value.value)}"
76
+ return f"{value.name} {_serialize_dimensions(value.dimensions)} {_serialize_value(value.value)}"
77
77
  else:
78
- return f"{_serialize_dimensions(value.dimensions)} {serialize_value(value.value)}"
78
+ return f"{_serialize_dimensions(value.dimensions)} {_serialize_value(value.value)}"
79
79
  else:
80
80
  raise TypeError(f"Not a valid dimensioned value: {type(value)}")
81
81
 
82
82
 
83
- def serialize_value(
83
+ def _serialize_value(
84
84
  value: Any, *, assume_field: bool = False, assume_dimensions: bool = False
85
85
  ) -> str:
86
86
  if isinstance(value, FoamDictionaryBase.DimensionSet) or assume_dimensions:
@@ -101,3 +101,23 @@ def serialize_value(
101
101
  return _serialize_bool(value)
102
102
 
103
103
  return str(value)
104
+
105
+
106
+ def _serialize_dictionary(value: Any) -> str:
107
+ if isinstance(value, Mapping):
108
+ return "\n".join(serialize_entry(k, v) for k, v in value.items())
109
+ else:
110
+ raise TypeError(f"Not a valid dictionary: {type(value)}")
111
+
112
+
113
+ def serialize_entry(
114
+ keyword: str,
115
+ value: Any,
116
+ *,
117
+ assume_field: bool = False,
118
+ assume_dimensions: bool = False,
119
+ ) -> str:
120
+ try:
121
+ return f"{keyword}\n{{\n{_serialize_dictionary(value)}\n}}"
122
+ except TypeError:
123
+ return f"{keyword} {_serialize_value(value, assume_field=assume_field, assume_dimensions=assume_dimensions)};"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foamlib
3
- Version: 0.2.3
3
+ Version: 0.2.4
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
@@ -27,6 +27,7 @@ Description-Content-Type: text/markdown
27
27
  License-File: LICENSE.txt
28
28
  Requires-Dist: aioshutil<2,>=1
29
29
  Requires-Dist: pyparsing<4,>=3
30
+ Requires-Dist: typing-extensions<5,>=4
30
31
  Provides-Extra: lint
31
32
  Requires-Dist: mypy<2,>=1; extra == "lint"
32
33
  Requires-Dist: pytest<9,>=7; extra == "lint"
@@ -1,5 +1,6 @@
1
1
  aioshutil<2,>=1
2
2
  pyparsing<4,>=3
3
+ typing-extensions<5,>=4
3
4
 
4
5
  [docs]
5
6
  sphinx<8,>=7
@@ -30,6 +30,7 @@ classifiers = [
30
30
  dependencies = [
31
31
  "aioshutil>=1,<2",
32
32
  "pyparsing>=3,<4",
33
+ "typing-extensions>=4,<5",
33
34
  ]
34
35
 
35
36
  dynamic = ["version"]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes