shepherd-core 2023.8.7__py3-none-any.whl → 2023.8.8__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/__init__.py +1 -1
- shepherd_core/data_models/__init__.py +3 -1
- shepherd_core/data_models/base/cal_measurement.py +4 -3
- shepherd_core/data_models/base/calibration.py +37 -4
- shepherd_core/data_models/base/shepherd.py +9 -0
- shepherd_core/data_models/experiment/experiment.py +1 -0
- shepherd_core/data_models/experiment/observer_features.py +1 -1
- shepherd_core/data_models/experiment/target_config.py +1 -0
- shepherd_core/data_models/task/__init__.py +13 -5
- shepherd_core/data_models/task/emulation.py +10 -4
- shepherd_core/data_models/task/harvest.py +9 -3
- shepherd_core/data_models/task/observer_tasks.py +10 -0
- shepherd_core/data_models/task/testbed_tasks.py +9 -1
- shepherd_core/inventory/__init__.py +3 -3
- shepherd_core/testbed_client/client.py +4 -2
- shepherd_core/testbed_client/user_model.py +2 -1
- {shepherd_core-2023.8.7.dist-info → shepherd_core-2023.8.8.dist-info}/METADATA +8 -1
- {shepherd_core-2023.8.7.dist-info → shepherd_core-2023.8.8.dist-info}/RECORD +25 -25
- {shepherd_core-2023.8.7.dist-info → shepherd_core-2023.8.8.dist-info}/WHEEL +1 -1
- tests/data_models/example_cal_data.yaml +2 -1
- tests/data_models/example_cal_meas.yaml +2 -1
- tests/data_models/test_base_models.py +17 -0
- tests/inventory/test_inventory.py +1 -1
- {shepherd_core-2023.8.7.dist-info → shepherd_core-2023.8.8.dist-info}/top_level.txt +0 -0
- {shepherd_core-2023.8.7.dist-info → shepherd_core-2023.8.8.dist-info}/zip-safe +0 -0
shepherd_core/__init__.py
CHANGED
|
@@ -3,6 +3,7 @@ from .base.calibration import CalibrationEmulator
|
|
|
3
3
|
from .base.calibration import CalibrationHarvester
|
|
4
4
|
from .base.calibration import CalibrationPair
|
|
5
5
|
from .base.calibration import CalibrationSeries
|
|
6
|
+
from .base.calibration import CapeData
|
|
6
7
|
from .base.content import ContentModel
|
|
7
8
|
from .base.shepherd import ShpModel
|
|
8
9
|
from .base.wrapper import Wrapper
|
|
@@ -23,6 +24,7 @@ from .experiment.target_config import TargetConfig
|
|
|
23
24
|
|
|
24
25
|
__all__ = [
|
|
25
26
|
# Core
|
|
27
|
+
"CapeData",
|
|
26
28
|
"CalibrationCape",
|
|
27
29
|
"CalibrationEmulator",
|
|
28
30
|
"CalibrationHarvester",
|
|
@@ -46,4 +48,4 @@ __all__ = [
|
|
|
46
48
|
"EnergyDType",
|
|
47
49
|
"VirtualSourceConfig",
|
|
48
50
|
"VirtualHarvesterConfig",
|
|
49
|
-
]
|
|
51
|
+
]
|
|
@@ -11,6 +11,7 @@ from .. import CalibrationCape
|
|
|
11
11
|
from .. import CalibrationEmulator
|
|
12
12
|
from .. import CalibrationHarvester
|
|
13
13
|
from .. import CalibrationPair
|
|
14
|
+
from .calibration import CapeData
|
|
14
15
|
from .shepherd import ShpModel
|
|
15
16
|
|
|
16
17
|
# TODO: move to shepherd_data to remove scipy-dependency from _core
|
|
@@ -75,12 +76,12 @@ class CalMeasurementEmulator(ShpModel):
|
|
|
75
76
|
|
|
76
77
|
|
|
77
78
|
class CalMeasurementCape(ShpModel):
|
|
79
|
+
cape: Optional[CapeData] = None
|
|
80
|
+
host: Optional[str] = None
|
|
81
|
+
|
|
78
82
|
harvester: Optional[CalMeasurementHarvester] = None
|
|
79
83
|
emulator: Optional[CalMeasurementEmulator] = None
|
|
80
84
|
|
|
81
|
-
cape: Optional[str] = None
|
|
82
|
-
host: Optional[str] = None
|
|
83
|
-
|
|
84
85
|
def to_cal(self) -> CalibrationCape:
|
|
85
86
|
dv = self.model_dump()
|
|
86
87
|
dcal = CalibrationCape().model_dump()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import struct
|
|
2
|
+
from datetime import date
|
|
2
3
|
from typing import Callable
|
|
3
4
|
from typing import Generator
|
|
4
5
|
from typing import Optional
|
|
@@ -7,7 +8,10 @@ from typing import Union
|
|
|
7
8
|
|
|
8
9
|
import numpy as np
|
|
9
10
|
from numpy.typing import NDArray
|
|
11
|
+
from pydantic import Field
|
|
10
12
|
from pydantic import PositiveFloat
|
|
13
|
+
from pydantic import conbytes
|
|
14
|
+
from pydantic import constr
|
|
11
15
|
from pydantic import validate_call
|
|
12
16
|
|
|
13
17
|
from ...calibration_hw_def import adc_current_to_raw
|
|
@@ -146,6 +150,33 @@ class CalibrationEmulator(ShpModel):
|
|
|
146
150
|
return cal_set
|
|
147
151
|
|
|
148
152
|
|
|
153
|
+
class CapeData(ShpModel):
|
|
154
|
+
"""Representation of Beaglebone Cape information
|
|
155
|
+
-> just provide serial-number on creation
|
|
156
|
+
|
|
157
|
+
According to BeagleBone specifications, each cape should host an EEPROM
|
|
158
|
+
that contains some standardized information about the type of cape,
|
|
159
|
+
manufacturer, version etc.
|
|
160
|
+
|
|
161
|
+
`See<https://github.com/beagleboard/beaglebone-black/wiki/System-Reference-Manual#824_EEPROM_Data_Format>`_
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
header: conbytes(max_length=4) = b"\xAA\x55\x33\xEE"
|
|
165
|
+
eeprom_revision: constr(max_length=2) = "A2"
|
|
166
|
+
board_name: constr(max_length=32) = "BeagleBone SHEPHERD2 Cape"
|
|
167
|
+
version: constr(max_length=4) = "24B0"
|
|
168
|
+
manufacturer: constr(max_length=16) = "NES TU DRESDEN"
|
|
169
|
+
part_number: constr(max_length=16) = "BB-SHPRD"
|
|
170
|
+
|
|
171
|
+
serial_number: constr(max_length=12)
|
|
172
|
+
|
|
173
|
+
cal_date: constr(max_length=12) = Field(default_factory=date.today().isoformat)
|
|
174
|
+
|
|
175
|
+
def __repr__(self) -> str:
|
|
176
|
+
"""string-representation allows print(model)"""
|
|
177
|
+
return str(self.model_dump())
|
|
178
|
+
|
|
179
|
+
|
|
149
180
|
class CalibrationCape(ShpModel):
|
|
150
181
|
"""Represents calibration data of shepherd cape.
|
|
151
182
|
Defines the format of calibration data and provides convenient functions
|
|
@@ -154,19 +185,20 @@ class CalibrationCape(ShpModel):
|
|
|
154
185
|
YAML: .to_file() and .from_file() already in ShpModel
|
|
155
186
|
"""
|
|
156
187
|
|
|
188
|
+
cape: Optional[CapeData] = None
|
|
189
|
+
host: Optional[str] = None
|
|
190
|
+
|
|
157
191
|
harvester: CalibrationHarvester = CalibrationHarvester()
|
|
158
192
|
emulator: CalibrationEmulator = CalibrationEmulator()
|
|
159
193
|
|
|
160
|
-
cape: Optional[str] = None
|
|
161
|
-
host: Optional[str] = None
|
|
162
|
-
|
|
163
194
|
@classmethod
|
|
164
|
-
def from_bytestr(cls, data: bytes):
|
|
195
|
+
def from_bytestr(cls, data: bytes, cape: Optional[CapeData] = None):
|
|
165
196
|
"""Instantiates calibration data based on byte string.
|
|
166
197
|
This is mainly used to deserialize data read from an EEPROM memory.
|
|
167
198
|
|
|
168
199
|
Args:
|
|
169
200
|
data: Byte string containing calibration data.
|
|
201
|
+
cape: data can be supplied
|
|
170
202
|
Returns:
|
|
171
203
|
CalibrationCape object with extracted calibration data.
|
|
172
204
|
"""
|
|
@@ -177,6 +209,7 @@ class CalibrationCape(ShpModel):
|
|
|
177
209
|
for _i, walk in enumerate(lw):
|
|
178
210
|
# hardcoded fixed depth ... bad but easy
|
|
179
211
|
dv[walk[0]][walk[1]][walk[2]] = float(values[_i])
|
|
212
|
+
dv["cape"] = cape
|
|
180
213
|
return cls(**dv)
|
|
181
214
|
|
|
182
215
|
def to_bytestr(self) -> bytes:
|
|
@@ -67,6 +67,15 @@ class ShpModel(BaseModel):
|
|
|
67
67
|
"""allows dict access -> model["key"], in addition to model.key"""
|
|
68
68
|
return self.__getattribute__(key)
|
|
69
69
|
|
|
70
|
+
def keys(self):
|
|
71
|
+
"""Fn of dict"""
|
|
72
|
+
return self.model_dump().keys()
|
|
73
|
+
|
|
74
|
+
def items(self):
|
|
75
|
+
"""Fn of dict"""
|
|
76
|
+
for key in self.keys():
|
|
77
|
+
yield key, self[key]
|
|
78
|
+
|
|
70
79
|
@classmethod
|
|
71
80
|
def schema_to_file(cls, path: Union[str, Path]) -> None:
|
|
72
81
|
"""store schema to yaml (for frontend-generators)"""
|
|
@@ -28,6 +28,7 @@ class Experiment(ShpModel, title="Config of an Experiment"):
|
|
|
28
28
|
description="Unique ID",
|
|
29
29
|
default_factory=id_default,
|
|
30
30
|
)
|
|
31
|
+
# ⤷ TODO: automatic ID is problematic for identification by hash
|
|
31
32
|
name: NameStr
|
|
32
33
|
description: Annotated[
|
|
33
34
|
Optional[SafeStr], Field(description="Required for public instances")
|
|
@@ -61,7 +61,7 @@ class GpioTracing(ShpModel, title="Config for GPIO-Tracing"):
|
|
|
61
61
|
gpios: Optional[
|
|
62
62
|
Annotated[List[GPIO], Field(min_length=1, max_length=10)]
|
|
63
63
|
] = None # = all
|
|
64
|
-
# ⤷ TODO: list of GPIO to build mask, one of both should be internal
|
|
64
|
+
# ⤷ TODO: list of GPIO to build mask, one of both should be internal / computed field
|
|
65
65
|
|
|
66
66
|
# time
|
|
67
67
|
delay: timedelta = 0 # seconds
|
|
@@ -33,6 +33,7 @@ class TargetConfig(ShpModel, title="Target Config"):
|
|
|
33
33
|
Annotated[List[Annotated[int, Field(ge=0)]], Field(min_length=1, max_length=64)]
|
|
34
34
|
] = None
|
|
35
35
|
# ⤷ individual starting times -> allows to use the same environment
|
|
36
|
+
# TODO: delays not used ATM
|
|
36
37
|
|
|
37
38
|
firmware1: Firmware
|
|
38
39
|
firmware2: Optional[Firmware] = None
|
|
@@ -50,16 +50,18 @@ def prepare_task(
|
|
|
50
50
|
elif isinstance(config, ShpModel):
|
|
51
51
|
shp_wrap = Wrapper(
|
|
52
52
|
datatype=type(config).__name__,
|
|
53
|
-
parameters=config.
|
|
53
|
+
parameters=config.model_dump(),
|
|
54
54
|
)
|
|
55
55
|
else:
|
|
56
56
|
raise ValueError("had unknown input: %s", type(config))
|
|
57
57
|
|
|
58
58
|
if shp_wrap.datatype == TestbedTasks:
|
|
59
59
|
if observer is None:
|
|
60
|
-
|
|
61
|
-
"Task-Set contained TestbedTasks
|
|
60
|
+
logger.debug(
|
|
61
|
+
"Task-Set contained TestbedTasks & no observer was provided "
|
|
62
|
+
"-> will return TB-Tasks"
|
|
62
63
|
)
|
|
64
|
+
return shp_wrap
|
|
63
65
|
tbt = TestbedTasks(**shp_wrap.parameters)
|
|
64
66
|
logger.debug("Loading Testbed-Tasks %s for %s", tbt.name, observer)
|
|
65
67
|
obt = tbt.get_observer_tasks(observer)
|
|
@@ -67,12 +69,12 @@ def prepare_task(
|
|
|
67
69
|
raise ValueError("Observer '%s' is not in TestbedTask-Set", observer)
|
|
68
70
|
shp_wrap = Wrapper(
|
|
69
71
|
datatype=type(obt).__name__,
|
|
70
|
-
parameters=obt.
|
|
72
|
+
parameters=obt.model_dump(),
|
|
71
73
|
)
|
|
72
74
|
return shp_wrap
|
|
73
75
|
|
|
74
76
|
|
|
75
|
-
def extract_tasks(shp_wrap: Wrapper) -> List[ShpModel]:
|
|
77
|
+
def extract_tasks(shp_wrap: Wrapper, no_task_sets: bool = True) -> List[ShpModel]:
|
|
76
78
|
""" """
|
|
77
79
|
if shp_wrap.datatype == ObserverTasks:
|
|
78
80
|
obt = ObserverTasks(**shp_wrap.parameters)
|
|
@@ -85,6 +87,12 @@ def extract_tasks(shp_wrap: Wrapper) -> List[ShpModel]:
|
|
|
85
87
|
content = [FirmwareModTask(**shp_wrap.parameters)]
|
|
86
88
|
elif shp_wrap.datatype == ProgrammingTask.__name__:
|
|
87
89
|
content = [ProgrammingTask(**shp_wrap.parameters)]
|
|
90
|
+
elif shp_wrap.datatype == TestbedTasks.__name__:
|
|
91
|
+
if no_task_sets:
|
|
92
|
+
raise ValueError(
|
|
93
|
+
"Model in Wrapper was TestbedTasks -> Task-Sets not allowed!"
|
|
94
|
+
)
|
|
95
|
+
content = [TestbedTasks(**shp_wrap.parameters)]
|
|
88
96
|
else:
|
|
89
97
|
raise ValueError("Extractor had unknown task: %s", shp_wrap.datatype)
|
|
90
98
|
|
|
@@ -46,7 +46,7 @@ class EmulationTask(ShpModel):
|
|
|
46
46
|
# - providing a directory -> file is named emu_timestamp.h5
|
|
47
47
|
# - for a complete path the filename is not changed except it exists and
|
|
48
48
|
# overwrite is disabled -> emu#num.h5
|
|
49
|
-
# TODO: should the path be mandatory?
|
|
49
|
+
# TODO: should the output-path be mandatory?
|
|
50
50
|
force_overwrite: bool = False
|
|
51
51
|
# ⤷ Overwrite existing file
|
|
52
52
|
output_compression: Optional[Compression] = Compression.default
|
|
@@ -92,8 +92,10 @@ class EmulationTask(ShpModel):
|
|
|
92
92
|
@model_validator(mode="before")
|
|
93
93
|
@classmethod
|
|
94
94
|
def pre_correction(cls, values: dict) -> dict:
|
|
95
|
-
# add local timezone-data
|
|
95
|
+
# convert & add local timezone-data
|
|
96
96
|
has_time = values.get("time_start") is not None
|
|
97
|
+
if has_time and isinstance(values["time_start"], (int, float)):
|
|
98
|
+
values["time_start"] = datetime.fromtimestamp(values["time_start"])
|
|
97
99
|
if has_time and isinstance(values["time_start"], str):
|
|
98
100
|
values["time_start"] = datetime.fromisoformat(values["time_start"])
|
|
99
101
|
if has_time and values["time_start"].tzinfo is None:
|
|
@@ -104,8 +106,12 @@ class EmulationTask(ShpModel):
|
|
|
104
106
|
def post_validation(self):
|
|
105
107
|
# TODO: limit paths
|
|
106
108
|
has_time = self.time_start is not None
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
time_now = datetime.now().astimezone()
|
|
110
|
+
if has_time and self.time_start < time_now:
|
|
111
|
+
raise ValueError(
|
|
112
|
+
"Start-Time for Emulation can't be in the past "
|
|
113
|
+
f"('{self.time_start}' vs '{time_now}'."
|
|
114
|
+
)
|
|
109
115
|
if self.duration and self.duration.total_seconds() < 0:
|
|
110
116
|
raise ValueError("Task-Duration can't be negative.")
|
|
111
117
|
if isinstance(self.voltage_aux, str) and self.voltage_aux not in [
|
|
@@ -55,8 +55,10 @@ class HarvestTask(ShpModel):
|
|
|
55
55
|
@model_validator(mode="before")
|
|
56
56
|
@classmethod
|
|
57
57
|
def pre_correction(cls, values: dict) -> dict:
|
|
58
|
-
# add local timezone-data
|
|
58
|
+
# convert & add local timezone-data, TODO: used twice, refactor
|
|
59
59
|
has_time = values.get("time_start") is not None
|
|
60
|
+
if has_time and isinstance(values["time_start"], (int, float)):
|
|
61
|
+
values["time_start"] = datetime.fromtimestamp(values["time_start"])
|
|
60
62
|
if has_time and isinstance(values["time_start"], str):
|
|
61
63
|
values["time_start"] = datetime.fromisoformat(values["time_start"])
|
|
62
64
|
if has_time and values["time_start"].tzinfo is None:
|
|
@@ -67,8 +69,12 @@ class HarvestTask(ShpModel):
|
|
|
67
69
|
def post_validation(self):
|
|
68
70
|
# TODO: limit paths
|
|
69
71
|
has_time = self.time_start is not None
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
time_now = datetime.now().astimezone()
|
|
73
|
+
if has_time and self.time_start < time_now:
|
|
74
|
+
raise ValueError(
|
|
75
|
+
"Start-Time for Emulation can't be in the past "
|
|
76
|
+
f"('{self.time_start}' vs '{time_now}'."
|
|
77
|
+
)
|
|
72
78
|
if self.duration and self.duration.total_seconds() < 0:
|
|
73
79
|
raise ValueError("Task-Duration can't be negative.")
|
|
74
80
|
return self
|
|
@@ -3,6 +3,7 @@ from pathlib import Path
|
|
|
3
3
|
from typing import List
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
|
+
from pydantic import computed_field
|
|
6
7
|
from pydantic import validate_call
|
|
7
8
|
|
|
8
9
|
from ..base.content import IdInt
|
|
@@ -78,3 +79,12 @@ class ObserverTasks(ShpModel):
|
|
|
78
79
|
continue
|
|
79
80
|
tasks.append(task)
|
|
80
81
|
return tasks
|
|
82
|
+
|
|
83
|
+
@computed_field
|
|
84
|
+
def output_paths(self) -> dict:
|
|
85
|
+
values = {}
|
|
86
|
+
if isinstance(self.emulation, EmulationTask):
|
|
87
|
+
if self.emulation.output_path is None:
|
|
88
|
+
raise ValueError("Emu-Task should have a valid output-path")
|
|
89
|
+
values[self.observer] = self.emulation.output_path
|
|
90
|
+
return values
|
|
@@ -3,6 +3,7 @@ from typing import Optional
|
|
|
3
3
|
|
|
4
4
|
from pydantic import EmailStr
|
|
5
5
|
from pydantic import Field
|
|
6
|
+
from pydantic import computed_field
|
|
6
7
|
from pydantic import validate_call
|
|
7
8
|
from typing_extensions import Annotated
|
|
8
9
|
|
|
@@ -34,6 +35,13 @@ class TestbedTasks(ShpModel):
|
|
|
34
35
|
|
|
35
36
|
def get_observer_tasks(self, observer) -> Optional[ObserverTasks]:
|
|
36
37
|
for tasks in self.observer_tasks:
|
|
37
|
-
if observer
|
|
38
|
+
if observer == tasks.observer:
|
|
38
39
|
return tasks
|
|
39
40
|
return None
|
|
41
|
+
|
|
42
|
+
@computed_field
|
|
43
|
+
def output_paths(self) -> dict:
|
|
44
|
+
values = {}
|
|
45
|
+
for obt in self.observer_tasks:
|
|
46
|
+
values = {**values, **obt.output_paths}
|
|
47
|
+
return values
|
|
@@ -43,7 +43,7 @@ class Inventory(PythonInventory, SystemInventory, TargetInventory):
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
class InventoryList(ShpModel):
|
|
46
|
-
|
|
46
|
+
elements: Annotated[List[Inventory], Field(min_length=1)]
|
|
47
47
|
|
|
48
48
|
def to_csv(self, path: Path) -> None:
|
|
49
49
|
"""TODO: pretty messed up (raw lists and dicts for sub-elements)
|
|
@@ -53,8 +53,8 @@ class InventoryList(ShpModel):
|
|
|
53
53
|
if path.is_dir():
|
|
54
54
|
path = path / "inventory.yaml"
|
|
55
55
|
with open(path.as_posix(), "w") as fd:
|
|
56
|
-
fd.write(", ".join(self.
|
|
57
|
-
for item in self.
|
|
56
|
+
fd.write(", ".join(self.elements[0].model_dump().keys()) + "\r\n")
|
|
57
|
+
for item in self.elements:
|
|
58
58
|
content = list(item.model_dump().values())
|
|
59
59
|
content = ["" if value is None else str(value) for value in content]
|
|
60
60
|
fd.write(", ".join(content) + "\r\n")
|
|
@@ -65,10 +65,12 @@ class TestbedClient:
|
|
|
65
65
|
def insert(self, data: ShpModel) -> bool:
|
|
66
66
|
wrap = Wrapper(
|
|
67
67
|
datatype=type(data).__name__,
|
|
68
|
-
parameters=data.
|
|
68
|
+
parameters=data.model_dump(),
|
|
69
69
|
)
|
|
70
70
|
if self._connected:
|
|
71
|
-
r = self._req.post(
|
|
71
|
+
r = self._req.post(
|
|
72
|
+
self._server + "/add", data=wrap.model_dump_json(), timeout=2
|
|
73
|
+
)
|
|
72
74
|
r.raise_for_status()
|
|
73
75
|
else:
|
|
74
76
|
self._fixtures.insert_model(wrap)
|
|
@@ -49,11 +49,12 @@ class User(ShpModel):
|
|
|
49
49
|
email: EmailStr
|
|
50
50
|
|
|
51
51
|
pw_hash: Optional[SecretBytes] = None
|
|
52
|
-
# ⤷
|
|
52
|
+
# ⤷ was hash_password("this_will_become_a_salted_slow_hash") -> slowed BBB down
|
|
53
53
|
# ⤷ TODO (min_length=128, max_length=512)
|
|
54
54
|
|
|
55
55
|
token: SecretStr
|
|
56
56
|
# ⤷ TODO (min_length=128), request with: token.get_secret_value()
|
|
57
|
+
active: bool = False
|
|
57
58
|
|
|
58
59
|
@model_validator(mode="before")
|
|
59
60
|
@classmethod
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: shepherd-core
|
|
3
|
-
Version: 2023.8.
|
|
3
|
+
Version: 2023.8.8
|
|
4
4
|
Summary: Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed
|
|
5
5
|
Home-page: https://pypi.org/project/shepherd-core/
|
|
6
6
|
Author: Ingmar Splitt, Kai Geissdoerfer
|
|
@@ -100,6 +100,13 @@ The Library is available via PyPI and can be installed with
|
|
|
100
100
|
pip install shepherd-data
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
for bleeding-edge-features or dev-work it is possible to install directly from GitHub-Sources (here `dev`-branch):
|
|
104
|
+
|
|
105
|
+
```Shell
|
|
106
|
+
pip install git+https://github.com/orgua/shepherd-datalib.git@dev#subdirectory=shepherd_core -U
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
|
|
103
110
|
If you are working with ``.elf``-files (embedding into experiments) you make "objcopy" accessible to python. In Ubuntu, you can either install ``build-essential`` or ``binutils-$ARCH`` with arch being ``msp430`` or ``arm-none-eabi`` for the nRF52.
|
|
104
111
|
|
|
105
112
|
```shell
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
shepherd_core/__init__.py,sha256=
|
|
1
|
+
shepherd_core/__init__.py,sha256=N3fEX9mKsr5t5LinDVOe3aQVQth1MuFYuyfGa2l1rRY,1223
|
|
2
2
|
shepherd_core/calibration_hw_def.py,sha256=thaDBoY-nGJhxOLVLWUVWFBI_NX8EjnYcF1J2mMwqEQ,2160
|
|
3
3
|
shepherd_core/commons.py,sha256=8HLrOq30Zrgh0AcrtakJYyu3hwMgQks7mF7JyaBMcdw,170
|
|
4
4
|
shepherd_core/logger.py,sha256=2c6mbBW71dMddMDhll5_3ocgew6hj11uz8EnkQ4IpcU,1468
|
|
5
5
|
shepherd_core/reader.py,sha256=zOpdf9LQ6kcoercZ0olgIni3hzOIspWX5bF1hSXYdCE,20843
|
|
6
6
|
shepherd_core/writer.py,sha256=lSbE0JN8N0wRTCQF6rR0IpKtScdOqyflDBDngwj5gII,13910
|
|
7
|
-
shepherd_core/data_models/__init__.py,sha256=
|
|
7
|
+
shepherd_core/data_models/__init__.py,sha256=mem0m4nZY3EgG1ctBdGGGt128lhmglF9a4e5w9OGJu0,1651
|
|
8
8
|
shepherd_core/data_models/doc_virtual_source.py,sha256=rJ6uIF7sFF0YUa1LV-G0_XtjH_9gJEHzI4JFs_I_LvM,6616
|
|
9
9
|
shepherd_core/data_models/base/__init__.py,sha256=ugVEWXfYRCmK4o94RG4N_GKR7AbBQLfn5PCbEKVpZMU,44
|
|
10
|
-
shepherd_core/data_models/base/cal_measurement.py,sha256=
|
|
11
|
-
shepherd_core/data_models/base/calibration.py,sha256=
|
|
10
|
+
shepherd_core/data_models/base/cal_measurement.py,sha256=7liEZznO7Bx13-XYDh4c93uSDlgd0j4yQE1XaWJUBIw,2887
|
|
11
|
+
shepherd_core/data_models/base/calibration.py,sha256=DUQZfnx3csl5owlmUVsNHaP16xQQYI7WOPfTa-_FRws,9327
|
|
12
12
|
shepherd_core/data_models/base/content.py,sha256=H-PpGvIw_6iUcNtpy7JEVpjfh_eWncBoZ2mSzFNJ86o,1801
|
|
13
|
-
shepherd_core/data_models/base/shepherd.py,sha256=
|
|
13
|
+
shepherd_core/data_models/base/shepherd.py,sha256=4X5oQi_5VsuG3VCOlNT77KFv21X1rDeHo2EAYPvVvjM,4577
|
|
14
14
|
shepherd_core/data_models/base/wrapper.py,sha256=mzAMdX9-BeSAeTzlWKFnjj3v2wV6NJgaSHULFHEiWes,600
|
|
15
15
|
shepherd_core/data_models/content/__init__.py,sha256=6xQgeVaDgQzqwB69KJjPywt-utPu_222wiARRll_RP8,493
|
|
16
16
|
shepherd_core/data_models/content/energy_environment.py,sha256=t2W5ZxxhzdWSEtFyyF9iv1VkFqmBCAldOa5t6aEvZP8,1145
|
|
@@ -23,16 +23,16 @@ shepherd_core/data_models/content/virtual_harvester_fixture.yaml,sha256=UWlXq-7l
|
|
|
23
23
|
shepherd_core/data_models/content/virtual_source.py,sha256=lfVqiUnZCDaekTKaqAotJX4OIp2FsbyHJsm08pW1Suw,14226
|
|
24
24
|
shepherd_core/data_models/content/virtual_source_fixture.yaml,sha256=2PsWP3-xad5TycZ-OQn23WsJdYwq7_9_foC4wBFYmK0,10443
|
|
25
25
|
shepherd_core/data_models/experiment/__init__.py,sha256=DX9kylCe8zFm4PpVT8YS4csip7-MDoSrdah3nhBdiJE,651
|
|
26
|
-
shepherd_core/data_models/experiment/experiment.py,sha256=
|
|
27
|
-
shepherd_core/data_models/experiment/observer_features.py,sha256=
|
|
28
|
-
shepherd_core/data_models/experiment/target_config.py,sha256=
|
|
29
|
-
shepherd_core/data_models/task/__init__.py,sha256=
|
|
30
|
-
shepherd_core/data_models/task/emulation.py,sha256=
|
|
26
|
+
shepherd_core/data_models/experiment/experiment.py,sha256=v2aJab4mKhj7OfAEMn6I1iqIIXmE0yi7PtuVjDE-_V8,4100
|
|
27
|
+
shepherd_core/data_models/experiment/observer_features.py,sha256=UYDxNqf26XHp1MJi1wdwJx4GV3DVXAQfc9HPybfarOo,4798
|
|
28
|
+
shepherd_core/data_models/experiment/target_config.py,sha256=cth-zAIx7ngeMAmuJl5t2MiyVqdXj1dkRr3LFlMOY1k,3550
|
|
29
|
+
shepherd_core/data_models/task/__init__.py,sha256=QfKlAh6pTltiymWtT5hZ2lllz74paAqicqbXTB5TbJM,3168
|
|
30
|
+
shepherd_core/data_models/task/emulation.py,sha256=S8h9o2md5-txVL4Om-7co3GUgXJ6MC5OgW7rCtki37Y,6024
|
|
31
31
|
shepherd_core/data_models/task/firmware_mod.py,sha256=RbSrpZnqkRDwOnCSXetZsJBSkt6_aNC3IsLSCs0s0o8,2401
|
|
32
|
-
shepherd_core/data_models/task/harvest.py,sha256=
|
|
33
|
-
shepherd_core/data_models/task/observer_tasks.py,sha256=
|
|
32
|
+
shepherd_core/data_models/task/harvest.py,sha256=Vv0L_KyemJmrFmwd1iTiiKtZJPcf3WQOFGCRQ-pbmwg,3159
|
|
33
|
+
shepherd_core/data_models/task/observer_tasks.py,sha256=wq3YsTOSfxXDtg4Y9q-oTYk45FtqVEbw5HBHpvv0mjA,2994
|
|
34
34
|
shepherd_core/data_models/task/programming.py,sha256=x4AoaNYbNsbJF3Tpa7gdkw-935yuyRWCtLW39RBHVXA,1937
|
|
35
|
-
shepherd_core/data_models/task/testbed_tasks.py,sha256=
|
|
35
|
+
shepherd_core/data_models/task/testbed_tasks.py,sha256=41fOnggGwUt0ccX03jnAg3Akdt_6jQPVRS4gpqAGV9I,1499
|
|
36
36
|
shepherd_core/data_models/testbed/__init__.py,sha256=kQG0EUqJ5ylGRuwYZTbppWue9zDcSytpsHtUnohbGgA,566
|
|
37
37
|
shepherd_core/data_models/testbed/cape.py,sha256=Wxqkmcq4UZVRpIqQLBd0oEaSLPwsAfoa_TRwOpgpxEw,1123
|
|
38
38
|
shepherd_core/data_models/testbed/cape_fixture.yaml,sha256=ZrnNflXsr-krenSzAjTnFxPA4zcOnSiIO6hDo9o5Dt0,1451
|
|
@@ -53,14 +53,14 @@ shepherd_core/fw_tools/converter.py,sha256=Sm1iZo67Ukw1zS5IpcRobVTduJoh0EgHtPRPG
|
|
|
53
53
|
shepherd_core/fw_tools/converter_elf.py,sha256=hUORTkbTDA8RRVtM2ykKTrkQ3TrW9_zENIHv8Rhhp3E,992
|
|
54
54
|
shepherd_core/fw_tools/patcher.py,sha256=rkElnUHk-Uq0KEpbxy-zA5wP-ja88n9Jh0f4N_xIqtk,3670
|
|
55
55
|
shepherd_core/fw_tools/validation.py,sha256=if1EeWROw5j5PfwLulVhrXxdL5ycObk35IzyNpEHbRY,4200
|
|
56
|
-
shepherd_core/inventory/__init__.py,sha256=
|
|
56
|
+
shepherd_core/inventory/__init__.py,sha256=v-huLoj3z3k5KW_ubql7wir4yOYi4hjVK7iQjwuJXLw,1894
|
|
57
57
|
shepherd_core/inventory/python.py,sha256=LnvP9c-rWOe3552WXkl8FUL_V4k6IQ629PJDixWZplc,1064
|
|
58
58
|
shepherd_core/inventory/system.py,sha256=m87eMi6dee1xCWDsS_24fghWrkuwBUEIlulZFdRL_ZU,1929
|
|
59
59
|
shepherd_core/inventory/target.py,sha256=96jGYII8GUT429nXPGB0DE5iyrFSsislCpu5t2MJ0u4,362
|
|
60
60
|
shepherd_core/testbed_client/__init__.py,sha256=V38uxXOhwB8tlAjR0jH1MPSWB1LltwC0g8ipwaIyC9o,103
|
|
61
|
-
shepherd_core/testbed_client/client.py,sha256=
|
|
61
|
+
shepherd_core/testbed_client/client.py,sha256=fL3aYIqlRCHf_sTnHT983K9Th75EECGD8ED2FDhDImY,5327
|
|
62
62
|
shepherd_core/testbed_client/fixtures.py,sha256=O3iAbj6E8aJ1MzD2080ZwrOTGsZGgQs-85ZP_MMf7z4,8306
|
|
63
|
-
shepherd_core/testbed_client/user_model.py,sha256=
|
|
63
|
+
shepherd_core/testbed_client/user_model.py,sha256=HL-NP6YBhYLv_b-B6xeiA9q7A1zHsPT3YE5rqvc-S0g,1984
|
|
64
64
|
shepherd_core/vsource/__init__.py,sha256=x84_0M8Dg8R7DLKE5zyNAAGFiuOHPehDOWPt2KeBhKw,344
|
|
65
65
|
shepherd_core/vsource/virtual_converter_model.py,sha256=UBdiagp5YaIOMzpBqcwSDjheBC5tVHnmkPszvCLZe8M,10394
|
|
66
66
|
shepherd_core/vsource/virtual_harvester_model.py,sha256=Q_PfZlkrP2ugwvQ_a9W1JdBWVh9gkgj-jzBuyqgJLno,7783
|
|
@@ -74,9 +74,9 @@ tests/test_reader.py,sha256=ZTH6aYV7sw7F4VFg05WCu_tt_BueHInj6xlOO2voroY,9609
|
|
|
74
74
|
tests/test_writer.py,sha256=qQUIPjE-Spjx8LBSi0ZDYlHMh-eufDUY_4yQwR-gGHE,5278
|
|
75
75
|
tests/data_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
76
|
tests/data_models/conftest.py,sha256=5QMmrNqC3RGLhEvG8YifMMa28bnXdRXJtAAHWMEqpms,367
|
|
77
|
-
tests/data_models/example_cal_data.yaml,sha256=
|
|
77
|
+
tests/data_models/example_cal_data.yaml,sha256=61QrTWjvvI3phIoZsKKiw02thYPjZeY51a302Bl-wk4,785
|
|
78
78
|
tests/data_models/example_cal_data_faulty.yaml,sha256=BNR-Tuxc3jzBkNID28xsuSkLxZByw6FQLjbATG0GKUk,683
|
|
79
|
-
tests/data_models/example_cal_meas.yaml,sha256=
|
|
79
|
+
tests/data_models/example_cal_meas.yaml,sha256=GVgwDMjf0AvzU50ir4sn7ig6bI_xjNmi64gRDTkoyt0,5439
|
|
80
80
|
tests/data_models/example_cal_meas_faulty1.yaml,sha256=ojDt3jaiVfGFQ5N5RbomsKG1mDdLHrwiZPldkGrpA_U,4339
|
|
81
81
|
tests/data_models/example_cal_meas_faulty2.yaml,sha256=3qpcWfm9Q7uE_sOWmaRaj0eERIDnX0jY4cFNbgUaLUU,4172
|
|
82
82
|
tests/data_models/example_config_emulator.yaml,sha256=1yFbaHsM3Vy7DxuMhg0EYl_oJ-8Q4hwuQX0Un1vXsds,1259
|
|
@@ -85,7 +85,7 @@ tests/data_models/example_config_experiment_alternative.yaml,sha256=drCxtYp7Hilu
|
|
|
85
85
|
tests/data_models/example_config_harvester.yaml,sha256=B5gf55VzJax_Gn8isnXxVuWXim0KviMQfyz6FxEp82s,597
|
|
86
86
|
tests/data_models/example_config_testbed.yaml,sha256=ubN9dfvrMPxHQuWpqw_JkNHTxc4B9QjL2eDxkwwMnbc,470
|
|
87
87
|
tests/data_models/example_config_virtsource.yaml,sha256=zB9nGys728SzUrR4tO-e8ebr1vP8-Bgg7TsKISDnGrk,4415
|
|
88
|
-
tests/data_models/test_base_models.py,sha256=
|
|
88
|
+
tests/data_models/test_base_models.py,sha256=FF_z_-9KZj9QXFIU3O0S_X9wDtP8xSQ7l-32PmEblfc,6708
|
|
89
89
|
tests/data_models/test_content_fixtures.py,sha256=xcKe70_hL37Ae3LswaXZdY4YfOWqW_fj_JVb-95Qnqo,1701
|
|
90
90
|
tests/data_models/test_content_models.py,sha256=87TFxiu8m35CTOvE4MoYHhKLZ0T1p4JVE_hvHk9_OyE,7306
|
|
91
91
|
tests/data_models/test_examples.py,sha256=yiiPZCjFQ4oBZCiIGmR3XOyU9qEAiFqncmO33LbbPNU,1420
|
|
@@ -102,15 +102,15 @@ tests/fw_tools/test_converter.py,sha256=mKUpgNmjeOKhyBF9c3bsJ4D_YczSHaxvnejX547o
|
|
|
102
102
|
tests/fw_tools/test_patcher.py,sha256=ZDCYygjia7U71qzImxvBHGuuNWwbzAMTroYGQmxNxk4,2044
|
|
103
103
|
tests/fw_tools/test_validation.py,sha256=6a-qS_lb4qs7iZmGwnHzR_Rbm4MD_2GQwvGW2pqOo1o,1721
|
|
104
104
|
tests/inventory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
105
|
-
tests/inventory/test_inventory.py,sha256
|
|
105
|
+
tests/inventory/test_inventory.py,sha256=-B3edajduBnQtr_lcd96ybU9tKK50ms5s0w2FQn3P-Q,645
|
|
106
106
|
tests/testbed_client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
107
107
|
tests/vsource/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
108
108
|
tests/vsource/conftest.py,sha256=yV-dYtslkTVssjXFHWzAkYge1lBzxNbewcwaermXsR8,1364
|
|
109
109
|
tests/vsource/test_converter.py,sha256=HWm1Mqe-jZn_gyGz-nHvrZtRxv4uME8j4zAkFnyQIdw,5163
|
|
110
110
|
tests/vsource/test_harvester.py,sha256=_SFA22rd1rIeqD01ayN_EwREyb7PGknnJu_AZJcC2b0,2532
|
|
111
111
|
tests/vsource/test_z.py,sha256=bbMUuOhfLJHwW2l4PEqj0giaWECJPNGu1ERVywqkdvA,57
|
|
112
|
-
shepherd_core-2023.8.
|
|
113
|
-
shepherd_core-2023.8.
|
|
114
|
-
shepherd_core-2023.8.
|
|
115
|
-
shepherd_core-2023.8.
|
|
116
|
-
shepherd_core-2023.8.
|
|
112
|
+
shepherd_core-2023.8.8.dist-info/METADATA,sha256=gioq8iFuAJOHlR-z1CVddu3jCqEWMZY0w3_AFx9BIJY,4539
|
|
113
|
+
shepherd_core-2023.8.8.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
114
|
+
shepherd_core-2023.8.8.dist-info/top_level.txt,sha256=6H9zsX2PNWwILI7EJu8fNam1KfG2Sqvkez-jlwrD9SE,20
|
|
115
|
+
shepherd_core-2023.8.8.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
116
|
+
shepherd_core-2023.8.8.dist-info/RECORD,,
|
|
@@ -11,9 +11,19 @@ from shepherd_core.data_models.base.calibration import CalibrationEmulator
|
|
|
11
11
|
from shepherd_core.data_models.base.calibration import CalibrationHarvester
|
|
12
12
|
from shepherd_core.data_models.base.calibration import CalibrationPair
|
|
13
13
|
from shepherd_core.data_models.base.calibration import CalibrationSeries
|
|
14
|
+
from shepherd_core.data_models.base.calibration import CapeData
|
|
14
15
|
from shepherd_core.data_models.base.content import ContentModel
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
def test_base_model_cape_data() -> None:
|
|
19
|
+
CapeData(serial_number="xyz1")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_base_model_cape_data_fail() -> None:
|
|
23
|
+
with pytest.raises(ValueError):
|
|
24
|
+
CapeData()
|
|
25
|
+
|
|
26
|
+
|
|
17
27
|
def test_base_model_cal_pair_conv() -> None:
|
|
18
28
|
cal = CalibrationPair(gain=4.9)
|
|
19
29
|
val_raw = 500
|
|
@@ -61,6 +71,13 @@ def test_base_model_cal_cape_bytestr() -> None:
|
|
|
61
71
|
assert cal1.get_hash() == cal2.get_hash()
|
|
62
72
|
|
|
63
73
|
|
|
74
|
+
def test_base_model_cal_cape_bytestr_with_cape_data() -> None:
|
|
75
|
+
cal1 = CalibrationCape(cape=CapeData(serial_number="123"))
|
|
76
|
+
cb = cal1.to_bytestr()
|
|
77
|
+
cal2 = CalibrationCape.from_bytestr(cb, cal1.cape)
|
|
78
|
+
assert cal1.get_hash() == cal2.get_hash()
|
|
79
|
+
|
|
80
|
+
|
|
64
81
|
def test_base_model_cal_cape_example(tmp_path: Path) -> None:
|
|
65
82
|
cal0 = CalMeasurementCape()
|
|
66
83
|
path1 = Path(__file__).resolve().with_name("example_cal_data.yaml")
|
|
File without changes
|
|
File without changes
|