foamlib 0.7.2__py3-none-any.whl → 0.7.3__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.7.2"
3
+ __version__ = "0.7.3"
4
4
 
5
5
  from ._cases import (
6
6
  AsyncFoamCase,
foamlib/_files/_files.py CHANGED
@@ -19,10 +19,10 @@ from ._io import FoamFileIO
19
19
  from ._serialization import Kind, dumps, normalize
20
20
  from ._types import (
21
21
  Data,
22
- DataEntry,
23
22
  Dict_,
24
23
  Dimensioned,
25
24
  DimensionSet,
25
+ Entry,
26
26
  Field,
27
27
  File,
28
28
  MutableData,
@@ -57,13 +57,13 @@ class FoamFile(
57
57
  self._file = _file
58
58
  self._keywords = _keywords
59
59
 
60
- def __getitem__(self, keyword: str) -> DataEntry | FoamFile.SubDict:
60
+ def __getitem__(self, keyword: str) -> Data | FoamFile.SubDict:
61
61
  return self._file[(*self._keywords, keyword)]
62
62
 
63
63
  def __setitem__(
64
64
  self,
65
65
  keyword: str,
66
- data: Data,
66
+ data: Entry,
67
67
  ) -> None:
68
68
  self._file[(*self._keywords, keyword)] = data
69
69
 
@@ -174,7 +174,7 @@ class FoamFile(
174
174
 
175
175
  def __getitem__(
176
176
  self, keywords: str | tuple[str, ...] | None
177
- ) -> DataEntry | FoamFile.SubDict:
177
+ ) -> Data | FoamFile.SubDict:
178
178
  if not keywords:
179
179
  keywords = ()
180
180
  elif not isinstance(keywords, tuple):
@@ -190,7 +190,7 @@ class FoamFile(
190
190
  return FoamFile.SubDict(self, keywords)
191
191
  return deepcopy(value)
192
192
 
193
- def __setitem__(self, keywords: str | tuple[str, ...] | None, data: Data) -> None:
193
+ def __setitem__(self, keywords: str | tuple[str, ...] | None, data: Entry) -> None:
194
194
  if not keywords:
195
195
  keywords = ()
196
196
  elif not isinstance(keywords, tuple):
@@ -438,7 +438,7 @@ class FoamFieldFile(FoamFile):
438
438
 
439
439
  def __getitem__(
440
440
  self, keywords: str | tuple[str, ...] | None
441
- ) -> DataEntry | FoamFile.SubDict:
441
+ ) -> Data | FoamFile.SubDict:
442
442
  if not keywords:
443
443
  keywords = ()
444
444
  elif not isinstance(keywords, tuple):
@@ -16,7 +16,6 @@ else:
16
16
  from typing import Any as EllipsisType
17
17
 
18
18
  from pyparsing import (
19
- CharsNotIn,
20
19
  Combine,
21
20
  Dict,
22
21
  Forward,
@@ -28,16 +27,16 @@ from pyparsing import (
28
27
  Opt,
29
28
  ParserElement,
30
29
  ParseResults,
31
- QuotedString,
32
30
  Regex,
33
31
  Word,
34
32
  common,
35
33
  counted_array,
34
+ dbl_quoted_string,
36
35
  identchars,
37
36
  printables,
38
37
  )
39
38
 
40
- from ._types import DataEntry, Dimensioned, DimensionSet, File
39
+ from ._types import Data, Dimensioned, DimensionSet, File
41
40
 
42
41
 
43
42
  def _list_of(entry: ParserElement) -> ParserElement:
@@ -59,18 +58,52 @@ def _list_of(entry: ParserElement) -> ParserElement:
59
58
  )
60
59
 
61
60
 
62
- def _counted_tensor_list(*, size: int, ignore: Regex) -> ParserElement:
63
- float_pattern = r"[+-]?((\d+\.?\d*(e[+-]?\d+)?)|nan|inf(inity)?)"
64
- ignore_pattern = rf"(?:\s|{ignore.re.pattern})+"
61
+ def _parse_ascii_field(
62
+ s: str, *, elsize: int, ignore: Regex | None
63
+ ) -> list[float] | list[list[float]]:
64
+ values = [
65
+ float(v)
66
+ for v in (re.sub(ignore.re, " ", s) if ignore is not None else s)
67
+ .replace("(", " ")
68
+ .replace(")", " ")
69
+ .split()
70
+ ]
65
71
 
66
- if size == 1:
72
+ if elsize == 1:
73
+ return values
74
+
75
+ return [values[i : i + elsize] for i in range(0, len(values), elsize)]
76
+
77
+
78
+ def _unpack_binary_field(
79
+ b: bytes, *, elsize: int, length: int
80
+ ) -> list[float] | list[list[float]]:
81
+ float_size = len(b) / elsize / length
82
+ assert float_size in (4, 8)
83
+
84
+ arr = array.array("f" if float_size == 4 else "d", b)
85
+ values = arr.tolist()
86
+
87
+ if elsize == 1:
88
+ return values
89
+
90
+ return [values[i : i + elsize] for i in range(0, len(values), elsize)]
91
+
92
+
93
+ def _counted_tensor_list(
94
+ *, elsize: int = 1, ignore: Regex | None = None
95
+ ) -> ParserElement:
96
+ float_pattern = r"(?i:[+-]?(?:(?:\d+\.?\d*(?:e[+-]?\d+)?)|nan|inf(?:inity)?))"
97
+ ignore_pattern = rf"(?:\s|{ignore.re.pattern})+" if ignore is not None else r"\s+"
98
+
99
+ if elsize == 1:
67
100
  tensor_pattern = float_pattern
68
101
  tensor = common.ieee_float
69
102
  else:
70
- tensor_pattern = rf"\((?:{ignore_pattern})?(?:{float_pattern}{ignore_pattern}){{{size - 1}}}{float_pattern}(?:{ignore_pattern})?\)"
103
+ tensor_pattern = rf"\((?:{ignore_pattern})?(?:{float_pattern}{ignore_pattern}){{{elsize - 1}}}{float_pattern}(?:{ignore_pattern})?\)"
71
104
  tensor = (
72
105
  Literal("(").suppress()
73
- + Group(common.ieee_float[size], aslist=True)
106
+ + Group(common.ieee_float[elsize], aslist=True)
74
107
  + Literal(")").suppress()
75
108
  )
76
109
 
@@ -81,34 +114,29 @@ def _counted_tensor_list(*, size: int, ignore: Regex) -> ParserElement:
81
114
  length = tks[0]
82
115
  assert isinstance(length, int)
83
116
 
84
- list_ <<= Regex(
85
- rf"\((?:{ignore_pattern})?(?:{tensor_pattern}{ignore_pattern}){{{length - 1}}}{tensor_pattern}(?:{ignore_pattern})?\)",
86
- flags=re.IGNORECASE,
117
+ list_ <<= (
118
+ Regex(
119
+ rf"\((?:{ignore_pattern})?(?:{tensor_pattern}{ignore_pattern}){{{length - 1}}}{tensor_pattern}(?:{ignore_pattern})?\)"
120
+ ).add_parse_action(
121
+ lambda tks: [_parse_ascii_field(tks[0], elsize=elsize, ignore=ignore)]
122
+ )
123
+ | Regex(
124
+ rf"\((?s:.{{{length * elsize * 8}}}|.{{{length * elsize * 4}}})\)"
125
+ ).set_parse_action(
126
+ lambda tks: [
127
+ _unpack_binary_field(
128
+ tks[0][1:-1].encode("latin-1"), elsize=elsize, length=length
129
+ )
130
+ ]
131
+ )
132
+ | (
133
+ Literal("{").suppress() + tensor + Literal("}").suppress()
134
+ ).set_parse_action(lambda tks: [[tks[0]] * length])
87
135
  )
88
136
 
89
- count = common.integer.add_parse_action(count_parse_action)
90
-
91
- def list_parse_action(
92
- tks: ParseResults,
93
- ) -> list[list[float]] | list[list[list[float]]]:
94
- values = [
95
- float(v)
96
- for v in re.sub(ignore.re, " ", tks[0])
97
- .replace("(", " ")
98
- .replace(")", " ")
99
- .split()
100
- ]
101
-
102
- if size == 1:
103
- return [values]
104
-
105
- return [[values[i : i + size] for i in range(0, len(values), size)]]
137
+ count = common.integer.copy().add_parse_action(count_parse_action)
106
138
 
107
- list_.add_parse_action(list_parse_action)
108
-
109
- return (count.suppress() + list_) | (
110
- common.integer + Literal("{").suppress() + tensor + Literal("}").suppress()
111
- ).set_parse_action(lambda tks: [[tks[1]] * tks[0]])
139
+ return count.suppress() + list_
112
140
 
113
141
 
114
142
  def _keyword_entry_of(
@@ -132,25 +160,6 @@ def _keyword_entry_of(
132
160
  return keyword_entry
133
161
 
134
162
 
135
- def _unpack_binary_field(
136
- tks: ParseResults,
137
- *,
138
- elsize: int = 1,
139
- ) -> Sequence[Sequence[float] | Sequence[Sequence[float]]]:
140
- float_size = len(tks[0]) // elsize
141
-
142
- arr = array.array("f" if float_size == 4 else "d", "".join(tks).encode("latin-1"))
143
-
144
- values: Sequence[float] | Sequence[Sequence[float]]
145
-
146
- if elsize != 1:
147
- values = [arr[i : i + elsize].tolist() for i in range(0, len(arr), elsize)]
148
- else:
149
- values = arr.tolist()
150
-
151
- return [values]
152
-
153
-
154
163
  # https://github.com/pyparsing/pyparsing/pull/584
155
164
  _COMMENT = Regex(r"(?:/\*(?:[^*]|\*(?!/))*\*/)|(?://(?:\\\n|[^\n])*)")
156
165
 
@@ -202,103 +211,27 @@ _FIELD = (Keyword("uniform", _IDENTBODYCHARS).suppress() + _TENSOR) | (
202
211
  (
203
212
  Literal("scalar").suppress()
204
213
  + Literal(">").suppress()
205
- + (
206
- _counted_tensor_list(size=1, ignore=_COMMENT)
207
- | (
208
- (
209
- (
210
- counted_array(
211
- CharsNotIn(exact=8),
212
- common.integer + Literal("(").suppress(),
213
- )
214
- )
215
- | (
216
- counted_array(
217
- CharsNotIn(exact=4),
218
- common.integer + Literal("(").suppress(),
219
- )
220
- )
221
- )
222
- + Literal(")").suppress()
223
- ).set_parse_action(_unpack_binary_field)
224
- )
214
+ + _counted_tensor_list(elsize=1, ignore=_COMMENT)
225
215
  )
226
216
  | (
227
217
  Literal("vector").suppress()
228
218
  + Literal(">").suppress()
229
- + (
230
- _counted_tensor_list(size=3, ignore=_COMMENT)
231
- | (
232
- (
233
- (
234
- counted_array(
235
- CharsNotIn(exact=8 * 3),
236
- common.integer + Literal("(").suppress(),
237
- )
238
- )
239
- | (
240
- counted_array(
241
- CharsNotIn(exact=4 * 3),
242
- common.integer + Literal("(").suppress(),
243
- )
244
- )
245
- )
246
- + Literal(")").suppress()
247
- ).set_parse_action(lambda tks: _unpack_binary_field(tks, elsize=3))
248
- )
219
+ + _counted_tensor_list(elsize=3, ignore=_COMMENT)
249
220
  )
250
221
  | (
251
222
  Literal("symmTensor").suppress()
252
223
  + Literal(">").suppress()
253
- + (
254
- _counted_tensor_list(size=6, ignore=_COMMENT)
255
- | (
256
- (
257
- (
258
- counted_array(
259
- CharsNotIn(exact=8 * 6),
260
- common.integer + Literal("(").suppress(),
261
- )
262
- )
263
- | (
264
- counted_array(
265
- CharsNotIn(exact=4 * 6),
266
- common.integer + Literal("(").suppress(),
267
- )
268
- )
269
- )
270
- + Literal(")").suppress()
271
- ).set_parse_action(lambda tks: _unpack_binary_field(tks, elsize=6))
272
- )
224
+ + _counted_tensor_list(elsize=6, ignore=_COMMENT)
273
225
  )
274
226
  | (
275
227
  Literal("tensor").suppress()
276
228
  + Literal(">").suppress()
277
- + (
278
- _counted_tensor_list(size=9, ignore=_COMMENT)
279
- | (
280
- (
281
- (
282
- counted_array(
283
- CharsNotIn(exact=8 * 9),
284
- common.integer + Literal("(").suppress(),
285
- )
286
- )
287
- | (
288
- counted_array(
289
- CharsNotIn(exact=4 * 9),
290
- common.integer + Literal("(").suppress(),
291
- )
292
- )
293
- )
294
- + Literal(")").suppress()
295
- ).set_parse_action(lambda tks: _unpack_binary_field(tks, elsize=9))
296
- )
229
+ + _counted_tensor_list(elsize=9, ignore=_COMMENT)
297
230
  )
298
231
  )
299
232
  )
300
233
  )
301
- _TOKEN = QuotedString('"', unquote_results=False) | _IDENTIFIER
234
+ _TOKEN = dbl_quoted_string | _IDENTIFIER
302
235
  DATA = Forward()
303
236
  KEYWORD = (
304
237
  _TOKEN
@@ -333,11 +266,11 @@ _FILE = (
333
266
  )
334
267
 
335
268
 
336
- class Parsed(Mapping[Tuple[str, ...], Union[DataEntry, EllipsisType]]):
269
+ class Parsed(Mapping[Tuple[str, ...], Union[Data, EllipsisType]]):
337
270
  def __init__(self, contents: bytes) -> None:
338
271
  self._parsed: MutableMapping[
339
272
  tuple[str, ...],
340
- tuple[int, DataEntry | EllipsisType, int],
273
+ tuple[int, Data | EllipsisType, int],
341
274
  ] = {}
342
275
  for parse_result in _FILE.parse_string(
343
276
  contents.decode("latin-1"), parse_all=True
@@ -350,10 +283,10 @@ class Parsed(Mapping[Tuple[str, ...], Union[DataEntry, EllipsisType]]):
350
283
  @staticmethod
351
284
  def _flatten_result(
352
285
  parse_result: ParseResults, *, _keywords: tuple[str, ...] = ()
353
- ) -> Mapping[tuple[str, ...], tuple[int, DataEntry | EllipsisType, int]]:
286
+ ) -> Mapping[tuple[str, ...], tuple[int, Data | EllipsisType, int]]:
354
287
  ret: MutableMapping[
355
288
  tuple[str, ...],
356
- tuple[int, DataEntry | EllipsisType, int],
289
+ tuple[int, Data | EllipsisType, int],
357
290
  ] = {}
358
291
  start = parse_result.locn_start
359
292
  assert isinstance(start, int)
@@ -380,14 +313,14 @@ class Parsed(Mapping[Tuple[str, ...], Union[DataEntry, EllipsisType]]):
380
313
  ret[(*_keywords, keyword)] = (start, d, end)
381
314
  return ret
382
315
 
383
- def __getitem__(self, keywords: tuple[str, ...]) -> DataEntry | EllipsisType:
316
+ def __getitem__(self, keywords: tuple[str, ...]) -> Data | EllipsisType:
384
317
  _, data, _ = self._parsed[keywords]
385
318
  return data
386
319
 
387
320
  def put(
388
321
  self,
389
322
  keywords: tuple[str, ...],
390
- data: DataEntry | EllipsisType,
323
+ data: Data | EllipsisType,
391
324
  content: bytes,
392
325
  ) -> None:
393
326
  start, end = self.entry_location(keywords, missing_ok=True)
@@ -12,7 +12,7 @@ else:
12
12
  from typing import Mapping, Sequence
13
13
 
14
14
  from ._parsing import DATA, KEYWORD
15
- from ._types import Data, DataEntry, Dimensioned, DimensionSet
15
+ from ._types import Data, Dimensioned, DimensionSet, Entry
16
16
  from ._util import is_sequence
17
17
 
18
18
  try:
@@ -34,14 +34,14 @@ class Kind(Enum):
34
34
 
35
35
 
36
36
  @overload
37
- def normalize(data: DataEntry, *, kind: Kind = Kind.DEFAULT) -> DataEntry: ...
37
+ def normalize(data: Data, *, kind: Kind = Kind.DEFAULT) -> Data: ...
38
38
 
39
39
 
40
40
  @overload
41
- def normalize(data: Data, *, kind: Kind = Kind.DEFAULT) -> Data: ...
41
+ def normalize(data: Entry, *, kind: Kind = Kind.DEFAULT) -> Entry: ...
42
42
 
43
43
 
44
- def normalize(data: Data, *, kind: Kind = Kind.DEFAULT) -> Data:
44
+ def normalize(data: Entry, *, kind: Kind = Kind.DEFAULT) -> Entry:
45
45
  if numpy and isinstance(data, np.ndarray):
46
46
  ret = data.tolist()
47
47
  assert isinstance(ret, list)
@@ -76,7 +76,7 @@ def normalize(data: Data, *, kind: Kind = Kind.DEFAULT) -> Data:
76
76
  assert isinstance(data, str)
77
77
  return data
78
78
 
79
- return cast(DataEntry, DATA.parse_string(data, parse_all=True)[0])
79
+ return cast(Data, DATA.parse_string(data, parse_all=True)[0])
80
80
 
81
81
  if isinstance(
82
82
  data,
@@ -89,7 +89,7 @@ def normalize(data: Data, *, kind: Kind = Kind.DEFAULT) -> Data:
89
89
 
90
90
 
91
91
  def dumps(
92
- data: Data,
92
+ data: Entry,
93
93
  *,
94
94
  kind: Kind = Kind.DEFAULT,
95
95
  ) -> bytes:
foamlib/_files/_types.py CHANGED
@@ -46,33 +46,36 @@ class Dimensioned:
46
46
 
47
47
 
48
48
  Field = Union[
49
- Tensor, Sequence[Tensor], "np.ndarray[Tuple[int, int], np.dtype[np.generic]]"
49
+ Tensor,
50
+ Sequence[Tensor],
51
+ "np.ndarray[Tuple[int], np.dtype[np.generic]]",
52
+ "np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
50
53
  ]
51
54
 
52
- DataEntry = Union[
55
+ Data = Union[
53
56
  str,
54
57
  int,
55
58
  float,
56
59
  bool,
57
60
  Dimensioned,
58
61
  DimensionSet,
59
- Sequence["Data"],
62
+ Sequence["Entry"],
60
63
  Tensor,
61
64
  Field,
62
65
  ]
63
66
 
64
- Data = Union[
65
- DataEntry,
66
- Mapping[str, "Data"],
67
+ Entry = Union[
68
+ Data,
69
+ Mapping[str, "Entry"],
67
70
  ]
68
71
  """
69
72
  A value that can be stored in an OpenFOAM file.
70
73
  """
71
74
 
72
75
  MutableData = Union[
73
- DataEntry,
76
+ Data,
74
77
  MutableMapping[str, "MutableData"],
75
78
  ]
76
79
 
77
- Dict_ = Dict[str, Union["Data", "Dict_"]]
78
- File = Dict[Optional[str], Union["Data", "Dict_"]]
80
+ Dict_ = Dict[str, Union["Entry", "Dict_"]]
81
+ File = Dict[Optional[str], Union["Entry", "Dict_"]]
foamlib/_files/_util.py CHANGED
@@ -14,10 +14,10 @@ else:
14
14
  from typing_extensions import TypeGuard
15
15
 
16
16
  if TYPE_CHECKING:
17
- from ._types import Data
17
+ from ._types import Entry
18
18
 
19
19
 
20
20
  def is_sequence(
21
- value: Data,
22
- ) -> TypeGuard[Sequence[Data]]:
21
+ value: Entry,
22
+ ) -> TypeGuard[Sequence[Entry]]:
23
23
  return isinstance(value, Sequence) and not isinstance(value, str)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foamlib
3
- Version: 0.7.2
3
+ Version: 0.7.3
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
@@ -1,4 +1,4 @@
1
- foamlib/__init__.py,sha256=YrFnCARXwvjW-QZzK9cS_ivto2gvTEJwdSVU5ZfCBkM,452
1
+ foamlib/__init__.py,sha256=GdEjgMru_5M1AG0ltkVKqNek6vw5aI4j_6QNApGRqsg,452
2
2
  foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  foamlib/_cases/__init__.py,sha256=wTUHcUgU1CBgpu0cUMtksQ5VKG6B8CFu9xc3dWwsQuo,358
4
4
  foamlib/_cases/_async.py,sha256=i6g4EBHqvI-1PkdrxsRto2ynW7sxsOga2bSYk1XVG1U,7795
@@ -9,14 +9,14 @@ foamlib/_cases/_subprocess.py,sha256=6BlBRxknj2-BFcGkx7oVcuL63_utSaY1Axmsc1qV9j8
9
9
  foamlib/_cases/_sync.py,sha256=2BJXB7Nzldb4OgPukqupgYqdceUGkI2mYhhtGPWEBrc,5901
10
10
  foamlib/_cases/_util.py,sha256=lhVca3ERY0zwYjDam6W2QMROt0yX5vAF-9_DS5RuMbM,1547
11
11
  foamlib/_files/__init__.py,sha256=GDkYkF3F-ADhkCRT3j9dQQHPP5LyJJYb8TaBbZTQ6fo,96
12
- foamlib/_files/_files.py,sha256=LVLMeP9Zt9esuVGhntnjBA4_u_NhiX5xkm09Qemcle8,15846
12
+ foamlib/_files/_files.py,sha256=_qzXSsKRVXNrfySewonJJqL9I4OA8RTZuYyuWTGR4Ys,15829
13
13
  foamlib/_files/_io.py,sha256=IQLqoqnA1TpHf21NbUho2wsYWevyqC6MKo-wfpaObUU,2226
14
- foamlib/_files/_parsing.py,sha256=D1l7j_KldD6h-iJvFT6c0CiwctWvUxeGJxh-J93zDs8,15430
15
- foamlib/_files/_serialization.py,sha256=0vqJxltjscqp16mIvd0iKXbeRMbq3a7uLG2INWxzCBg,5861
16
- foamlib/_files/_types.py,sha256=eY06nox8cZe6FixUQigvZRV9Fc7gwehJxuQz_wCCnqo,1678
17
- foamlib/_files/_util.py,sha256=O9t2W26XDs63cVLroW8rZ35Puas20NhnKr_gLMlZixI,493
18
- foamlib-0.7.2.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
19
- foamlib-0.7.2.dist-info/METADATA,sha256=dK_DN2ZLU49org-G_XI4kdNDg551I8b68d52Q4cAePU,7957
20
- foamlib-0.7.2.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
21
- foamlib-0.7.2.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
22
- foamlib-0.7.2.dist-info/RECORD,,
14
+ foamlib/_files/_parsing.py,sha256=sY_Cyep9R7HfeTOKnKoAh9ZVXTnrJw3HGIgFFwUPGms,12541
15
+ foamlib/_files/_serialization.py,sha256=GOhWIMHNf5MaLJUjbiRffNGQn1xVGPbyh_Mm50iz5e8,5847
16
+ foamlib/_files/_types.py,sha256=mOOTXVrrD6MZGH64TmK1KX7WfUVBS8JLOuHTeeDerDQ,1729
17
+ foamlib/_files/_util.py,sha256=lkoSJHXjd6MvDxx39ZF75mhPq-_QX9AjrruVcQ7I9WI,496
18
+ foamlib-0.7.3.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
19
+ foamlib-0.7.3.dist-info/METADATA,sha256=4yvR9-0fYVRRfbROkoO3HcmmtZVYI4QAqIC_NPqKE0A,7957
20
+ foamlib-0.7.3.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
21
+ foamlib-0.7.3.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
22
+ foamlib-0.7.3.dist-info/RECORD,,