foamlib 0.8.11__py3-none-any.whl → 0.9.1__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 +1 -1
- foamlib/_files/_parsing.py +206 -110
- foamlib/_files/_types.py +0 -34
- {foamlib-0.8.11.dist-info → foamlib-0.9.1.dist-info}/METADATA +1 -1
- {foamlib-0.8.11.dist-info → foamlib-0.9.1.dist-info}/RECORD +7 -7
- {foamlib-0.8.11.dist-info → foamlib-0.9.1.dist-info}/WHEEL +0 -0
- {foamlib-0.8.11.dist-info → foamlib-0.9.1.dist-info}/licenses/LICENSE.txt +0 -0
foamlib/__init__.py
CHANGED
foamlib/_files/_parsing.py
CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import re
|
4
4
|
import sys
|
5
|
-
from typing import Tuple, Union, cast
|
5
|
+
from typing import TYPE_CHECKING, Tuple, Union, cast
|
6
6
|
|
7
7
|
if sys.version_info >= (3, 9):
|
8
8
|
from collections.abc import Iterator, Mapping, MutableMapping, Sequence
|
@@ -25,6 +25,7 @@ from pyparsing import (
|
|
25
25
|
LineEnd,
|
26
26
|
Literal,
|
27
27
|
Located,
|
28
|
+
NoMatch,
|
28
29
|
Opt,
|
29
30
|
ParserElement,
|
30
31
|
ParseResults,
|
@@ -37,131 +38,172 @@ from pyparsing import (
|
|
37
38
|
printables,
|
38
39
|
)
|
39
40
|
|
40
|
-
from ._types import Data, Dimensioned, DimensionSet, File
|
41
|
+
from ._types import Data, Dimensioned, DimensionSet, File
|
41
42
|
|
43
|
+
if TYPE_CHECKING:
|
44
|
+
from numpy.typing import DTypeLike
|
42
45
|
|
43
|
-
def _tensor(tensor_kind: TensorKind, *, ignore: Regex | None = None) -> Regex:
|
44
|
-
float_pattern = r"(?i:[+-]?(?:(?:\d+\.?\d*(?:e[+-]?\d+)?)|nan|inf(?:inity)?))"
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
def _ascii_numeric_list(
|
48
|
+
dtype: DTypeLike,
|
49
|
+
*,
|
50
|
+
nested: int | None = None,
|
51
|
+
ignore: Regex | None = None,
|
52
|
+
empty_ok: bool = False,
|
53
|
+
) -> ParserElement:
|
54
|
+
dtype = np.dtype(dtype)
|
55
|
+
|
56
|
+
if np.issubdtype(dtype, np.floating):
|
57
|
+
element = common.ieee_float
|
58
|
+
element_pattern = r"(?i:[+-]?(?:(?:\d+\.?\d*(?:e[+-]?\d+)?)|nan|inf(?:inity)?))"
|
59
|
+
elif np.issubdtype(dtype, np.integer):
|
60
|
+
element = common.integer
|
61
|
+
element_pattern = r"(?:-?\d+)"
|
62
|
+
else:
|
63
|
+
msg = f"Unsupported dtype: {dtype}"
|
64
|
+
raise TypeError(msg)
|
52
65
|
|
53
|
-
|
54
|
-
rf"
|
66
|
+
spacing_pattern = (
|
67
|
+
rf"(?:(?:\s|{ignore.re.pattern})+)" if ignore is not None else r"(?:\s+)"
|
55
68
|
)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
else tks[0][1:-1],
|
61
|
-
sep=" ",
|
69
|
+
|
70
|
+
if nested is not None:
|
71
|
+
element = (
|
72
|
+
Literal("(").suppress() + Group(element[nested]) + Literal(")").suppress()
|
62
73
|
)
|
63
|
-
|
64
|
-
return ret
|
74
|
+
element_pattern = rf"(?:{spacing_pattern}?\({element_pattern}?(?:{element_pattern}{spacing_pattern}){{{nested - 1}}}{element_pattern}{spacing_pattern}?\))"
|
65
75
|
|
76
|
+
list_ = Forward()
|
66
77
|
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
78
|
+
def process_count(tks: ParseResults) -> None:
|
79
|
+
nonlocal list_
|
80
|
+
|
81
|
+
if not tks:
|
82
|
+
count = None
|
83
|
+
else:
|
84
|
+
(count,) = tks
|
85
|
+
assert isinstance(count, int)
|
86
|
+
|
87
|
+
if count is None:
|
88
|
+
if not empty_ok:
|
89
|
+
list_pattern = rf"\({spacing_pattern}?(?:{element_pattern}{spacing_pattern})*{element_pattern}{spacing_pattern}?\)"
|
90
|
+
else:
|
91
|
+
list_pattern = rf"\({spacing_pattern}?(?:{element_pattern}{spacing_pattern})*{element_pattern}?{spacing_pattern}?\)"
|
92
|
+
|
93
|
+
elif count == 0:
|
94
|
+
if not empty_ok:
|
95
|
+
list_ <<= NoMatch()
|
96
|
+
else:
|
97
|
+
list_ <<= (Literal("(") + Literal(")")).add_parse_action(
|
98
|
+
lambda: np.empty((0, nested) if nested else 0, dtype=dtype)
|
99
|
+
)
|
100
|
+
return
|
101
|
+
|
102
|
+
else:
|
103
|
+
list_pattern = rf"\({spacing_pattern}?(?:{element_pattern}{spacing_pattern}){{{count - 1}}}{element_pattern}{spacing_pattern}?\)"
|
104
|
+
|
105
|
+
list_ <<= Regex(list_pattern).add_parse_action(
|
106
|
+
lambda tks: to_array(tks, dtype=dtype)
|
79
107
|
)
|
80
|
-
| (
|
81
|
-
common.integer + Literal("{").suppress() + entry + Literal("}").suppress()
|
82
|
-
).set_parse_action(lambda tks: [[tks[1]] * tks[0]])
|
83
|
-
)
|
84
108
|
|
109
|
+
def to_array(
|
110
|
+
tks: ParseResults, *, dtype: DTypeLike
|
111
|
+
) -> np.ndarray[tuple[int] | tuple[int, int], np.dtype[np.integer | np.floating]]:
|
112
|
+
(s,) = tks
|
113
|
+
assert s.startswith("(")
|
114
|
+
assert s.endswith(")")
|
115
|
+
s = s[1:-1]
|
116
|
+
if ignore is not None:
|
117
|
+
s = re.sub(ignore.re, " ", s)
|
118
|
+
if nested is not None:
|
119
|
+
s = s.replace("(", " ").replace(")", " ")
|
120
|
+
|
121
|
+
ret: np.ndarray[
|
122
|
+
tuple[int] | tuple[int, int], np.dtype[np.integer | np.floating]
|
123
|
+
] = np.fromstring(s, sep=" ", dtype=dtype) # type: ignore[assignment]
|
124
|
+
|
125
|
+
if nested is not None:
|
126
|
+
ret = ret.reshape(-1, nested)
|
85
127
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
128
|
+
return ret
|
129
|
+
|
130
|
+
def to_full_array(
|
131
|
+
tks: ParseResults, *, dtype: type
|
132
|
+
) -> np.ndarray[tuple[int] | tuple[int, int], np.dtype[np.integer | np.floating]]:
|
133
|
+
count, lst = tks
|
134
|
+
assert isinstance(count, int)
|
92
135
|
|
93
|
-
|
136
|
+
if nested is None:
|
137
|
+
return np.full(count, lst, dtype=dtype)
|
94
138
|
|
139
|
+
return np.full((count, nested), lst, dtype=dtype) # type: ignore[return-value]
|
95
140
|
|
96
|
-
|
97
|
-
|
98
|
-
)
|
99
|
-
|
100
|
-
|
141
|
+
ret = ((Opt(common.integer).add_parse_action(process_count)).suppress() + list_) | (
|
142
|
+
common.integer + Literal("{").suppress() + element + Literal("}").suppress()
|
143
|
+
).add_parse_action(lambda tks: to_full_array(tks, dtype=float))
|
144
|
+
|
145
|
+
if ignore is not None:
|
146
|
+
ret.ignore(ignore)
|
101
147
|
|
102
|
-
|
103
|
-
return np.frombuffer(b, dtype=dtype).reshape(-1, *tensor_kind.shape) # type: ignore [return-value]
|
148
|
+
return ret
|
104
149
|
|
105
150
|
|
106
|
-
def
|
107
|
-
|
151
|
+
def _binary_numeric_list(
|
152
|
+
dtype: DTypeLike, *, nested: int | None = None, empty_ok: bool = False
|
108
153
|
) -> ParserElement:
|
109
|
-
|
110
|
-
ignore_pattern = rf"(?:\s|{ignore.re.pattern})+" if ignore is not None else r"\s+"
|
154
|
+
dtype = np.dtype(dtype)
|
111
155
|
|
112
|
-
|
156
|
+
elsize = nested if nested is not None else 1
|
113
157
|
|
114
|
-
list_
|
115
|
-
rf"\((?:{ignore_pattern})?(?:{tensor.re.pattern}{ignore_pattern})*{tensor.re.pattern}(?:{ignore_pattern})?\)"
|
116
|
-
).add_parse_action(
|
117
|
-
lambda tks: [_parse_ascii_field(tks[0], tensor_kind, ignore=ignore)]
|
118
|
-
) | (
|
119
|
-
(Literal("(") + Literal(")"))
|
120
|
-
.suppress()
|
121
|
-
.add_parse_action(lambda: np.array([]).reshape(0, *tensor_kind.shape))
|
122
|
-
)
|
158
|
+
list_ = Forward()
|
123
159
|
|
124
|
-
def
|
160
|
+
def process_count(tks: ParseResults) -> None:
|
125
161
|
nonlocal list_
|
126
|
-
|
127
|
-
assert isinstance(
|
128
|
-
|
129
|
-
if not
|
130
|
-
list_ <<= (
|
131
|
-
((Literal("(") + Literal(")")) | (Literal("{") + Literal("}")))
|
132
|
-
.suppress()
|
133
|
-
.add_parse_action(lambda: np.array([]).reshape(0, *tensor_kind.shape))
|
134
|
-
)
|
162
|
+
(size,) = tks
|
163
|
+
assert isinstance(size, int)
|
164
|
+
|
165
|
+
if size == 0 and not empty_ok:
|
166
|
+
list_ <<= NoMatch()
|
135
167
|
return
|
136
168
|
|
137
|
-
list_ <<= (
|
138
|
-
Regex(
|
139
|
-
rf"\((?:{ignore_pattern})?(?:{tensor.re.pattern}{ignore_pattern}){{{length - 1}}}{tensor.re.pattern}(?:{ignore_pattern})?\)"
|
140
|
-
).add_parse_action(
|
141
|
-
lambda tks: [_parse_ascii_field(tks[0], tensor_kind, ignore=ignore)]
|
142
|
-
)
|
143
|
-
| Regex(
|
144
|
-
rf"\((?s:({'.' * 8 * tensor_kind.size}|{'.' * 4 * tensor_kind.size}){{{length}}})\)"
|
145
|
-
).add_parse_action(
|
146
|
-
lambda tks: [
|
147
|
-
_unpack_binary_field(
|
148
|
-
tks[0][1:-1].encode("latin-1"), tensor_kind, length=length
|
149
|
-
)
|
150
|
-
]
|
151
|
-
)
|
152
|
-
| (
|
153
|
-
Literal("{").suppress() + tensor + Literal("}").suppress()
|
154
|
-
).add_parse_action(
|
155
|
-
lambda tks: [np.full((length, *tensor_kind.shape), tks[0], dtype=float)]
|
156
|
-
)
|
157
|
-
)
|
169
|
+
list_ <<= Regex(rf"\((?s:{'.' * dtype.itemsize * elsize}){{{size}}}\)")
|
158
170
|
|
159
|
-
|
171
|
+
def to_array(
|
172
|
+
tks: ParseResults,
|
173
|
+
) -> np.ndarray[tuple[int] | tuple[int, int], np.dtype[np.integer | np.floating]]:
|
174
|
+
size, s = tks
|
175
|
+
assert isinstance(size, int)
|
176
|
+
assert isinstance(s, str)
|
177
|
+
assert s[0] == "("
|
178
|
+
assert s[-1] == ")"
|
179
|
+
s = s[1:-1]
|
180
|
+
|
181
|
+
ret = np.frombuffer(s.encode("latin-1"), dtype=dtype)
|
182
|
+
|
183
|
+
if nested is not None:
|
184
|
+
ret = ret.reshape(-1, nested)
|
185
|
+
|
186
|
+
return ret # type: ignore[return-value]
|
160
187
|
|
161
188
|
return (
|
162
|
-
|
163
|
-
|
164
|
-
|
189
|
+
common.integer.copy().add_parse_action(process_count) + list_
|
190
|
+
).add_parse_action(to_array)
|
191
|
+
|
192
|
+
|
193
|
+
def _list_of(entry: ParserElement) -> ParserElement:
|
194
|
+
return (
|
195
|
+
(
|
196
|
+
counted_array(entry, common.integer + Literal("(").suppress())
|
197
|
+
+ Literal(")").suppress()
|
198
|
+
).set_parse_action(lambda tks: [tks.as_list()])
|
199
|
+
| (
|
200
|
+
Literal("(").suppress()
|
201
|
+
+ Group((entry)[...], aslist=True)
|
202
|
+
+ Literal(")").suppress()
|
203
|
+
)
|
204
|
+
| (
|
205
|
+
common.integer + Literal("{").suppress() + entry + Literal("}").suppress()
|
206
|
+
).set_parse_action(lambda tks: [[tks[1]] * tks[0]])
|
165
207
|
)
|
166
208
|
|
167
209
|
|
@@ -250,12 +292,11 @@ _SWITCH = (
|
|
250
292
|
_DIMENSIONS = (
|
251
293
|
Literal("[").suppress() + common.number[0, 7] + Literal("]").suppress()
|
252
294
|
).set_parse_action(lambda tks: DimensionSet(*tks))
|
253
|
-
_TENSOR = (
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
)
|
295
|
+
_TENSOR = common.ieee_float | (
|
296
|
+
Literal("(").suppress()
|
297
|
+
+ Group(common.ieee_float[3] | common.ieee_float[6] | common.ieee_float[9])
|
298
|
+
+ Literal(")").suppress()
|
299
|
+
).add_parse_action(lambda tks: np.array(tks[0], dtype=float))
|
259
300
|
_PARENTHESIZED = Forward()
|
260
301
|
_IDENTIFIER = Combine(Word(_IDENTCHARS, _IDENTBODYCHARS) + Opt(_PARENTHESIZED))
|
261
302
|
_PARENTHESIZED <<= Combine(
|
@@ -270,12 +311,55 @@ _DIMENSIONED = (Opt(_IDENTIFIER) + _DIMENSIONS + _TENSOR).set_parse_action(
|
|
270
311
|
_FIELD = (Keyword("uniform", _IDENTBODYCHARS).suppress() + _TENSOR) | (
|
271
312
|
Keyword("nonuniform", _IDENTBODYCHARS).suppress()
|
272
313
|
+ (
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
314
|
+
(
|
315
|
+
Opt(
|
316
|
+
Literal("List") + Literal("<") + Literal("scalar") + Literal(">")
|
317
|
+
).suppress()
|
318
|
+
+ (
|
319
|
+
_ascii_numeric_list(dtype=float, ignore=_COMMENT, empty_ok=True)
|
320
|
+
| _binary_numeric_list(dtype=np.float64, empty_ok=True)
|
321
|
+
| _binary_numeric_list(dtype=np.float32, empty_ok=True)
|
322
|
+
)
|
323
|
+
)
|
324
|
+
| (
|
325
|
+
Opt(
|
326
|
+
Literal("List") + Literal("<") + Literal("vector") + Literal(">")
|
327
|
+
).suppress()
|
328
|
+
+ (
|
329
|
+
_ascii_numeric_list(
|
330
|
+
dtype=float, nested=3, ignore=_COMMENT, empty_ok=True
|
331
|
+
)
|
332
|
+
| _binary_numeric_list(np.float64, nested=3, empty_ok=True)
|
333
|
+
| _binary_numeric_list(np.float32, nested=3, empty_ok=True)
|
334
|
+
)
|
335
|
+
)
|
336
|
+
| (
|
337
|
+
Opt(
|
338
|
+
Literal("List") + Literal("<") + Literal("symmTensor") + Literal(">")
|
339
|
+
).suppress()
|
340
|
+
+ (
|
341
|
+
_ascii_numeric_list(
|
342
|
+
dtype=float, nested=6, ignore=_COMMENT, empty_ok=True
|
343
|
+
)
|
344
|
+
| _binary_numeric_list(np.float64, nested=6, empty_ok=True)
|
345
|
+
| _binary_numeric_list(np.float32, nested=6, empty_ok=True)
|
346
|
+
)
|
347
|
+
)
|
348
|
+
| (
|
349
|
+
Opt(
|
350
|
+
Literal("List") + Literal("<") + Literal("tensor") + Literal(">")
|
351
|
+
).suppress()
|
352
|
+
+ (
|
353
|
+
_ascii_numeric_list(
|
354
|
+
dtype=float, nested=9, ignore=_COMMENT, empty_ok=True
|
355
|
+
)
|
356
|
+
| _binary_numeric_list(np.float64, nested=9, empty_ok=True)
|
357
|
+
| _binary_numeric_list(np.float32, nested=9, empty_ok=True)
|
358
|
+
)
|
359
|
+
)
|
277
360
|
)
|
278
361
|
)
|
362
|
+
|
279
363
|
_DIRECTIVE = Word("#", _IDENTBODYCHARS)
|
280
364
|
_TOKEN = dbl_quoted_string | _DIRECTIVE | _IDENTIFIER
|
281
365
|
_DATA = Forward()
|
@@ -319,7 +403,19 @@ _LOCATED_DICTIONARY = Group(
|
|
319
403
|
located=True,
|
320
404
|
)
|
321
405
|
)[...]
|
322
|
-
_LOCATED_DATA = Group(
|
406
|
+
_LOCATED_DATA = Group(
|
407
|
+
Located(
|
408
|
+
(
|
409
|
+
_ascii_numeric_list(dtype=int, ignore=_COMMENT)
|
410
|
+
| _binary_numeric_list(dtype=np.int64)
|
411
|
+
| _binary_numeric_list(dtype=np.int32)
|
412
|
+
| _ascii_numeric_list(dtype=float, nested=3, ignore=_COMMENT)
|
413
|
+
| _binary_numeric_list(dtype=np.float64, nested=3)
|
414
|
+
| _binary_numeric_list(dtype=np.float32, nested=3)
|
415
|
+
| _DATA
|
416
|
+
).add_parse_action(lambda tks: ["", tks[0]])
|
417
|
+
)
|
418
|
+
)
|
323
419
|
|
324
420
|
_FILE = (
|
325
421
|
Dict(_LOCATED_DICTIONARY + Opt(_LOCATED_DATA) + _LOCATED_DICTIONARY)
|
foamlib/_files/_types.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import sys
|
4
|
-
from enum import Enum
|
5
4
|
from typing import Dict, NamedTuple, Optional, Union
|
6
5
|
|
7
6
|
import numpy as np
|
@@ -42,39 +41,6 @@ TensorLike = Union[
|
|
42
41
|
]
|
43
42
|
|
44
43
|
|
45
|
-
class TensorKind(Enum):
|
46
|
-
SCALAR = ()
|
47
|
-
VECTOR = (3,)
|
48
|
-
SYMM_TENSOR = (6,)
|
49
|
-
TENSOR = (9,)
|
50
|
-
|
51
|
-
@property
|
52
|
-
def shape(self) -> tuple[()] | tuple[int]:
|
53
|
-
shape: tuple[()] | tuple[int] = self.value
|
54
|
-
return shape
|
55
|
-
|
56
|
-
@property
|
57
|
-
def size(self) -> int:
|
58
|
-
return int(np.prod(self.shape))
|
59
|
-
|
60
|
-
def __str__(self) -> str:
|
61
|
-
return {
|
62
|
-
TensorKind.SCALAR: "scalar",
|
63
|
-
TensorKind.VECTOR: "vector",
|
64
|
-
TensorKind.SYMM_TENSOR: "symmTensor",
|
65
|
-
TensorKind.TENSOR: "tensor",
|
66
|
-
}[self]
|
67
|
-
|
68
|
-
@staticmethod
|
69
|
-
def from_shape(shape: tuple[int, ...]) -> TensorKind:
|
70
|
-
for kind in TensorKind:
|
71
|
-
if kind.shape == shape:
|
72
|
-
return kind
|
73
|
-
|
74
|
-
msg = f"No tensor kind for shape {shape!r}"
|
75
|
-
raise ValueError(msg)
|
76
|
-
|
77
|
-
|
78
44
|
class Dimensioned:
|
79
45
|
def __init__(
|
80
46
|
self,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
foamlib/__init__.py,sha256=
|
1
|
+
foamlib/__init__.py,sha256=0HqaL6QRggvb5wLBXgC3aMmHL7gltD8K2njaeYZJezI,452
|
2
2
|
foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
foamlib/_cases/__init__.py,sha256=_A1TTHuQfS9FH2_33lSEyLtOJZGFHZBco1tWJCVOHks,358
|
4
4
|
foamlib/_cases/_async.py,sha256=e4lGTcQBbFGwfG6SmJks5aa5LWd_0dy01kgKZWAgTGQ,11655
|
@@ -11,10 +11,10 @@ foamlib/_cases/_util.py,sha256=QCizfbuJdOCeF9ogU2R-y-iWX5kfaOA4U2W68t6QlOM,2544
|
|
11
11
|
foamlib/_files/__init__.py,sha256=q1vkjXnjnSZvo45jPAICpWeF2LZv5V6xfzAR6S8fS5A,96
|
12
12
|
foamlib/_files/_files.py,sha256=gSJQjvB1f7N2yJtCTx9kpivKqSSNjDj37qNMpned5CM,19505
|
13
13
|
foamlib/_files/_io.py,sha256=BGbbm6HKxL2ka0YMCmHqZQZ1R4PPQlkvWWb4FHMAS8k,2217
|
14
|
-
foamlib/_files/_parsing.py,sha256=
|
14
|
+
foamlib/_files/_parsing.py,sha256=Nhktc7RnF7QIydUFm1umgQKiIW0s8GoPmagWRqfvaLQ,17404
|
15
15
|
foamlib/_files/_serialization.py,sha256=QJ-F6BKizVe0gpjnpIfPxNGTqWwalY4PQtCKdDY9D70,5502
|
16
|
-
foamlib/_files/_types.py,sha256=
|
17
|
-
foamlib-0.
|
18
|
-
foamlib-0.
|
19
|
-
foamlib-0.
|
20
|
-
foamlib-0.
|
16
|
+
foamlib/_files/_types.py,sha256=q5O_x680XhGfvPHCNF_3objK1imUG2kgQYNRF2Z4qJ0,2918
|
17
|
+
foamlib-0.9.1.dist-info/METADATA,sha256=ZSdTaK1ejV7YBHJVoQX384eudRHxTIxfjRiK7kH0Bxk,12906
|
18
|
+
foamlib-0.9.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
19
|
+
foamlib-0.9.1.dist-info/licenses/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
|
20
|
+
foamlib-0.9.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|