foamlib 0.3.7__py3-none-any.whl → 0.3.9__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,6 +1,6 @@
1
1
  """A Python interface for interacting with OpenFOAM."""
2
2
 
3
- __version__ = "0.3.7"
3
+ __version__ = "0.3.9"
4
4
 
5
5
  from ._cases import AsyncFoamCase, FoamCase, FoamCaseBase
6
6
  from ._files import FoamDict, FoamFieldFile, FoamFile
foamlib/_cases.py CHANGED
@@ -32,8 +32,6 @@ from ._util import is_sequence, run_process, run_process_async
32
32
  class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
33
33
  def __init__(self, path: Union[Path, str] = Path()):
34
34
  self.path = Path(path).absolute()
35
- if not self.path.is_dir():
36
- raise NotADirectoryError(f"{self.path} is not a directory")
37
35
 
38
36
  class TimeDirectory(Set[FoamFieldFile]):
39
37
  """
@@ -46,8 +44,6 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
46
44
 
47
45
  def __init__(self, path: Union[Path, str]):
48
46
  self.path = Path(path).absolute()
49
- if not self.path.is_dir():
50
- raise NotADirectoryError(f"{self.path} is not a directory")
51
47
 
52
48
  @property
53
49
  def time(self) -> float:
@@ -60,23 +56,29 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
60
56
  return self.path.name
61
57
 
62
58
  def __getitem__(self, key: str) -> FoamFieldFile:
63
- try:
59
+ if (self.path / key).is_file():
64
60
  return FoamFieldFile(self.path / key)
65
- except FileNotFoundError as e:
66
- raise KeyError(key) from e
61
+ elif (self.path / f"{key}.gz").is_file():
62
+ return FoamFieldFile(self.path / f"{key}.gz")
63
+ else:
64
+ raise KeyError(key)
67
65
 
68
66
  def __contains__(self, obj: object) -> bool:
69
67
  if isinstance(obj, FoamFieldFile):
70
68
  return obj.path.parent == self.path
71
69
  elif isinstance(obj, str):
72
- return (self.path / obj).is_file()
70
+ return (self.path / obj).is_file() or (
71
+ self.path / f"{obj}.gz"
72
+ ).is_file()
73
73
  else:
74
74
  return False
75
75
 
76
76
  def __iter__(self) -> Iterator[FoamFieldFile]:
77
77
  for p in self.path.iterdir():
78
- if p.is_file():
79
- yield FoamFieldFile(p.name)
78
+ if p.is_file() and (
79
+ p.suffix != ".gz" or not p.with_suffix("").is_file()
80
+ ):
81
+ yield FoamFieldFile(p)
80
82
 
81
83
  def __len__(self) -> int:
82
84
  return len(list(iter(self)))
@@ -118,7 +120,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
118
120
  self, index: Union[int, slice, float, str]
119
121
  ) -> Union["FoamCaseBase.TimeDirectory", Sequence["FoamCaseBase.TimeDirectory"]]:
120
122
  if isinstance(index, str):
121
- return FoamCaseBase.TimeDirectory(self.path / str(index))
123
+ return FoamCaseBase.TimeDirectory(self.path / index)
122
124
  elif isinstance(index, float):
123
125
  for time in self._times:
124
126
  if time.time == index:
@@ -148,9 +150,15 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
148
150
  if has_decompose_par_dict and p.name.startswith("processor"):
149
151
  paths.add(p)
150
152
 
153
+ if (self.path / "0.orig").is_dir() and (self.path / "0").is_dir():
154
+ paths.add(self.path / "0")
155
+
151
156
  if has_block_mesh_dict and (self.path / "constant" / "polyMesh").exists():
152
157
  paths.add(self.path / "constant" / "polyMesh")
153
158
 
159
+ if self._run_script() is not None:
160
+ paths.update(self.path.glob("log.*"))
161
+
154
162
  return paths
155
163
 
156
164
  def _clone_ignore(
@@ -176,7 +184,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
176
184
  else:
177
185
  return None
178
186
 
179
- def _run_script(self, *, parallel: Optional[bool]) -> Optional[Path]:
187
+ def _run_script(self, *, parallel: Optional[bool] = None) -> Optional[Path]:
180
188
  """Return the path to the (All)run script, or None if no run script is found."""
181
189
  run = self.path / "run"
182
190
  run_parallel = self.path / "run-parallel"
@@ -325,7 +333,10 @@ class FoamCase(FoamCaseBase):
325
333
  self.run([script_path], check=check)
326
334
  else:
327
335
  for p in self._clean_paths():
328
- shutil.rmtree(p)
336
+ if p.is_dir():
337
+ shutil.rmtree(p)
338
+ else:
339
+ p.unlink()
329
340
 
330
341
  def run(
331
342
  self,
@@ -359,6 +370,9 @@ class FoamCase(FoamCaseBase):
359
370
  return self.run([script_path], check=check)
360
371
 
361
372
  else:
373
+ if not self and (self.path / "0.orig").is_dir():
374
+ self.restore_0_dir()
375
+
362
376
  if (self.path / "system" / "blockMeshDict").is_file():
363
377
  self.block_mesh()
364
378
 
@@ -393,6 +407,11 @@ class FoamCase(FoamCaseBase):
393
407
  """Reconstruct this case after parallel running."""
394
408
  self.run(["reconstructPar"], check=check)
395
409
 
410
+ def restore_0_dir(self) -> None:
411
+ """Restore the 0 directory from the 0.orig directory."""
412
+ shutil.rmtree(self.path / "0", ignore_errors=True)
413
+ shutil.copytree(self.path / "0.orig", self.path / "0")
414
+
396
415
  def copy(self, dest: Union[Path, str]) -> "FoamCase":
397
416
  """
398
417
  Make a copy of this case.
@@ -478,7 +497,10 @@ class AsyncFoamCase(FoamCaseBase):
478
497
  await self.run([script_path], check=check)
479
498
  else:
480
499
  for p in self._clean_paths():
481
- await aioshutil.rmtree(p)
500
+ if p.is_dir():
501
+ await aioshutil.rmtree(p)
502
+ else:
503
+ p.unlink()
482
504
 
483
505
  async def run(
484
506
  self,
@@ -531,6 +553,9 @@ class AsyncFoamCase(FoamCaseBase):
531
553
  await self.run([script_path], check=check, cpus=cpus)
532
554
 
533
555
  else:
556
+ if not self and (self.path / "0.orig").is_dir():
557
+ await self.restore_0_dir()
558
+
534
559
  if (self.path / "system" / "blockMeshDict").is_file():
535
560
  await self.block_mesh()
536
561
 
@@ -572,6 +597,11 @@ class AsyncFoamCase(FoamCaseBase):
572
597
  """Reconstruct this case after parallel running."""
573
598
  await self.run(["reconstructPar"], check=check)
574
599
 
600
+ async def restore_0_dir(self) -> None:
601
+ """Restore the 0 directory from the 0.orig directory."""
602
+ await aioshutil.rmtree(self.path / "0", ignore_errors=True)
603
+ await aioshutil.copytree(self.path / "0.orig", self.path / "0")
604
+
575
605
  async def copy(self, dest: Union[Path, str]) -> "AsyncFoamCase":
576
606
  """
577
607
  Make a copy of this case.
foamlib/_files/_files.py CHANGED
@@ -101,7 +101,7 @@ class FoamFile(
101
101
  if value is ...:
102
102
  return FoamFile.SubDict(self, keywords)
103
103
  else:
104
- return value # type: ignore [return-value]
104
+ return value
105
105
 
106
106
  @property
107
107
  def _binary(self) -> bool:
foamlib/_files/_io.py CHANGED
@@ -1,3 +1,4 @@
1
+ import gzip
1
2
  import sys
2
3
  from copy import deepcopy
3
4
  from pathlib import Path
@@ -20,10 +21,6 @@ from ._parsing import Parsed
20
21
  class FoamFileIO:
21
22
  def __init__(self, path: Union[str, Path]) -> None:
22
23
  self.path = Path(path).absolute()
23
- if self.path.is_dir():
24
- raise IsADirectoryError(self.path)
25
- elif not self.path.is_file():
26
- raise FileNotFoundError(self.path)
27
24
 
28
25
  self.__contents: Optional[bytes] = None
29
26
  self.__parsed: Optional[Parsed] = None
@@ -51,6 +48,10 @@ class FoamFileIO:
51
48
  def _read(self) -> Tuple[bytes, Parsed]:
52
49
  if not self.__defer_io:
53
50
  contents = self.path.read_bytes()
51
+
52
+ if self.path.suffix == ".gz":
53
+ contents = gzip.decompress(contents)
54
+
54
55
  if contents != self.__contents:
55
56
  self.__contents = contents
56
57
  self.__parsed = None
@@ -67,6 +68,9 @@ class FoamFileIO:
67
68
  self.__contents = contents
68
69
  self.__parsed = None
69
70
  if not self.__defer_io:
71
+ if self.path.suffix == ".gz":
72
+ contents = gzip.compress(contents)
73
+
70
74
  self.path.write_bytes(contents)
71
75
  self.__dirty = False
72
76
  else:
@@ -247,6 +247,6 @@ class Parsed(Mapping[Tuple[str, ...], Union[FoamDict.Data, EllipsisType]]):
247
247
  r = v
248
248
 
249
249
  assert isinstance(r, dict)
250
- r[keywords[-1]] = {} if data is ... else data # type: ignore [assignment]
250
+ r[keywords[-1]] = {} if data is ... else data
251
251
 
252
252
  return ret
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foamlib
3
- Version: 0.3.7
3
+ Version: 0.3.9
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
@@ -45,7 +45,7 @@ Requires-Dist: pytest <9,>=7 ; extra == 'typing'
45
45
  Requires-Dist: pytest-asyncio <0.24,>=0.21 ; extra == 'typing'
46
46
  Requires-Dist: numpy <2,>=1 ; extra == 'typing'
47
47
 
48
- # foamlib
48
+ [<img alt="foamlib" src="https://github.com/gerlero/foamlib/raw/main/logo.png" height="50">](https://github.com/gerlero/foamlib)
49
49
 
50
50
  [![Documentation](https://img.shields.io/readthedocs/foamlib)](https://foamlib.readthedocs.io/)
51
51
  [![CI](https://github.com/gerlero/foamlib/actions/workflows/ci.yml/badge.svg)](https://github.com/gerlero/foamlib/actions/workflows/ci.yml)
@@ -54,7 +54,8 @@ Requires-Dist: numpy <2,>=1 ; extra == 'typing'
54
54
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
55
55
  [![PyPI](https://img.shields.io/pypi/v/foamlib)](https://pypi.org/project/foamlib/)
56
56
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/foamlib)](https://pypi.org/project/foamlib/)
57
- [![Docker image](https://img.shields.io/badge/docker%20image-gerlero%2Ffoamlib-informational)](https://hub.docker.com/r/gerlero/foamlib/)
57
+ ![OpenFOAM](https://img.shields.io/badge/openfoam-.com%20|%20.org-informational)
58
+ [![Docker image](https://img.shields.io/badge/docker%20image-microfluidica%2Ffoamlib-0085a0)](https://hub.docker.com/r/microfluidica/foamlib/)
58
59
 
59
60
  **foamlib** provides a simple, modern and ergonomic Python interface for interacting with [OpenFOAM](https://www.openfoam.com).
60
61
 
@@ -0,0 +1,15 @@
1
+ foamlib/__init__.py,sha256=VA5OODQTc1hOiKx4Hg0kYE_r9Q9num_-mR-wMHHhR1c,431
2
+ foamlib/_cases.py,sha256=4b9CCDAuKi5Dp8DUksIbaMsp0Yi0xv5QeZLVAUrKRh8,21417
3
+ foamlib/_util.py,sha256=vL03aAzpWdZyYIhe2WTxHiz9b4lnttVnRuzqUmZvXXk,3047
4
+ foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ foamlib/_files/__init__.py,sha256=vDkPj8u8bX_I_m2YfeKvXBgwg8D1ufyFCfHGHKN3JPQ,140
6
+ foamlib/_files/_base.py,sha256=YA5a-i5HZuA3JslCD6r-DwZzpSA8r42dqSXef286Ako,2050
7
+ foamlib/_files/_files.py,sha256=4rZb3HMJADmJBGmRpChiujJNX1UIxhgHI5YPEmEOWvE,10784
8
+ foamlib/_files/_io.py,sha256=pGYMoLI5Dz2Y90EB1CtklZiffpDTGuQbbbkyqRe0JAo,2115
9
+ foamlib/_files/_parsing.py,sha256=sWUeF9xiM6AriQjljl3jEpvoFRMmaS1h3bT3b0oor3U,7279
10
+ foamlib/_files/_serialization.py,sha256=rmZW42Pyn1DIJbGMZqFG_lZ5DcLhPmfUgH24qsu2rIk,3400
11
+ foamlib-0.3.9.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
12
+ foamlib-0.3.9.dist-info/METADATA,sha256=FmZVopicBSscMw3JI3D6dnpLLDfcHLn4BQkrhklp8Sw,5242
13
+ foamlib-0.3.9.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
14
+ foamlib-0.3.9.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
15
+ foamlib-0.3.9.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- foamlib/__init__.py,sha256=hW4v8Ud3Ftd_sV1O_SuF4JzxkLRjjKwCl-A81aOu0zo,431
2
- foamlib/_cases.py,sha256=ELwX-Gr3ZB11axG6coHqXDyGh9Xb7kgAfYkhCsEGZy4,20278
3
- foamlib/_util.py,sha256=vL03aAzpWdZyYIhe2WTxHiz9b4lnttVnRuzqUmZvXXk,3047
4
- foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- foamlib/_files/__init__.py,sha256=vDkPj8u8bX_I_m2YfeKvXBgwg8D1ufyFCfHGHKN3JPQ,140
6
- foamlib/_files/_base.py,sha256=YA5a-i5HZuA3JslCD6r-DwZzpSA8r42dqSXef286Ako,2050
7
- foamlib/_files/_files.py,sha256=JcOVP3eu9QYCOPt_DfobigKsd0VqgJRfEVytMOwES_g,10815
8
- foamlib/_files/_io.py,sha256=So9rG6iW77sRK2xFz5KHX6AFtYc2L19voAwn-_NmQow,2075
9
- foamlib/_files/_parsing.py,sha256=-zSpEDjuPxzOdsLWaeQl7j6FZHyw2-jXNgOCXkcGskU,7308
10
- foamlib/_files/_serialization.py,sha256=rmZW42Pyn1DIJbGMZqFG_lZ5DcLhPmfUgH24qsu2rIk,3400
11
- foamlib-0.3.7.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
12
- foamlib-0.3.7.dist-info/METADATA,sha256=CqC7YFwGgMYkr_niGYF3p_675P8Jc1670msKlZcqjZw,5037
13
- foamlib-0.3.7.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
14
- foamlib-0.3.7.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
15
- foamlib-0.3.7.dist-info/RECORD,,