shepherd-data 2025.2.1__tar.gz → 2025.4.1__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.
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/PKG-INFO +3 -3
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/pyproject.toml +2 -1
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data/__init__.py +1 -1
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data/cli.py +65 -22
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data/mppt.py +5 -1
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data/reader.py +18 -14
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data.egg-info/PKG-INFO +3 -3
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data.egg-info/requires.txt +1 -1
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/README.md +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/setup.cfg +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data/ivonne.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data.egg-info/SOURCES.txt +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data.egg-info/dependency_links.txt +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data.egg-info/entry_points.txt +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data.egg-info/top_level.txt +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data.egg-info/zip-safe +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_cli.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_cli_downsample.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_cli_extract.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_cli_extract_gpio.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_cli_extract_meta.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_cli_extract_uart.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_cli_plot.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_cli_validate.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_cli_version.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_examples.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_ivonne.py +0 -0
- {shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/tests/test_reader.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: shepherd_data
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.4.1
|
|
4
4
|
Summary: Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed
|
|
5
5
|
Author-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
6
6
|
Maintainer-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
@@ -36,7 +36,7 @@ Requires-Dist: numpy
|
|
|
36
36
|
Requires-Dist: pandas>=2.0.0
|
|
37
37
|
Requires-Dist: pyYAML
|
|
38
38
|
Requires-Dist: scipy
|
|
39
|
-
Requires-Dist: shepherd-core[inventory]>=2025.
|
|
39
|
+
Requires-Dist: shepherd-core[inventory]>=2025.04.1
|
|
40
40
|
Requires-Dist: tqdm
|
|
41
41
|
Provides-Extra: elf
|
|
42
42
|
Requires-Dist: shepherd-core[elf]; extra == "elf"
|
|
@@ -38,7 +38,7 @@ dependencies = [
|
|
|
38
38
|
"pandas>=2.0.0", # full-version, v2 is OK
|
|
39
39
|
"pyYAML",
|
|
40
40
|
"scipy", # full-version
|
|
41
|
-
"shepherd-core[inventory]>=2025.
|
|
41
|
+
"shepherd-core[inventory]>=2025.04.1", # libs are strongly coupled
|
|
42
42
|
"tqdm", # full-version
|
|
43
43
|
]
|
|
44
44
|
|
|
@@ -103,3 +103,4 @@ source = ["shepherd_data"]
|
|
|
103
103
|
[tool.mypy]
|
|
104
104
|
python_version = 3.8
|
|
105
105
|
ignore_missing_imports = true
|
|
106
|
+
disable_error_code = ["call-arg", ]
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Command definitions for CLI."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
import os
|
|
5
4
|
import sys
|
|
6
5
|
from contextlib import suppress
|
|
7
6
|
from datetime import datetime
|
|
@@ -22,7 +21,7 @@ from .reader import Reader
|
|
|
22
21
|
logger = logging.getLogger("SHPData.cli")
|
|
23
22
|
|
|
24
23
|
|
|
25
|
-
def path_to_flist(data_path: Path) -> List[Path]:
|
|
24
|
+
def path_to_flist(data_path: Path, *, recurse: bool = False) -> List[Path]:
|
|
26
25
|
"""Every path gets transformed to a list of paths.
|
|
27
26
|
|
|
28
27
|
Transformations:
|
|
@@ -31,16 +30,14 @@ def path_to_flist(data_path: Path) -> List[Path]:
|
|
|
31
30
|
- or else: empty list
|
|
32
31
|
"""
|
|
33
32
|
data_path = Path(data_path).resolve()
|
|
34
|
-
h5files = []
|
|
33
|
+
h5files: list = []
|
|
35
34
|
if data_path.is_file() and data_path.suffix.lower() == ".h5":
|
|
36
35
|
h5files.append(data_path)
|
|
37
36
|
elif data_path.is_dir():
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
continue
|
|
43
|
-
h5files.append(fpath)
|
|
37
|
+
files = data_path.glob(
|
|
38
|
+
"**/*.h5" if recurse else "*.h5"
|
|
39
|
+
) # for py>=3.12: case_sensitive=False
|
|
40
|
+
h5files = [file for file in files if file.is_file()]
|
|
44
41
|
return h5files
|
|
45
42
|
|
|
46
43
|
|
|
@@ -70,9 +67,15 @@ def version() -> None:
|
|
|
70
67
|
|
|
71
68
|
@cli.command(short_help="Validates a file or directory containing shepherd-recordings")
|
|
72
69
|
@click.argument("in_data", type=click.Path(exists=True, resolve_path=True))
|
|
73
|
-
|
|
70
|
+
@click.option(
|
|
71
|
+
"--recurse",
|
|
72
|
+
"-a",
|
|
73
|
+
is_flag=True,
|
|
74
|
+
help="Also consider files in sub-folders",
|
|
75
|
+
)
|
|
76
|
+
def validate(in_data: Path, *, recurse: bool = False) -> None:
|
|
74
77
|
"""Validate a file or directory containing shepherd-recordings."""
|
|
75
|
-
files = path_to_flist(in_data)
|
|
78
|
+
files = path_to_flist(in_data, recurse=recurse)
|
|
76
79
|
verbose_level = get_verbose_level() # TODO: should be stored and passed in ctx
|
|
77
80
|
valid_dir = True
|
|
78
81
|
for file in files:
|
|
@@ -123,7 +126,13 @@ def validate(in_data: Path) -> None:
|
|
|
123
126
|
"--raw",
|
|
124
127
|
"-r",
|
|
125
128
|
is_flag=True,
|
|
126
|
-
help="
|
|
129
|
+
help="Don't convert data to si-units",
|
|
130
|
+
)
|
|
131
|
+
@click.option(
|
|
132
|
+
"--recurse",
|
|
133
|
+
"-a",
|
|
134
|
+
is_flag=True,
|
|
135
|
+
help="Also consider files in sub-folders",
|
|
127
136
|
)
|
|
128
137
|
def extract(
|
|
129
138
|
in_data: Path,
|
|
@@ -133,9 +142,10 @@ def extract(
|
|
|
133
142
|
separator: str,
|
|
134
143
|
*,
|
|
135
144
|
raw: bool = False,
|
|
145
|
+
recurse: bool = False,
|
|
136
146
|
) -> None:
|
|
137
147
|
"""Extract recorded IVSamples and store them to csv."""
|
|
138
|
-
files = path_to_flist(in_data)
|
|
148
|
+
files = path_to_flist(in_data, recurse=recurse)
|
|
139
149
|
verbose_level = get_verbose_level()
|
|
140
150
|
if not isinstance(ds_factor, (float, int)) or ds_factor < 1:
|
|
141
151
|
ds_factor = 1000
|
|
@@ -162,10 +172,15 @@ def extract(
|
|
|
162
172
|
type=click.STRING,
|
|
163
173
|
help="Set an individual csv-separator",
|
|
164
174
|
)
|
|
165
|
-
|
|
166
|
-
|
|
175
|
+
@click.option(
|
|
176
|
+
"--recurse",
|
|
177
|
+
"-a",
|
|
178
|
+
is_flag=True,
|
|
179
|
+
help="Also consider files in sub-folders",
|
|
180
|
+
)
|
|
181
|
+
def extract_meta(in_data: Path, separator: str, *, recurse: bool = False) -> None:
|
|
167
182
|
"""Extract metadata and logs from file or directory containing shepherd-recordings."""
|
|
168
|
-
files = path_to_flist(in_data)
|
|
183
|
+
files = path_to_flist(in_data, recurse=recurse)
|
|
169
184
|
verbose_level = get_verbose_level()
|
|
170
185
|
for file in files:
|
|
171
186
|
logger.info("Extracting metadata & logs from '%s' ...", file.name)
|
|
@@ -195,9 +210,15 @@ def extract_meta(in_data: Path, separator: str) -> None:
|
|
|
195
210
|
short_help="Extracts uart from gpio-trace in file or directory containing shepherd-recordings"
|
|
196
211
|
)
|
|
197
212
|
@click.argument("in_data", type=click.Path(exists=True, resolve_path=True))
|
|
198
|
-
|
|
213
|
+
@click.option(
|
|
214
|
+
"--recurse",
|
|
215
|
+
"-a",
|
|
216
|
+
is_flag=True,
|
|
217
|
+
help="Also consider files in sub-folders",
|
|
218
|
+
)
|
|
219
|
+
def extract_uart(in_data: Path, *, recurse: bool = False) -> None:
|
|
199
220
|
"""Extract UART from GPIO-trace in file or directory containing shepherd-recordings."""
|
|
200
|
-
files = path_to_flist(in_data)
|
|
221
|
+
files = path_to_flist(in_data, recurse=recurse)
|
|
201
222
|
verbose_level = get_verbose_level()
|
|
202
223
|
for file in files:
|
|
203
224
|
logger.info("Extracting uart from gpio-trace from from '%s' ...", file.name)
|
|
@@ -220,6 +241,7 @@ def extract_uart(in_data: Path) -> None:
|
|
|
220
241
|
log_file.write(timestamp.strftime("%Y-%m-%d %H:%M:%S.%f") + ":")
|
|
221
242
|
# TODO: allow to skip Timestamp and export raw text
|
|
222
243
|
log_file.write(f"\t{str.encode(line[1])}")
|
|
244
|
+
# TODO: does this produce "\tb'abc'"?
|
|
223
245
|
log_file.write("\n")
|
|
224
246
|
except TypeError:
|
|
225
247
|
logger.exception("ERROR: Will skip file. It caused an exception.")
|
|
@@ -233,10 +255,16 @@ def extract_uart(in_data: Path) -> None:
|
|
|
233
255
|
default=";",
|
|
234
256
|
type=click.STRING,
|
|
235
257
|
help="Set an individual csv-separator",
|
|
258
|
+
) # TODO: also configure decimal point
|
|
259
|
+
@click.option(
|
|
260
|
+
"--recurse",
|
|
261
|
+
"-a",
|
|
262
|
+
is_flag=True,
|
|
263
|
+
help="Also consider files in sub-folders",
|
|
236
264
|
)
|
|
237
|
-
def extract_gpio(in_data: Path, separator: str) -> None:
|
|
265
|
+
def extract_gpio(in_data: Path, separator: str, *, recurse: bool = False) -> None:
|
|
238
266
|
"""Extract UART from gpio-trace in file or directory containing shepherd-recordings."""
|
|
239
|
-
files = path_to_flist(in_data)
|
|
267
|
+
files = path_to_flist(in_data, recurse=recurse)
|
|
240
268
|
verbose_level = get_verbose_level()
|
|
241
269
|
for file in files:
|
|
242
270
|
logger.info("Extracting gpio-trace from from '%s' ...", file.name)
|
|
@@ -281,15 +309,23 @@ def extract_gpio(in_data: Path, separator: str) -> None:
|
|
|
281
309
|
type=click.FLOAT,
|
|
282
310
|
help="End-point in seconds, will be max if omitted",
|
|
283
311
|
)
|
|
312
|
+
@click.option(
|
|
313
|
+
"--recurse",
|
|
314
|
+
"-a",
|
|
315
|
+
is_flag=True,
|
|
316
|
+
help="Also consider files in sub-folders",
|
|
317
|
+
)
|
|
284
318
|
def downsample(
|
|
285
319
|
in_data: Path,
|
|
286
320
|
ds_factor: Optional[float],
|
|
287
321
|
sample_rate: Optional[int],
|
|
288
322
|
start: Optional[float],
|
|
289
323
|
end: Optional[float],
|
|
324
|
+
*,
|
|
325
|
+
recurse: bool = False,
|
|
290
326
|
) -> None:
|
|
291
327
|
"""Create an array of down-sampled files from file or dir containing shepherd-recordings."""
|
|
292
|
-
files = path_to_flist(in_data)
|
|
328
|
+
files = path_to_flist(in_data, recurse=recurse)
|
|
293
329
|
verbose_level = get_verbose_level()
|
|
294
330
|
for file in files:
|
|
295
331
|
try:
|
|
@@ -351,6 +387,12 @@ def downsample(
|
|
|
351
387
|
is_flag=True,
|
|
352
388
|
help="Plot only power instead of voltage, current & power",
|
|
353
389
|
)
|
|
390
|
+
@click.option(
|
|
391
|
+
"--recurse",
|
|
392
|
+
"-a",
|
|
393
|
+
is_flag=True,
|
|
394
|
+
help="Also consider files in sub-folders",
|
|
395
|
+
)
|
|
354
396
|
def plot(
|
|
355
397
|
in_data: Path,
|
|
356
398
|
start: Optional[float],
|
|
@@ -360,9 +402,10 @@ def plot(
|
|
|
360
402
|
*,
|
|
361
403
|
multiplot: bool,
|
|
362
404
|
only_power: bool,
|
|
405
|
+
recurse: bool = False,
|
|
363
406
|
) -> None:
|
|
364
407
|
"""Plot IV-trace from file or directory containing shepherd-recordings."""
|
|
365
|
-
files = path_to_flist(in_data)
|
|
408
|
+
files = path_to_flist(in_data, recurse=recurse)
|
|
366
409
|
verbose_level = get_verbose_level()
|
|
367
410
|
multiplot = multiplot and len(files) > 1
|
|
368
411
|
data = []
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
Might be exchanged by shepherds py-model of pru-harvesters.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from abc import ABC
|
|
7
|
+
from abc import abstractmethod
|
|
8
|
+
|
|
6
9
|
import numpy as np
|
|
7
10
|
import pandas as pd
|
|
8
11
|
|
|
@@ -36,7 +39,7 @@ def find_oc(v_arr: np.ndarray, i_arr: np.ndarray, ratio: float = 0.05) -> np.nda
|
|
|
36
39
|
return v_arr[np.argmax(i_arr < i_arr[0] * ratio)]
|
|
37
40
|
|
|
38
41
|
|
|
39
|
-
class MPPTracker:
|
|
42
|
+
class MPPTracker(ABC):
|
|
40
43
|
"""Prototype for a MPPT-class.
|
|
41
44
|
|
|
42
45
|
:param v_max: Maximum voltage supported by shepherd
|
|
@@ -48,6 +51,7 @@ class MPPTracker:
|
|
|
48
51
|
self.v_max: float = v_max
|
|
49
52
|
self.v_proto: np.ndarray = np.linspace(0, v_max, pts_per_curve)
|
|
50
53
|
|
|
54
|
+
@abstractmethod
|
|
51
55
|
def process(self, coeffs: pd.DataFrame) -> pd.DataFrame:
|
|
52
56
|
"""Apply harvesting model to input data.
|
|
53
57
|
|
|
@@ -4,7 +4,10 @@ import math
|
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Dict
|
|
7
|
+
from typing import List
|
|
8
|
+
from typing import Mapping
|
|
7
9
|
from typing import Optional
|
|
10
|
+
from typing import Sequence
|
|
8
11
|
from typing import Union
|
|
9
12
|
|
|
10
13
|
import h5py
|
|
@@ -56,21 +59,25 @@ class Reader(CoreReader):
|
|
|
56
59
|
if csv_path.exists():
|
|
57
60
|
self._logger.info("File already exists, will skip '%s'", csv_path.name)
|
|
58
61
|
return 0
|
|
59
|
-
datasets
|
|
62
|
+
datasets: List[str] = [
|
|
63
|
+
str(key) for key in h5_group if isinstance(h5_group[key], h5py.Dataset)
|
|
64
|
+
]
|
|
60
65
|
datasets.remove("time")
|
|
61
66
|
datasets = ["time", *datasets]
|
|
62
67
|
separator = separator.strip().ljust(2)
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
header_elements: List[str] = [
|
|
69
|
+
str(h5_group[key].attrs["description"]).replace(", ", separator) for key in datasets
|
|
70
|
+
]
|
|
71
|
+
header: str = separator.join(header_elements)
|
|
65
72
|
with csv_path.open("w", encoding="utf-8-sig") as csv_file:
|
|
66
73
|
self._logger.info("CSV-Generator will save '%s' to '%s'", h5_group.name, csv_path.name)
|
|
67
74
|
csv_file.write(header + "\n")
|
|
68
75
|
ts_gain = h5_group["time"].attrs.get("gain", 1e-9)
|
|
69
76
|
# for converting data to si - if raw=false
|
|
70
|
-
gains:
|
|
77
|
+
gains: Dict[str, float] = {
|
|
71
78
|
key: h5_group[key].attrs.get("gain", 1.0) for key in datasets[1:]
|
|
72
79
|
}
|
|
73
|
-
offsets:
|
|
80
|
+
offsets: Dict[str, float] = {
|
|
74
81
|
key: h5_group[key].attrs.get("offset", 1.0) for key in datasets[1:]
|
|
75
82
|
}
|
|
76
83
|
for idx, time_ns in enumerate(h5_group["time"][:]):
|
|
@@ -222,7 +229,7 @@ class Reader(CoreReader):
|
|
|
222
229
|
for _iter in trange(
|
|
223
230
|
0,
|
|
224
231
|
iterations,
|
|
225
|
-
desc=f"downsampling {data_src.name}",
|
|
232
|
+
desc=f"downsampling {data_src.name if isinstance(data_src, h5py.Dataset) else ''}",
|
|
226
233
|
leave=False,
|
|
227
234
|
disable=iterations < 8,
|
|
228
235
|
):
|
|
@@ -242,7 +249,7 @@ class Reader(CoreReader):
|
|
|
242
249
|
self,
|
|
243
250
|
start_s: Optional[float],
|
|
244
251
|
end_s: Optional[float],
|
|
245
|
-
ds_factor:
|
|
252
|
+
ds_factor: float,
|
|
246
253
|
) -> Path:
|
|
247
254
|
"""Cut source to given limits, downsample by factor and store result in separate file.
|
|
248
255
|
|
|
@@ -290,10 +297,7 @@ class Reader(CoreReader):
|
|
|
290
297
|
else:
|
|
291
298
|
cut_str = ""
|
|
292
299
|
|
|
293
|
-
if ds_factor > 1
|
|
294
|
-
ds_str = f".downsample_x{round(ds_factor)}"
|
|
295
|
-
else:
|
|
296
|
-
ds_str = ""
|
|
300
|
+
ds_str = f".downsample_x{round(ds_factor)}" if ds_factor > 1 else ""
|
|
297
301
|
|
|
298
302
|
dst_file = self.file_path.resolve().with_suffix(cut_str + ds_str + ".h5")
|
|
299
303
|
if dst_file.exists():
|
|
@@ -403,7 +407,7 @@ class Reader(CoreReader):
|
|
|
403
407
|
for _ in trange(
|
|
404
408
|
0,
|
|
405
409
|
iterations,
|
|
406
|
-
desc=f"resampling {data_src.name}",
|
|
410
|
+
desc=f"resampling {data_src.name if isinstance(data_src, h5py.Dataset) else ''}",
|
|
407
411
|
leave=False,
|
|
408
412
|
disable=iterations < 8,
|
|
409
413
|
):
|
|
@@ -506,7 +510,7 @@ class Reader(CoreReader):
|
|
|
506
510
|
|
|
507
511
|
@staticmethod
|
|
508
512
|
def assemble_plot(
|
|
509
|
-
data: Union[
|
|
513
|
+
data: Union[Mapping, Sequence], width: int = 20, height: int = 10, *, only_pwr: bool = False
|
|
510
514
|
) -> plt.Figure:
|
|
511
515
|
"""Create the actual figure.
|
|
512
516
|
|
|
@@ -520,7 +524,7 @@ class Reader(CoreReader):
|
|
|
520
524
|
:return: figure
|
|
521
525
|
"""
|
|
522
526
|
# TODO: allow choosing freely from I, V, P, GPIO
|
|
523
|
-
if isinstance(data,
|
|
527
|
+
if isinstance(data, Mapping):
|
|
524
528
|
data = [data]
|
|
525
529
|
if only_pwr:
|
|
526
530
|
fig, ax = plt.subplots(1, 1, figsize=(width, height), layout="tight")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: shepherd_data
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.4.1
|
|
4
4
|
Summary: Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed
|
|
5
5
|
Author-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
6
6
|
Maintainer-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
@@ -36,7 +36,7 @@ Requires-Dist: numpy
|
|
|
36
36
|
Requires-Dist: pandas>=2.0.0
|
|
37
37
|
Requires-Dist: pyYAML
|
|
38
38
|
Requires-Dist: scipy
|
|
39
|
-
Requires-Dist: shepherd-core[inventory]>=2025.
|
|
39
|
+
Requires-Dist: shepherd-core[inventory]>=2025.04.1
|
|
40
40
|
Requires-Dist: tqdm
|
|
41
41
|
Provides-Extra: elf
|
|
42
42
|
Requires-Dist: shepherd-core[elf]; extra == "elf"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{shepherd_data-2025.2.1 → shepherd_data-2025.4.1}/shepherd_data.egg-info/dependency_links.txt
RENAMED
|
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
|