shepherd-core 2023.8.7__tar.gz → 2023.8.8__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.
Files changed (121) hide show
  1. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/PKG-INFO +8 -1
  2. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/README.md +7 -0
  3. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/__init__.py +1 -1
  4. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/__init__.py +3 -1
  5. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/base/cal_measurement.py +4 -3
  6. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/base/calibration.py +37 -4
  7. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/base/shepherd.py +9 -0
  8. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/experiment/experiment.py +1 -0
  9. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/experiment/observer_features.py +1 -1
  10. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/experiment/target_config.py +1 -0
  11. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/task/__init__.py +13 -5
  12. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/task/emulation.py +10 -4
  13. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/task/harvest.py +9 -3
  14. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/task/observer_tasks.py +10 -0
  15. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/task/testbed_tasks.py +9 -1
  16. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/inventory/__init__.py +3 -3
  17. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/testbed_client/client.py +4 -2
  18. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/testbed_client/user_model.py +2 -1
  19. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core.egg-info/PKG-INFO +8 -1
  20. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_cal_data.yaml +2 -1
  21. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_cal_meas.yaml +2 -1
  22. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/test_base_models.py +17 -0
  23. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/inventory/test_inventory.py +1 -1
  24. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/pyproject.toml +0 -0
  25. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/setup.cfg +0 -0
  26. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/calibration_hw_def.py +0 -0
  27. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/commons.py +0 -0
  28. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/base/__init__.py +0 -0
  29. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/base/content.py +0 -0
  30. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/base/wrapper.py +0 -0
  31. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/content/__init__.py +0 -0
  32. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/content/energy_environment.py +0 -0
  33. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/content/energy_environment_fixture.yaml +0 -0
  34. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/content/firmware.py +0 -0
  35. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/content/firmware_datatype.py +0 -0
  36. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/content/firmware_fixture.yaml +0 -0
  37. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/content/virtual_harvester.py +0 -0
  38. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/content/virtual_harvester_fixture.yaml +0 -0
  39. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/content/virtual_source.py +0 -0
  40. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/content/virtual_source_fixture.yaml +0 -0
  41. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/doc_virtual_source.py +0 -0
  42. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/experiment/__init__.py +0 -0
  43. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/task/firmware_mod.py +0 -0
  44. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/task/programming.py +0 -0
  45. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/__init__.py +0 -0
  46. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/cape.py +0 -0
  47. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/cape_fixture.yaml +0 -0
  48. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/gpio.py +0 -0
  49. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/gpio_fixture.yaml +0 -0
  50. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/mcu.py +0 -0
  51. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/mcu_fixture.yaml +0 -0
  52. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/observer.py +0 -0
  53. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/observer_fixture.yaml +0 -0
  54. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/target.py +0 -0
  55. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/target_fixture.yaml +0 -0
  56. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/testbed.py +0 -0
  57. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/data_models/testbed/testbed_fixture.yaml +0 -0
  58. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/decoder_waveform/__init__.py +0 -0
  59. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/decoder_waveform/uart.py +0 -0
  60. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/fw_tools/__init__.py +0 -0
  61. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/fw_tools/converter.py +0 -0
  62. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/fw_tools/converter_elf.py +0 -0
  63. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/fw_tools/patcher.py +0 -0
  64. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/fw_tools/validation.py +0 -0
  65. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/inventory/python.py +0 -0
  66. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/inventory/system.py +0 -0
  67. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/inventory/target.py +0 -0
  68. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/logger.py +0 -0
  69. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/reader.py +0 -0
  70. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/testbed_client/__init__.py +0 -0
  71. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/testbed_client/fixtures.py +0 -0
  72. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/vsource/__init__.py +0 -0
  73. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/vsource/virtual_converter_model.py +0 -0
  74. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/vsource/virtual_harvester_model.py +0 -0
  75. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/vsource/virtual_source_model.py +0 -0
  76. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core/writer.py +0 -0
  77. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core.egg-info/SOURCES.txt +0 -0
  78. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core.egg-info/dependency_links.txt +0 -0
  79. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core.egg-info/requires.txt +0 -0
  80. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core.egg-info/top_level.txt +0 -0
  81. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/shepherd_core.egg-info/zip-safe +0 -0
  82. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/__init__.py +0 -0
  83. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/conftest.py +0 -0
  84. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/__init__.py +0 -0
  85. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/conftest.py +0 -0
  86. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_cal_data_faulty.yaml +0 -0
  87. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_cal_meas_faulty1.yaml +0 -0
  88. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_cal_meas_faulty2.yaml +0 -0
  89. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_config_emulator.yaml +0 -0
  90. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_config_experiment.yaml +0 -0
  91. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_config_experiment_alternative.yaml +0 -0
  92. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_config_harvester.yaml +0 -0
  93. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_config_testbed.yaml +0 -0
  94. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/example_config_virtsource.yaml +0 -0
  95. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/test_content_fixtures.py +0 -0
  96. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/test_content_models.py +0 -0
  97. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/test_examples.py +0 -0
  98. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/test_experiment_models.py +0 -0
  99. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/test_task_generation.py +0 -0
  100. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/test_task_models.py +0 -0
  101. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/test_testbed_fixtures.py +0 -0
  102. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/data_models/test_testbed_models.py +0 -0
  103. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/decoder_waveform/__init__.py +0 -0
  104. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/decoder_waveform/test_decoder.py +0 -0
  105. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/fw_tools/__init__.py +0 -0
  106. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/fw_tools/conftest.py +0 -0
  107. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/fw_tools/test_converter.py +0 -0
  108. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/fw_tools/test_patcher.py +0 -0
  109. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/fw_tools/test_validation.py +0 -0
  110. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/inventory/__init__.py +0 -0
  111. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/test_cal_hw.py +0 -0
  112. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/test_examples.py +0 -0
  113. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/test_logger.py +0 -0
  114. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/test_reader.py +0 -0
  115. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/test_writer.py +0 -0
  116. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/testbed_client/__init__.py +0 -0
  117. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/vsource/__init__.py +0 -0
  118. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/vsource/conftest.py +0 -0
  119. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/vsource/test_converter.py +0 -0
  120. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/vsource/test_harvester.py +0 -0
  121. {shepherd_core-2023.8.7 → shepherd_core-2023.8.8}/tests/vsource/test_z.py +0 -0
@@ -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
@@ -77,6 +77,13 @@ The Library is available via PyPI and can be installed with
77
77
  pip install shepherd-data
78
78
  ```
79
79
 
80
+ for bleeding-edge-features or dev-work it is possible to install directly from GitHub-Sources (here `dev`-branch):
81
+
82
+ ```Shell
83
+ pip install git+https://github.com/orgua/shepherd-datalib.git@dev#subdirectory=shepherd_core -U
84
+ ```
85
+
86
+
80
87
  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.
81
88
 
82
89
  ```shell
@@ -40,6 +40,13 @@ The Library is available via PyPI and can be installed with
40
40
  pip install shepherd-data
41
41
  ```
42
42
 
43
+ for bleeding-edge-features or dev-work it is possible to install directly from GitHub-Sources (here `dev`-branch):
44
+
45
+ ```Shell
46
+ pip install git+https://github.com/orgua/shepherd-datalib.git@dev#subdirectory=shepherd_core -U
47
+ ```
48
+
49
+
43
50
  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.
44
51
 
45
52
  ```shell
@@ -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
@@ -77,6 +77,13 @@ The Library is available via PyPI and can be installed with
77
77
  pip install shepherd-data
78
78
  ```
79
79
 
80
+ for bleeding-edge-features or dev-work it is possible to install directly from GitHub-Sources (here `dev`-branch):
81
+
82
+ ```Shell
83
+ pip install git+https://github.com/orgua/shepherd-datalib.git@dev#subdirectory=shepherd_core -U
84
+ ```
85
+
86
+
80
87
  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.
81
88
 
82
89
  ```shell
@@ -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")