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 CHANGED
@@ -21,7 +21,7 @@ from .testbed_client.client import TestbedClient
21
21
  from .testbed_client.client import tb_client
22
22
  from .writer import BaseWriter
23
23
 
24
- __version__ = "2023.8.7"
24
+ __version__ = "2023.8.8"
25
25
 
26
26
  __all__ = [
27
27
  "BaseReader",
@@ -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
- ] # TODO: for pydantic 2 add @classmethod after @root_validator for cleaner type-checking
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.dict(),
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
- raise ValueError(
61
- "Task-Set contained TestbedTasks -> FN needs a observer-name"
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.dict(),
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
- if has_time and self.time_start < datetime.now().astimezone():
108
- raise ValueError("Start-Time for Emulation can't be in the past.")
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
- if has_time and self.time_start < datetime.now().astimezone():
71
- raise ValueError("Start-Time for Harvest can't be in the past.")
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 in tasks.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
- items: Annotated[List[Inventory], Field(min_length=1)]
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.items[0].model_dump().keys()) + "\r\n")
57
- for item in self.items:
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.dict(),
68
+ parameters=data.model_dump(),
69
69
  )
70
70
  if self._connected:
71
- r = self._req.post(self._server + "/add", data=wrap.json(), timeout=2)
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
- # ⤷ = hash_password("this_will_become_a_salted_slow_hash") -> slowed BBB down
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.7
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=0GzXNOw-IO838nMkft6LOrgv1j0PlotarZc_SKCculE,1223
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=Cda-ThRlCdTrgjncMjA3XyAdELwEchXwqzHaK7P4IZU,1685
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=XP8ZNZMfWWo-bqQug3RAQgLjjAaMnMmNs1dEXEDlF80,2848
11
- shepherd_core/data_models/base/calibration.py,sha256=zP99Mw4hVdC_x3EIwIgyOI0wg_FxhemOTgcbtVVC8r4,8099
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=lZxxX6bAA3NTr5v6ShZ-vjmTgpPolO9NjdYVXJ2XQ0o,4379
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=NPDON6gB2O87cyygMEjP_dWY3-YsmDqkQO4-kFAEMkE,4029
27
- shepherd_core/data_models/experiment/observer_features.py,sha256=TExJkL-qV9erezYnyi0ssAS4XdZd_rUVvZqkZZysVNg,4781
28
- shepherd_core/data_models/experiment/target_config.py,sha256=UYVm0fGnLWEQ3k60Qfdv_jJm1ThWKo9biHhtO0ECyq4,3518
29
- shepherd_core/data_models/task/__init__.py,sha256=vS4FonMO95F0jHRQt6IavNhXp0yqHQjvFyp7BFm6PsE,2807
30
- shepherd_core/data_models/task/emulation.py,sha256=6Si-nn3L5DRCI0LltO-X7LAaUglQIEYv3CNCyUAyHtg,5740
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=q7NktHhE4ifqr6-_jVGRGY3tjgcG6jRMRB6P31vtXjA,2852
33
- shepherd_core/data_models/task/observer_tasks.py,sha256=B-gv_0ualfqom8_u06-17uI9VBWBMf_CitwBBhRfl14,2614
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=LvEvd65tv_OCU2HmOPP9eT6VZiinEtlZSK-Nt2T9LVY,1272
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=pbE2AgTBBy8HNeQCiIZnoJmgyVcjbnjGnJj1pyRLqPk,1885
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=DCC59uVCX7ZWqpZiZtaWlgfFZBmrLfdANMel1fSa2Y4,5280
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=9DIWQXxX3MXvH2OpTbjpOp8rCu-zG_h2YH8fBBuRTSQ,1957
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=0c9ysKRyVCbs_kQ4wKeaH0jme8XCOGW6lyN324RUrXM,766
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=QLXIxdXvi8RTTFYHHhwbZjZrEmkWgIshuCRHeSB5BkQ,5420
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=bI207HDmYotUi2AKmbd3kUtCpiwr5Z-l6LrJ-0pnq_w,6207
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=waWfXQ4I5Q2GsUlGn3GUnDtbbO7jpUMb4R7r6d8IVmI,642
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.7.dist-info/METADATA,sha256=b48n4dwfW8TjB7GW7aO9_L70_g7OpZIFSJNe3q-IJlU,4312
113
- shepherd_core-2023.8.7.dist-info/WHEEL,sha256=5sUXSg9e4bi7lTLOHcm6QEYwO5TIF1TNbTSVFVjcJcc,92
114
- shepherd_core-2023.8.7.dist-info/top_level.txt,sha256=6H9zsX2PNWwILI7EJu8fNam1KfG2Sqvkez-jlwrD9SE,20
115
- shepherd_core-2023.8.7.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
116
- shepherd_core-2023.8.7.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.1)
2
+ Generator: bdist_wheel (0.41.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,7 +1,8 @@
1
1
  datatype: CalibrationCape
2
2
  parameters:
3
3
  host: sheep0
4
- cape: xyz1
4
+ cape:
5
+ serial_number: A123
5
6
  emulator:
6
7
  adc_C_A:
7
8
  gain: 2.2306053900482405e-07
@@ -2,7 +2,8 @@
2
2
  datatype: CalMeasurementCape
3
3
  parameters:
4
4
  host: sheep0
5
- cape: xyz1
5
+ cape:
6
+ serial_number: A123
6
7
  emulator:
7
8
  adc_C_A:
8
9
  - reference_si: 1.0e-05
@@ -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")
@@ -19,5 +19,5 @@ def test_collect_data(inv: Callable) -> None:
19
19
 
20
20
  def test_inventorize(tmp_path: Path) -> None:
21
21
  inv = Inventory.collect()
22
- inl = InventoryList(items=[inv])
22
+ inl = InventoryList(elements=[inv])
23
23
  inl.to_csv(tmp_path / "some.csv")