shepherd-core 2025.6.3__py3-none-any.whl → 2025.8.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.
- shepherd_core/data_models/base/cal_measurement.py +4 -5
- shepherd_core/data_models/base/calibration.py +8 -10
- shepherd_core/data_models/base/content.py +2 -3
- shepherd_core/data_models/base/shepherd.py +6 -8
- shepherd_core/data_models/base/wrapper.py +3 -4
- shepherd_core/data_models/content/energy_environment.py +4 -5
- shepherd_core/data_models/content/firmware.py +3 -5
- shepherd_core/data_models/content/virtual_harvester.py +5 -6
- shepherd_core/data_models/experiment/experiment.py +9 -17
- shepherd_core/data_models/experiment/observer_features.py +22 -38
- shepherd_core/data_models/experiment/target_config.py +10 -11
- shepherd_core/data_models/task/__init__.py +1 -3
- shepherd_core/data_models/task/emulation.py +18 -19
- shepherd_core/data_models/task/firmware_mod.py +3 -4
- shepherd_core/data_models/task/harvest.py +7 -10
- shepherd_core/data_models/task/observer_tasks.py +12 -10
- shepherd_core/data_models/task/programming.py +2 -2
- shepherd_core/data_models/task/testbed_tasks.py +8 -10
- shepherd_core/data_models/testbed/cape.py +3 -5
- shepherd_core/data_models/testbed/gpio.py +7 -8
- shepherd_core/data_models/testbed/mcu.py +1 -2
- shepherd_core/data_models/testbed/observer.py +5 -6
- shepherd_core/data_models/testbed/target.py +4 -6
- shepherd_core/data_models/testbed/testbed.py +2 -3
- shepherd_core/decoder_waveform/uart.py +12 -13
- shepherd_core/fw_tools/converter.py +1 -2
- shepherd_core/fw_tools/converter_elf.py +1 -2
- shepherd_core/fw_tools/patcher.py +65 -40
- shepherd_core/fw_tools/validation.py +7 -1
- shepherd_core/inventory/python.py +8 -9
- shepherd_core/inventory/system.py +1 -2
- shepherd_core/inventory/target.py +1 -2
- shepherd_core/logger.py +1 -2
- shepherd_core/reader.py +18 -23
- shepherd_core/testbed_client/client_abc_fix.py +2 -7
- shepherd_core/testbed_client/client_web.py +5 -9
- shepherd_core/testbed_client/fixtures.py +3 -5
- shepherd_core/testbed_client/user_model.py +4 -5
- shepherd_core/version.py +1 -1
- shepherd_core/vsource/virtual_converter_model.py +1 -2
- shepherd_core/vsource/virtual_harvester_simulation.py +1 -2
- shepherd_core/vsource/virtual_source_model.py +3 -5
- shepherd_core/vsource/virtual_source_simulation.py +2 -3
- shepherd_core/writer.py +12 -14
- {shepherd_core-2025.6.3.dist-info → shepherd_core-2025.8.1.dist-info}/METADATA +4 -8
- shepherd_core-2025.8.1.dist-info/RECORD +83 -0
- shepherd_core-2025.6.3.dist-info/RECORD +0 -83
- {shepherd_core-2025.6.3.dist-info → shepherd_core-2025.8.1.dist-info}/WHEEL +0 -0
- {shepherd_core-2025.6.3.dist-info → shepherd_core-2025.8.1.dist-info}/top_level.txt +0 -0
- {shepherd_core-2025.6.3.dist-info → shepherd_core-2025.8.1.dist-info}/zip-safe +0 -0
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import platform
|
|
4
4
|
from contextlib import suppress
|
|
5
5
|
from importlib import import_module
|
|
6
|
-
from typing import Optional
|
|
7
6
|
|
|
8
7
|
from pydantic import ConfigDict
|
|
9
8
|
from typing_extensions import Self
|
|
@@ -15,14 +14,14 @@ class PythonInventory(ShpModel):
|
|
|
15
14
|
"""Python related inventory model."""
|
|
16
15
|
|
|
17
16
|
# program versions
|
|
18
|
-
h5py:
|
|
19
|
-
numpy:
|
|
20
|
-
pydantic:
|
|
21
|
-
python:
|
|
22
|
-
shepherd_core:
|
|
23
|
-
shepherd_sheep:
|
|
24
|
-
yaml:
|
|
25
|
-
zstandard:
|
|
17
|
+
h5py: str | None = None
|
|
18
|
+
numpy: str | None = None
|
|
19
|
+
pydantic: str | None = None
|
|
20
|
+
python: str | None = None
|
|
21
|
+
shepherd_core: str | None = None
|
|
22
|
+
shepherd_sheep: str | None = None
|
|
23
|
+
yaml: str | None = None
|
|
24
|
+
zstandard: str | None = None
|
|
26
25
|
|
|
27
26
|
model_config = ConfigDict(str_min_length=0)
|
|
28
27
|
|
|
@@ -9,7 +9,6 @@ from datetime import datetime
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from types import MappingProxyType
|
|
11
11
|
from typing import Any
|
|
12
|
-
from typing import Optional
|
|
13
12
|
|
|
14
13
|
from typing_extensions import Self
|
|
15
14
|
|
|
@@ -41,7 +40,7 @@ class SystemInventory(ShpModel):
|
|
|
41
40
|
machine: str
|
|
42
41
|
processor: str
|
|
43
42
|
|
|
44
|
-
ptp:
|
|
43
|
+
ptp: str | None = None
|
|
45
44
|
|
|
46
45
|
hostname: str
|
|
47
46
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Hardware related inventory model."""
|
|
2
2
|
|
|
3
3
|
from collections.abc import Sequence
|
|
4
|
-
from typing import Optional
|
|
5
4
|
|
|
6
5
|
from pydantic import ConfigDict
|
|
7
6
|
from typing_extensions import Self
|
|
@@ -12,7 +11,7 @@ from shepherd_core.data_models import ShpModel
|
|
|
12
11
|
class TargetInventory(ShpModel):
|
|
13
12
|
"""Hardware related inventory model."""
|
|
14
13
|
|
|
15
|
-
cape:
|
|
14
|
+
cape: str | None = None
|
|
16
15
|
targets: Sequence[str] = ()
|
|
17
16
|
|
|
18
17
|
model_config = ConfigDict(str_min_length=0)
|
shepherd_core/logger.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
import logging.handlers
|
|
5
|
-
from typing import Union
|
|
6
5
|
|
|
7
6
|
import chromalog
|
|
8
7
|
|
|
@@ -18,7 +17,7 @@ def get_verbose_level() -> int:
|
|
|
18
17
|
return verbose_level
|
|
19
18
|
|
|
20
19
|
|
|
21
|
-
def set_log_verbose_level(log_:
|
|
20
|
+
def set_log_verbose_level(log_: logging.Logger | logging.Handler, verbose: int) -> None:
|
|
22
21
|
"""Set log level of shepherd."""
|
|
23
22
|
if verbose == 0:
|
|
24
23
|
log_.setLevel(logging.ERROR)
|
shepherd_core/reader.py
CHANGED
|
@@ -12,10 +12,7 @@ from itertools import product
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from types import MappingProxyType
|
|
14
14
|
from typing import TYPE_CHECKING
|
|
15
|
-
from typing import Annotated
|
|
16
15
|
from typing import Any
|
|
17
|
-
from typing import Optional
|
|
18
|
-
from typing import Union
|
|
19
16
|
|
|
20
17
|
import h5py
|
|
21
18
|
import numpy as np
|
|
@@ -91,8 +88,6 @@ class Reader:
|
|
|
91
88
|
self.file_size: int = 0
|
|
92
89
|
self.data_rate: float = 0
|
|
93
90
|
|
|
94
|
-
self.buffers_n: Annotated[int, deprecated("use .chunk_n instead")] = 0
|
|
95
|
-
|
|
96
91
|
# open file (if not already done by writer)
|
|
97
92
|
self._reader_opened: bool = False
|
|
98
93
|
if not hasattr(self, "h5file"):
|
|
@@ -161,9 +156,9 @@ class Reader:
|
|
|
161
156
|
|
|
162
157
|
def __exit__(
|
|
163
158
|
self,
|
|
164
|
-
typ:
|
|
165
|
-
exc:
|
|
166
|
-
tb:
|
|
159
|
+
typ: type[BaseException] | None = None,
|
|
160
|
+
exc: BaseException | None = None,
|
|
161
|
+
tb: TracebackType | None = None,
|
|
167
162
|
extra_arg: int = 0,
|
|
168
163
|
) -> None:
|
|
169
164
|
if self._reader_opened:
|
|
@@ -193,7 +188,7 @@ class Reader:
|
|
|
193
188
|
self.sample_interval_ns = round(10**9 * self.sample_interval_s)
|
|
194
189
|
self.samplerate_sps = max(round((self.samples_n - 1) / duration_s), 1)
|
|
195
190
|
self.runtime_s = round(self.samples_n / self.samplerate_sps, 1)
|
|
196
|
-
self.chunks_n =
|
|
191
|
+
self.chunks_n = int(self.samples_n // self.CHUNK_SAMPLES_N)
|
|
197
192
|
if isinstance(self.file_path, Path):
|
|
198
193
|
self.file_size = self.file_path.stat().st_size
|
|
199
194
|
else:
|
|
@@ -203,8 +198,8 @@ class Reader:
|
|
|
203
198
|
def read(
|
|
204
199
|
self,
|
|
205
200
|
start_n: int = 0,
|
|
206
|
-
end_n:
|
|
207
|
-
n_samples_per_chunk:
|
|
201
|
+
end_n: int | None = None,
|
|
202
|
+
n_samples_per_chunk: int | None = None,
|
|
208
203
|
*,
|
|
209
204
|
is_raw: bool = False,
|
|
210
205
|
omit_timestamps: bool = False,
|
|
@@ -251,8 +246,8 @@ class Reader:
|
|
|
251
246
|
def read_buffers(
|
|
252
247
|
self,
|
|
253
248
|
start_n: int = 0,
|
|
254
|
-
end_n:
|
|
255
|
-
n_samples_per_buffer:
|
|
249
|
+
end_n: int | None = None,
|
|
250
|
+
n_samples_per_buffer: int | None = None,
|
|
256
251
|
*,
|
|
257
252
|
is_raw: bool = False,
|
|
258
253
|
omit_ts: bool = False,
|
|
@@ -265,7 +260,7 @@ class Reader:
|
|
|
265
260
|
omit_timestamps=omit_ts,
|
|
266
261
|
)
|
|
267
262
|
|
|
268
|
-
def get_time_start(self) ->
|
|
263
|
+
def get_time_start(self) -> datetime | None:
|
|
269
264
|
if self.samples_n < 1:
|
|
270
265
|
return None
|
|
271
266
|
return datetime.fromtimestamp(self._cal.time.raw_to_si(self.ds_time[0]), tz=local_tz())
|
|
@@ -297,7 +292,7 @@ class Reader:
|
|
|
297
292
|
return self.h5file.attrs["hostname"]
|
|
298
293
|
return "unknown"
|
|
299
294
|
|
|
300
|
-
def get_datatype(self) ->
|
|
295
|
+
def get_datatype(self) -> EnergyDType | None:
|
|
301
296
|
try:
|
|
302
297
|
if "datatype" in self.h5file["data"].attrs:
|
|
303
298
|
return EnergyDType[self.h5file["data"].attrs["datatype"]]
|
|
@@ -308,7 +303,7 @@ class Reader:
|
|
|
308
303
|
else:
|
|
309
304
|
return None
|
|
310
305
|
|
|
311
|
-
def get_voltage_step(self) ->
|
|
306
|
+
def get_voltage_step(self) -> float | None:
|
|
312
307
|
"""Informs about the voltage step (in volts) used during harvesting the ivcurve.
|
|
313
308
|
|
|
314
309
|
Options for figuring out the real step:
|
|
@@ -316,7 +311,7 @@ class Reader:
|
|
|
316
311
|
- analyze recorded data for most often used delta
|
|
317
312
|
- calculate with 'steps_n * (1 + wait_cycles)' (done for calculating window_size)
|
|
318
313
|
"""
|
|
319
|
-
voltage_step:
|
|
314
|
+
voltage_step: float | None = (
|
|
320
315
|
self.get_config().get("virtual_harvester", {}).get("voltage_step_mV", None)
|
|
321
316
|
)
|
|
322
317
|
if voltage_step is None:
|
|
@@ -510,7 +505,7 @@ class Reader:
|
|
|
510
505
|
return float(sum(energy_ws))
|
|
511
506
|
|
|
512
507
|
def _dset_statistics(
|
|
513
|
-
self, dset: h5py.Dataset, cal:
|
|
508
|
+
self, dset: h5py.Dataset, cal: CalibrationPair | None = None
|
|
514
509
|
) -> dict[str, float]:
|
|
515
510
|
"""Create basic stats for a provided dataset.
|
|
516
511
|
|
|
@@ -615,7 +610,7 @@ class Reader:
|
|
|
615
610
|
|
|
616
611
|
def get_metadata(
|
|
617
612
|
self,
|
|
618
|
-
node:
|
|
613
|
+
node: h5py.Dataset | h5py.Group | None = None,
|
|
619
614
|
*,
|
|
620
615
|
minimal: bool = False,
|
|
621
616
|
) -> dict[str, dict]:
|
|
@@ -670,7 +665,7 @@ class Reader:
|
|
|
670
665
|
|
|
671
666
|
return metadata
|
|
672
667
|
|
|
673
|
-
def save_metadata(self, node:
|
|
668
|
+
def save_metadata(self, node: h5py.Dataset | h5py.Group | None = None) -> dict:
|
|
674
669
|
"""Get structure of file and dump content to yaml-file with same name as original.
|
|
675
670
|
|
|
676
671
|
:param node: starting node, leave free to go through whole file
|
|
@@ -688,7 +683,7 @@ class Reader:
|
|
|
688
683
|
metadata = {}
|
|
689
684
|
return metadata
|
|
690
685
|
|
|
691
|
-
def get_gpio_pin_num(self, name: str) ->
|
|
686
|
+
def get_gpio_pin_num(self, name: str) -> int | None:
|
|
692
687
|
# reverse lookup in a 2D-dict: key1 are pin_num, key2 are descriptor-names
|
|
693
688
|
if "gpio" not in self.h5file:
|
|
694
689
|
return None
|
|
@@ -709,7 +704,7 @@ class Reader:
|
|
|
709
704
|
data_1 = np.concatenate(([not data[0]], data[:-1]))
|
|
710
705
|
return data != data_1
|
|
711
706
|
|
|
712
|
-
def gpio_to_waveforms(self, name:
|
|
707
|
+
def gpio_to_waveforms(self, name: str | None = None) -> dict:
|
|
713
708
|
waveforms: dict[str, np.ndarray] = {}
|
|
714
709
|
if "gpio" not in self.h5file:
|
|
715
710
|
return waveforms
|
|
@@ -744,7 +739,7 @@ class Reader:
|
|
|
744
739
|
for row in pin_wf:
|
|
745
740
|
csv.write(f"{row[0] / 1e9}{separator}{int(row[1])}\n")
|
|
746
741
|
|
|
747
|
-
def gpio_to_uart(self) ->
|
|
742
|
+
def gpio_to_uart(self) -> np.ndarray | None:
|
|
748
743
|
wfs = self.gpio_to_waveforms("uart")
|
|
749
744
|
if len(wfs) < 1:
|
|
750
745
|
return None
|
|
@@ -18,7 +18,6 @@ TODO: Comfort functions missing
|
|
|
18
18
|
from abc import ABC
|
|
19
19
|
from abc import abstractmethod
|
|
20
20
|
from typing import Any
|
|
21
|
-
from typing import Optional
|
|
22
21
|
|
|
23
22
|
from shepherd_core.data_models.base.shepherd import ShpModel
|
|
24
23
|
from shepherd_core.data_models.base.wrapper import Wrapper
|
|
@@ -49,9 +48,7 @@ class AbcClient(ABC):
|
|
|
49
48
|
pass
|
|
50
49
|
|
|
51
50
|
@abstractmethod
|
|
52
|
-
def query_item(
|
|
53
|
-
self, model_type: str, uid: Optional[int] = None, name: Optional[str] = None
|
|
54
|
-
) -> dict:
|
|
51
|
+
def query_item(self, model_type: str, uid: int | None = None, name: str | None = None) -> dict:
|
|
55
52
|
pass
|
|
56
53
|
|
|
57
54
|
@abstractmethod
|
|
@@ -103,9 +100,7 @@ class FixturesClient(AbcClient):
|
|
|
103
100
|
def query_names(self, model_type: str) -> list[str]:
|
|
104
101
|
return list(self._fixtures[model_type].elements_by_name.keys())
|
|
105
102
|
|
|
106
|
-
def query_item(
|
|
107
|
-
self, model_type: str, uid: Optional[int] = None, name: Optional[str] = None
|
|
108
|
-
) -> dict:
|
|
103
|
+
def query_item(self, model_type: str, uid: int | None = None, name: str | None = None) -> dict:
|
|
109
104
|
if uid is not None:
|
|
110
105
|
return self._fixtures[model_type].query_id(uid)
|
|
111
106
|
if name is not None:
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
from importlib import import_module
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import Any
|
|
6
|
-
from typing import Optional
|
|
7
|
-
from typing import Union
|
|
8
6
|
|
|
9
7
|
from pydantic import validate_call
|
|
10
8
|
|
|
@@ -28,7 +26,7 @@ class WebClient(AbcClient):
|
|
|
28
26
|
|
|
29
27
|
testbed_server_default = "https://shepherd.cfaed.tu-dresden.de:8000/testbed"
|
|
30
28
|
|
|
31
|
-
def __init__(self, server:
|
|
29
|
+
def __init__(self, server: str | None = None, token: str | Path | None = None) -> None:
|
|
32
30
|
"""Connect to Testbed-Server with optional token and server-address.
|
|
33
31
|
|
|
34
32
|
server: optional address to shepherd-server-endpoint
|
|
@@ -39,8 +37,8 @@ class WebClient(AbcClient):
|
|
|
39
37
|
# add default values
|
|
40
38
|
self._token: str = "basic_public_access" # noqa: S105
|
|
41
39
|
self._server: str = config.TESTBED_SERVER
|
|
42
|
-
self._user:
|
|
43
|
-
self._key:
|
|
40
|
+
self._user: User | None = None
|
|
41
|
+
self._key: str | None = None
|
|
44
42
|
self._connected: bool = False
|
|
45
43
|
self._req = None
|
|
46
44
|
|
|
@@ -66,9 +64,7 @@ class WebClient(AbcClient):
|
|
|
66
64
|
def query_names(self, model_type: str) -> list[str]:
|
|
67
65
|
raise NotImplementedError("TODO")
|
|
68
66
|
|
|
69
|
-
def query_item(
|
|
70
|
-
self, model_type: str, uid: Optional[int] = None, name: Optional[str] = None
|
|
71
|
-
) -> dict:
|
|
67
|
+
def query_item(self, model_type: str, uid: int | None = None, name: str | None = None) -> dict:
|
|
72
68
|
raise NotImplementedError("TODO")
|
|
73
69
|
|
|
74
70
|
def try_inheritance(
|
|
@@ -88,7 +84,7 @@ class WebClient(AbcClient):
|
|
|
88
84
|
# Below are extra FNs not in ABC
|
|
89
85
|
|
|
90
86
|
@validate_call
|
|
91
|
-
def _connect(self, server:
|
|
87
|
+
def _connect(self, server: str | None = None, token: str | Path | None = None) -> bool:
|
|
92
88
|
"""Establish connection to testbed-server.
|
|
93
89
|
|
|
94
90
|
TODO: totally not finished
|
|
@@ -8,8 +8,6 @@ from datetime import datetime
|
|
|
8
8
|
from datetime import timedelta
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from typing import Any
|
|
11
|
-
from typing import Optional
|
|
12
|
-
from typing import Union
|
|
13
11
|
|
|
14
12
|
import yaml
|
|
15
13
|
from pydantic import validate_call
|
|
@@ -57,7 +55,7 @@ class Fixture:
|
|
|
57
55
|
# update iterator
|
|
58
56
|
self._iter_list: list[dict[str, Any]] = list(self.elements_by_name.values())
|
|
59
57
|
|
|
60
|
-
def __getitem__(self, key:
|
|
58
|
+
def __getitem__(self, key: str | int) -> dict[str, Any]:
|
|
61
59
|
original_key = key
|
|
62
60
|
if isinstance(key, str):
|
|
63
61
|
key = key.lower()
|
|
@@ -89,7 +87,7 @@ class Fixture:
|
|
|
89
87
|
return {_i["id"]: _i["name"] for _i in self.elements_by_id.values()}
|
|
90
88
|
|
|
91
89
|
def inheritance(
|
|
92
|
-
self, values: dict[str, Any], chain:
|
|
90
|
+
self, values: dict[str, Any], chain: list[str] | None = None
|
|
93
91
|
) -> tuple[dict[str, Any], list[str]]:
|
|
94
92
|
if chain is None:
|
|
95
93
|
chain = []
|
|
@@ -177,7 +175,7 @@ class Fixtures:
|
|
|
177
175
|
suffix = ".yaml"
|
|
178
176
|
|
|
179
177
|
@validate_call
|
|
180
|
-
def __init__(self, file_path:
|
|
178
|
+
def __init__(self, file_path: Path | None = None, *, reset: bool = False) -> None:
|
|
181
179
|
if file_path is None:
|
|
182
180
|
self.file_path = Path(__file__).parent.parent.resolve() / "data_models"
|
|
183
181
|
else:
|
|
@@ -4,7 +4,6 @@ import secrets
|
|
|
4
4
|
from hashlib import pbkdf2_hmac
|
|
5
5
|
from typing import Annotated
|
|
6
6
|
from typing import Any
|
|
7
|
-
from typing import Optional
|
|
8
7
|
|
|
9
8
|
from pydantic import EmailStr
|
|
10
9
|
from pydantic import Field
|
|
@@ -44,14 +43,14 @@ class User(ShpModel):
|
|
|
44
43
|
default_factory=id_default,
|
|
45
44
|
)
|
|
46
45
|
name: NameStr
|
|
47
|
-
description:
|
|
48
|
-
comment:
|
|
46
|
+
description: SafeStr | None = None
|
|
47
|
+
comment: SafeStr | None = None
|
|
49
48
|
|
|
50
|
-
name_full:
|
|
49
|
+
name_full: NameStr | None = None
|
|
51
50
|
group: NameStr
|
|
52
51
|
email: EmailStr
|
|
53
52
|
|
|
54
|
-
pw_hash:
|
|
53
|
+
pw_hash: SecretBytes | None = None
|
|
55
54
|
# ⤷ was hash_password("this_will_become_a_salted_slow_hash") -> slowed BBB down
|
|
56
55
|
# ⤷ TODO (min_length=128, max_length=512)
|
|
57
56
|
|
shepherd_core/version.py
CHANGED
|
@@ -15,7 +15,6 @@ Compromises:
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
import math
|
|
18
|
-
from typing import Optional
|
|
19
18
|
|
|
20
19
|
from shepherd_core.data_models import CalibrationEmulator
|
|
21
20
|
from shepherd_core.data_models.content.virtual_source import LUT_SIZE
|
|
@@ -32,7 +31,7 @@ class PruCalibration:
|
|
|
32
31
|
RESIDUE_MAX_nA: int = NOISE_ESTIMATE_nA * RESIDUE_SIZE_FACTOR
|
|
33
32
|
negative_residue_nA = 0
|
|
34
33
|
|
|
35
|
-
def __init__(self, cal_emu:
|
|
34
|
+
def __init__(self, cal_emu: CalibrationEmulator | None = None) -> None:
|
|
36
35
|
self.cal = cal_emu if cal_emu else CalibrationEmulator()
|
|
37
36
|
|
|
38
37
|
def conv_adc_raw_to_nA(self, current_raw: int) -> float:
|
|
@@ -9,7 +9,6 @@ The output file can be analyzed and plotted with shepherds tool suite.
|
|
|
9
9
|
|
|
10
10
|
from contextlib import ExitStack
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Optional
|
|
13
12
|
|
|
14
13
|
from tqdm import tqdm
|
|
15
14
|
|
|
@@ -23,7 +22,7 @@ from .virtual_harvester_model import VirtualHarvesterModel
|
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
def simulate_harvester(
|
|
26
|
-
config: VirtualHarvesterConfig, path_input: Path, path_output:
|
|
25
|
+
config: VirtualHarvesterConfig, path_input: Path, path_output: Path | None = None
|
|
27
26
|
) -> float:
|
|
28
27
|
"""Simulate behavior of virtual harvester algorithms.
|
|
29
28
|
|
|
@@ -10,8 +10,6 @@ NOTE: DO NOT OPTIMIZE -> stay close to original code-base
|
|
|
10
10
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
-
from typing import Optional
|
|
14
|
-
|
|
15
13
|
from shepherd_core.data_models.base.calibration import CalibrationEmulator
|
|
16
14
|
from shepherd_core.data_models.content.energy_environment import EnergyDType
|
|
17
15
|
from shepherd_core.data_models.content.virtual_harvester import HarvesterPRUConfig
|
|
@@ -28,11 +26,11 @@ class VirtualSourceModel:
|
|
|
28
26
|
|
|
29
27
|
def __init__(
|
|
30
28
|
self,
|
|
31
|
-
vsrc:
|
|
29
|
+
vsrc: VirtualSourceConfig | None,
|
|
32
30
|
cal_emu: CalibrationEmulator,
|
|
33
31
|
dtype_in: EnergyDType = EnergyDType.ivsample,
|
|
34
|
-
window_size:
|
|
35
|
-
voltage_step_V:
|
|
32
|
+
window_size: int | None = None,
|
|
33
|
+
voltage_step_V: float | None = None,
|
|
36
34
|
*,
|
|
37
35
|
log_intermediate: bool = False,
|
|
38
36
|
) -> None:
|
|
@@ -9,7 +9,6 @@ The output file can be analyzed and plotted with shepherds tool suite.
|
|
|
9
9
|
|
|
10
10
|
from contextlib import ExitStack
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Optional
|
|
13
12
|
|
|
14
13
|
import numpy as np
|
|
15
14
|
from tqdm import tqdm
|
|
@@ -28,7 +27,7 @@ def simulate_source(
|
|
|
28
27
|
config: VirtualSourceConfig,
|
|
29
28
|
target: TargetABC,
|
|
30
29
|
path_input: Path,
|
|
31
|
-
path_output:
|
|
30
|
+
path_output: Path | None = None,
|
|
32
31
|
*,
|
|
33
32
|
monitor_internals: bool = False,
|
|
34
33
|
) -> float:
|
|
@@ -66,7 +65,7 @@ def simulate_source(
|
|
|
66
65
|
stats_internal = np.empty((round(file_inp.runtime_s * file_inp.samplerate_sps), 11))
|
|
67
66
|
try:
|
|
68
67
|
# keep dependencies low
|
|
69
|
-
from matplotlib import pyplot as plt
|
|
68
|
+
from matplotlib import pyplot as plt # noqa: PLC0415
|
|
70
69
|
except ImportError:
|
|
71
70
|
log.warning("Matplotlib not installed, plotting of internals disabled")
|
|
72
71
|
stats_internal = None
|
shepherd_core/writer.py
CHANGED
|
@@ -9,8 +9,6 @@ from itertools import product
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from types import TracebackType
|
|
11
11
|
from typing import Any
|
|
12
|
-
from typing import Optional
|
|
13
|
-
from typing import Union
|
|
14
12
|
|
|
15
13
|
import h5py
|
|
16
14
|
import numpy as np
|
|
@@ -32,7 +30,7 @@ from .reader import Reader
|
|
|
32
30
|
|
|
33
31
|
# copy of core/models/base/shepherd - needed also here
|
|
34
32
|
def path2str(
|
|
35
|
-
dumper: SafeDumper, data:
|
|
33
|
+
dumper: SafeDumper, data: pathlib.Path | pathlib.WindowsPath | pathlib.PosixPath
|
|
36
34
|
) -> Node:
|
|
37
35
|
"""Add a yaml-representation for a specific datatype."""
|
|
38
36
|
return dumper.represent_scalar("tag:yaml.org,2002:str", str(data.as_posix()))
|
|
@@ -49,7 +47,7 @@ yaml.add_representer(pathlib.Path, path2str, SafeDumper)
|
|
|
49
47
|
yaml.add_representer(timedelta, time2int, SafeDumper)
|
|
50
48
|
|
|
51
49
|
|
|
52
|
-
def unique_path(base_path:
|
|
50
|
+
def unique_path(base_path: str | Path, suffix: str) -> Path:
|
|
53
51
|
"""Find an unused filename in case it already exists.
|
|
54
52
|
|
|
55
53
|
:param base_path: file-path to test
|
|
@@ -100,11 +98,11 @@ class Writer(Reader):
|
|
|
100
98
|
def __init__(
|
|
101
99
|
self,
|
|
102
100
|
file_path: Path,
|
|
103
|
-
mode:
|
|
104
|
-
datatype:
|
|
105
|
-
window_samples:
|
|
106
|
-
cal_data:
|
|
107
|
-
compression:
|
|
101
|
+
mode: str | None = None,
|
|
102
|
+
datatype: str | EnergyDType | None = None,
|
|
103
|
+
window_samples: int | None = None,
|
|
104
|
+
cal_data: CalSeries | CalEmu | CalHrv | None = None,
|
|
105
|
+
compression: Compression | None = Compression.default,
|
|
108
106
|
*,
|
|
109
107
|
modify_existing: bool = False,
|
|
110
108
|
force_overwrite: bool = False,
|
|
@@ -210,9 +208,9 @@ class Writer(Reader):
|
|
|
210
208
|
|
|
211
209
|
def __exit__(
|
|
212
210
|
self,
|
|
213
|
-
typ:
|
|
214
|
-
exc:
|
|
215
|
-
tb:
|
|
211
|
+
typ: type[BaseException] | None = None,
|
|
212
|
+
exc: BaseException | None = None,
|
|
213
|
+
tb: TracebackType | None = None,
|
|
216
214
|
extra_arg: int = 0,
|
|
217
215
|
) -> None:
|
|
218
216
|
self._align()
|
|
@@ -279,7 +277,7 @@ class Writer(Reader):
|
|
|
279
277
|
|
|
280
278
|
def append_iv_data_raw(
|
|
281
279
|
self,
|
|
282
|
-
timestamp:
|
|
280
|
+
timestamp: np.ndarray | float | int, # noqa: PYI041
|
|
283
281
|
voltage: np.ndarray,
|
|
284
282
|
current: np.ndarray,
|
|
285
283
|
) -> None:
|
|
@@ -318,7 +316,7 @@ class Writer(Reader):
|
|
|
318
316
|
|
|
319
317
|
def append_iv_data_si(
|
|
320
318
|
self,
|
|
321
|
-
timestamp:
|
|
319
|
+
timestamp: np.ndarray | float,
|
|
322
320
|
voltage: np.ndarray,
|
|
323
321
|
current: np.ndarray,
|
|
324
322
|
) -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shepherd_core
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.8.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>
|
|
@@ -18,7 +18,6 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
18
18
|
Classifier: Intended Audience :: Developers
|
|
19
19
|
Classifier: Intended Audience :: Information Technology
|
|
20
20
|
Classifier: Intended Audience :: Science/Research
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.10
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -26,7 +25,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
26
25
|
Classifier: License :: OSI Approved :: MIT License
|
|
27
26
|
Classifier: Operating System :: OS Independent
|
|
28
27
|
Classifier: Natural Language :: English
|
|
29
|
-
Requires-Python: >=3.
|
|
28
|
+
Requires-Python: >=3.10
|
|
30
29
|
Description-Content-Type: text/markdown
|
|
31
30
|
Requires-Dist: h5py
|
|
32
31
|
Requires-Dist: numpy
|
|
@@ -44,15 +43,12 @@ Requires-Dist: pwntools-elf-only; extra == "elf"
|
|
|
44
43
|
Provides-Extra: inventory
|
|
45
44
|
Requires-Dist: psutil; extra == "inventory"
|
|
46
45
|
Provides-Extra: dev
|
|
47
|
-
Requires-Dist: twine; extra == "dev"
|
|
48
|
-
Requires-Dist: pre-commit; extra == "dev"
|
|
49
|
-
Requires-Dist: pyright; extra == "dev"
|
|
50
|
-
Requires-Dist: ruff; extra == "dev"
|
|
51
|
-
Requires-Dist: mypy; extra == "dev"
|
|
52
46
|
Requires-Dist: types-PyYAML; extra == "dev"
|
|
53
47
|
Provides-Extra: test
|
|
54
48
|
Requires-Dist: pytest; extra == "test"
|
|
55
49
|
Requires-Dist: coverage; extra == "test"
|
|
50
|
+
Provides-Extra: all
|
|
51
|
+
Requires-Dist: shepherd-core[dev,elf,inventory,test]; extra == "all"
|
|
56
52
|
|
|
57
53
|
# Core Library
|
|
58
54
|
|