foamlib 0.8.3__tar.gz → 0.8.5__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 (51) hide show
  1. {foamlib-0.8.3 → foamlib-0.8.5}/PKG-INFO +1 -1
  2. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/__init__.py +1 -1
  3. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_files/_files.py +3 -3
  4. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_files/_parsing.py +26 -9
  5. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_files/_serialization.py +4 -1
  6. {foamlib-0.8.3 → foamlib-0.8.5}/tests/test_files/test_parsing.py +9 -0
  7. {foamlib-0.8.3 → foamlib-0.8.5}/.devcontainer.json +0 -0
  8. {foamlib-0.8.3 → foamlib-0.8.5}/.dockerignore +0 -0
  9. {foamlib-0.8.3 → foamlib-0.8.5}/.git-blame-ignore-revs +0 -0
  10. {foamlib-0.8.3 → foamlib-0.8.5}/.github/dependabot.yml +0 -0
  11. {foamlib-0.8.3 → foamlib-0.8.5}/.github/workflows/ci.yml +0 -0
  12. {foamlib-0.8.3 → foamlib-0.8.5}/.github/workflows/docker.yml +0 -0
  13. {foamlib-0.8.3 → foamlib-0.8.5}/.github/workflows/dockerhub-description.yml +0 -0
  14. {foamlib-0.8.3 → foamlib-0.8.5}/.github/workflows/pypi-publish.yml +0 -0
  15. {foamlib-0.8.3 → foamlib-0.8.5}/.gitignore +0 -0
  16. {foamlib-0.8.3 → foamlib-0.8.5}/.readthedocs.yaml +0 -0
  17. {foamlib-0.8.3 → foamlib-0.8.5}/Dockerfile +0 -0
  18. {foamlib-0.8.3 → foamlib-0.8.5}/LICENSE.txt +0 -0
  19. {foamlib-0.8.3 → foamlib-0.8.5}/README.md +0 -0
  20. {foamlib-0.8.3 → foamlib-0.8.5}/benchmark.png +0 -0
  21. {foamlib-0.8.3 → foamlib-0.8.5}/docs/Makefile +0 -0
  22. {foamlib-0.8.3 → foamlib-0.8.5}/docs/cases.rst +0 -0
  23. {foamlib-0.8.3 → foamlib-0.8.5}/docs/conf.py +0 -0
  24. {foamlib-0.8.3 → foamlib-0.8.5}/docs/files.rst +0 -0
  25. {foamlib-0.8.3 → foamlib-0.8.5}/docs/index.rst +0 -0
  26. {foamlib-0.8.3 → foamlib-0.8.5}/docs/make.bat +0 -0
  27. {foamlib-0.8.3 → foamlib-0.8.5}/docs/ruff.toml +0 -0
  28. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_cases/__init__.py +0 -0
  29. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_cases/_async.py +0 -0
  30. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_cases/_base.py +0 -0
  31. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_cases/_run.py +0 -0
  32. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_cases/_slurm.py +0 -0
  33. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_cases/_subprocess.py +0 -0
  34. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_cases/_sync.py +0 -0
  35. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_cases/_util.py +0 -0
  36. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_files/__init__.py +0 -0
  37. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_files/_io.py +0 -0
  38. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/_files/_types.py +0 -0
  39. {foamlib-0.8.3 → foamlib-0.8.5}/foamlib/py.typed +0 -0
  40. {foamlib-0.8.3 → foamlib-0.8.5}/logo.png +0 -0
  41. {foamlib-0.8.3 → foamlib-0.8.5}/pyproject.toml +0 -0
  42. {foamlib-0.8.3 → foamlib-0.8.5}/tests/__init__.py +0 -0
  43. {foamlib-0.8.3 → foamlib-0.8.5}/tests/ruff.toml +0 -0
  44. {foamlib-0.8.3 → foamlib-0.8.5}/tests/test_cases/__init__.py +0 -0
  45. {foamlib-0.8.3 → foamlib-0.8.5}/tests/test_cases/test_cavity.py +0 -0
  46. {foamlib-0.8.3 → foamlib-0.8.5}/tests/test_cases/test_cavity_async.py +0 -0
  47. {foamlib-0.8.3 → foamlib-0.8.5}/tests/test_cases/test_flange.py +0 -0
  48. {foamlib-0.8.3 → foamlib-0.8.5}/tests/test_cases/test_flange_async.py +0 -0
  49. {foamlib-0.8.3 → foamlib-0.8.5}/tests/test_files/__init__.py +0 -0
  50. {foamlib-0.8.3 → foamlib-0.8.5}/tests/test_files/test_dumps.py +0 -0
  51. {foamlib-0.8.3 → foamlib-0.8.5}/tests/test_files/test_files.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: foamlib
3
- Version: 0.8.3
3
+ Version: 0.8.5
4
4
  Summary: A Python interface for interacting with OpenFOAM
5
5
  Project-URL: Homepage, https://github.com/gerlero/foamlib
6
6
  Project-URL: Repository, https://github.com/gerlero/foamlib
@@ -1,6 +1,6 @@
1
1
  """A Python interface for interacting with OpenFOAM."""
2
2
 
3
- __version__ = "0.8.3"
3
+ __version__ = "0.8.5"
4
4
 
5
5
  from ._cases import (
6
6
  AsyncFoamCase,
@@ -308,15 +308,15 @@ class FoamFile(
308
308
  self[(*keywords, k)] = v
309
309
 
310
310
  elif keywords:
311
+ val = dumps(data, kind=kind)
311
312
  parsed.put(
312
313
  keywords,
313
314
  normalize(data, kind=kind),
314
315
  before
315
316
  + indentation
316
317
  + dumps(keywords[-1])
317
- + b" "
318
- + dumps(data, kind=kind)
319
- + b";"
318
+ + ((b" " + val) if val else b"")
319
+ + (b";" if not keywords[-1].startswith("#") else b"")
320
320
  + after,
321
321
  )
322
322
 
@@ -153,12 +153,19 @@ def _tensor_list(
153
153
 
154
154
 
155
155
  def _dict_of(
156
- keyword: ParserElement, data: ParserElement, *, located: bool = False
156
+ keyword: ParserElement,
157
+ data: ParserElement,
158
+ *,
159
+ directive: ParserElement | None = None,
160
+ located: bool = False,
157
161
  ) -> ParserElement:
158
162
  dict_ = Forward()
159
163
 
160
164
  keyword_entry = keyword + (dict_ | (data + Literal(";").suppress()))
161
165
 
166
+ if directive is not None:
167
+ keyword_entry |= directive + data + LineEnd().suppress() # type: ignore [no-untyped-call]
168
+
162
169
  if located:
163
170
  keyword_entry = Located(keyword_entry)
164
171
 
@@ -175,12 +182,17 @@ def _keyword_entry_of(
175
182
  keyword: ParserElement,
176
183
  data: ParserElement,
177
184
  *,
185
+ directive: ParserElement | None = None,
178
186
  located: bool = False,
179
187
  ) -> ParserElement:
180
188
  keyword_entry = keyword + (
181
- _dict_of(keyword, data, located=located) | (data + Literal(";").suppress())
189
+ _dict_of(keyword, data, directive=directive, located=located)
190
+ | (data + Literal(";").suppress())
182
191
  )
183
192
 
193
+ if directive is not None:
194
+ keyword_entry |= directive + data + LineEnd().suppress() # type: ignore [no-untyped-call]
195
+
184
196
  if located:
185
197
  keyword_entry = Located(keyword_entry)
186
198
  else:
@@ -223,11 +235,12 @@ _TENSOR = (
223
235
  | _tensor(TensorKind.SYMM_TENSOR)
224
236
  | _tensor(TensorKind.TENSOR)
225
237
  )
226
- _IDENTIFIER = Forward()
227
- _IDENTIFIER <<= Combine(
228
- Word(_IDENTCHARS, _IDENTBODYCHARS, exclude_chars="()")
229
- + Opt(Literal("(") + _IDENTIFIER + Literal(")"))
238
+ _PARENTHESIZED = Forward()
239
+ _IDENTIFIER = Combine(
240
+ Word(_IDENTCHARS, _IDENTBODYCHARS, exclude_chars="()") + Opt(_PARENTHESIZED)
230
241
  )
242
+ _PARENTHESIZED <<= Combine(Literal("(") + (_PARENTHESIZED | _IDENTIFIER) + Literal(")"))
243
+
231
244
  _DIMENSIONED = (Opt(_IDENTIFIER) + _DIMENSIONS + _TENSOR).set_parse_action(
232
245
  lambda tks: Dimensioned(*reversed(tks.as_list()))
233
246
  )
@@ -240,7 +253,8 @@ _FIELD = (Keyword("uniform", _IDENTBODYCHARS).suppress() + _TENSOR) | (
240
253
  | _tensor_list(TensorKind.TENSOR, ignore=_COMMENT)
241
254
  )
242
255
  )
243
- _TOKEN = dbl_quoted_string | _IDENTIFIER
256
+ _DIRECTIVE = Word("#", _IDENTBODYCHARS)
257
+ _TOKEN = dbl_quoted_string | _IDENTIFIER | _DIRECTIVE
244
258
  _DATA = Forward()
245
259
  _KEYWORD_ENTRY = _keyword_entry_of(_TOKEN | _list_of(_IDENTIFIER), _DATA)
246
260
  _DICT = _dict_of(_TOKEN, _DATA)
@@ -259,18 +273,21 @@ _DATA <<= (
259
273
 
260
274
 
261
275
  def parse_data(s: str) -> Data:
276
+ if not s.strip():
277
+ return ""
262
278
  return cast(Data, _DATA.parse_string(s, parse_all=True)[0])
263
279
 
264
280
 
265
281
  _LOCATED_DICTIONARY = Group(
266
- _keyword_entry_of(_TOKEN, Opt(_DATA, default=""), located=True)
282
+ _keyword_entry_of(
283
+ _TOKEN, Opt(_DATA, default=""), directive=_DIRECTIVE, located=True
284
+ )
267
285
  )[...]
268
286
  _LOCATED_DATA = Group(Located(_DATA.copy().add_parse_action(lambda tks: ["", tks[0]])))
269
287
 
270
288
  _FILE = (
271
289
  Dict(_LOCATED_DICTIONARY + Opt(_LOCATED_DATA) + _LOCATED_DICTIONARY)
272
290
  .ignore(_COMMENT)
273
- .ignore(Literal("#include") + ... + LineEnd()) # type: ignore [no-untyped-call]
274
291
  .parse_with_tabs()
275
292
  )
276
293
 
@@ -111,7 +111,10 @@ def dumps(
111
111
 
112
112
  if isinstance(data, tuple) and kind == Kind.SINGLE_ENTRY and len(data) == 2:
113
113
  k, v = data
114
- ret = dumps(k) + b" " + dumps(v)
114
+ ret = dumps(k)
115
+ val = dumps(v)
116
+ if val:
117
+ ret += b" " + val
115
118
  if not isinstance(v, Mapping):
116
119
  ret += b";"
117
120
  return ret
@@ -93,8 +93,17 @@ def test_parse_value() -> None:
93
93
  assert Parsed(b"(water oil mercury air)")[()] == ["water", "oil", "mercury", "air"]
94
94
  assert Parsed(b"div(phi,U)")[()] == "div(phi,U)"
95
95
  assert Parsed(b"div(nuEff*dev(T(grad(U))))")[()] == "div(nuEff*dev(T(grad(U))))"
96
+ assert Parsed(b"div((nuEff*dev(T(grad(U)))))")[()] == "div((nuEff*dev(T(grad(U)))))"
96
97
  assert Parsed(b"((air and water) { type constant; sigma 0.07; })")[()] == [
97
98
  (["air", "and", "water"], {"type": "constant", "sigma": 0.07})
98
99
  ]
99
100
  assert Parsed(b"[]")[()] == FoamFile.DimensionSet()
100
101
  assert Parsed(b"object f.1;")[("object",)] == "f.1"
102
+
103
+
104
+ def test_parse_directive() -> None:
105
+ assert Parsed(b'#include "filename"')[("#include",)] == '"filename"'
106
+ assert (
107
+ Parsed(b"functions\n{\n#includeFunc funcName\n}")[("functions", "#includeFunc")]
108
+ == "funcName"
109
+ )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes