shepherd-core 2025.6.3__tar.gz → 2025.6.4__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 (147) hide show
  1. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/PKG-INFO +2 -3
  2. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/experiment_from_yaml.yaml +0 -1
  3. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/experiment_generic_var1.py +0 -1
  4. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/experiment_generic_var2.py +0 -1
  5. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/experiment_models.py +0 -1
  6. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/pyproject.toml +2 -3
  7. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/base/cal_measurement.py +4 -5
  8. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/base/calibration.py +8 -10
  9. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/base/content.py +2 -3
  10. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/base/shepherd.py +6 -8
  11. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/base/wrapper.py +3 -4
  12. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/content/energy_environment.py +4 -5
  13. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/content/firmware.py +3 -5
  14. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/content/virtual_harvester.py +5 -6
  15. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/experiment/experiment.py +9 -17
  16. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/experiment/observer_features.py +15 -37
  17. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/experiment/target_config.py +10 -11
  18. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/task/__init__.py +1 -3
  19. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/task/emulation.py +10 -14
  20. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/task/firmware_mod.py +2 -4
  21. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/task/harvest.py +4 -7
  22. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/task/observer_tasks.py +7 -8
  23. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/task/programming.py +1 -2
  24. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/task/testbed_tasks.py +2 -9
  25. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/cape.py +3 -5
  26. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/gpio.py +7 -8
  27. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/mcu.py +1 -2
  28. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/observer.py +5 -6
  29. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/target.py +4 -6
  30. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/testbed.py +2 -3
  31. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/decoder_waveform/uart.py +11 -13
  32. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/fw_tools/converter.py +1 -2
  33. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/fw_tools/converter_elf.py +1 -2
  34. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/fw_tools/patcher.py +5 -6
  35. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/inventory/python.py +8 -9
  36. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/inventory/system.py +1 -2
  37. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/inventory/target.py +1 -2
  38. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/logger.py +1 -2
  39. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/reader.py +18 -23
  40. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/testbed_client/client_abc_fix.py +2 -7
  41. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/testbed_client/client_web.py +5 -9
  42. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/testbed_client/fixtures.py +3 -5
  43. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/testbed_client/user_model.py +4 -5
  44. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/version.py +1 -1
  45. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/vsource/virtual_converter_model.py +1 -2
  46. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/vsource/virtual_harvester_simulation.py +1 -2
  47. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/vsource/virtual_source_model.py +3 -5
  48. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/vsource/virtual_source_simulation.py +1 -2
  49. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/writer.py +12 -14
  50. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core.egg-info/PKG-INFO +2 -3
  51. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_config_experiment.yaml +0 -2
  52. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_config_experiment_alternative.yaml +0 -2
  53. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/test_experiment_models.py +12 -10
  54. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/test_task_generation.py +0 -1
  55. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/test_task_models.py +2 -4
  56. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/test_cal_hw.py +1 -1
  57. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/test_writer.py +6 -8
  58. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/vsource/test_converter.py +2 -3
  59. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/README.md +0 -0
  60. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/eenv_generator.py +0 -0
  61. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/firmware_model.py +0 -0
  62. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/firmware_modification.py +0 -0
  63. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/inventory.py +0 -0
  64. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/simulate_vharvester.py +0 -0
  65. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/simulate_vsource.py +0 -0
  66. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/uart_decode_waveform.py +0 -0
  67. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/uart_raw2.csv +0 -0
  68. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/examples/vsource_debug_sim.py +0 -0
  69. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/setup.cfg +0 -0
  70. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/__init__.py +0 -0
  71. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/calibration_hw_def.py +0 -0
  72. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/commons.py +0 -0
  73. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/config.py +0 -0
  74. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/__init__.py +0 -0
  75. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/base/__init__.py +0 -0
  76. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/base/timezone.py +0 -0
  77. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/content/__init__.py +0 -0
  78. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/content/_external_fixtures.yaml +0 -0
  79. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/content/energy_environment_fixture.yaml +0 -0
  80. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/content/firmware_datatype.py +0 -0
  81. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/content/virtual_harvester_fixture.yaml +0 -0
  82. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/content/virtual_source.py +0 -0
  83. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/content/virtual_source_fixture.yaml +0 -0
  84. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/experiment/__init__.py +0 -0
  85. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/readme.md +0 -0
  86. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/task/helper_paths.py +0 -0
  87. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/__init__.py +0 -0
  88. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/cape_fixture.yaml +0 -0
  89. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/gpio_fixture.yaml +0 -0
  90. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/mcu_fixture.yaml +0 -0
  91. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/observer_fixture.yaml +0 -0
  92. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/target_fixture.old1 +0 -0
  93. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/target_fixture.yaml +0 -0
  94. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/testbed/testbed_fixture.yaml +0 -0
  95. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/data_models/virtual_source_doc.txt +0 -0
  96. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/decoder_waveform/__init__.py +0 -0
  97. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/fw_tools/__init__.py +0 -0
  98. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/fw_tools/validation.py +0 -0
  99. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/inventory/__init__.py +0 -0
  100. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/testbed_client/__init__.py +0 -0
  101. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/testbed_client/cache_path.py +0 -0
  102. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/vsource/__init__.py +0 -0
  103. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/vsource/target_model.py +0 -0
  104. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core/vsource/virtual_harvester_model.py +0 -0
  105. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core.egg-info/SOURCES.txt +0 -0
  106. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core.egg-info/dependency_links.txt +0 -0
  107. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core.egg-info/requires.txt +0 -0
  108. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core.egg-info/top_level.txt +0 -0
  109. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/shepherd_core.egg-info/zip-safe +0 -0
  110. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/__init__.py +0 -0
  111. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/conftest.py +0 -0
  112. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/__init__.py +0 -0
  113. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/conftest.py +0 -0
  114. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_cal_data.yaml +0 -0
  115. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_cal_data_faulty.yaml +0 -0
  116. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_cal_meas.yaml +0 -0
  117. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_cal_meas_faulty1.yaml +0 -0
  118. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_cal_meas_faulty2.yaml +0 -0
  119. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_config_emulator.yaml +0 -0
  120. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_config_harvester.yaml +0 -0
  121. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_config_testbed.yaml +0 -0
  122. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/example_config_virtsource.yaml +0 -0
  123. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/test_base_models.py +0 -0
  124. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/test_content_fixtures.py +0 -0
  125. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/test_content_models.py +0 -0
  126. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/test_examples.py +0 -0
  127. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/test_testbed_fixtures.py +0 -0
  128. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/data_models/test_testbed_models.py +0 -0
  129. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/decoder_waveform/__init__.py +0 -0
  130. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/decoder_waveform/test_decoder.py +0 -0
  131. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/fw_tools/__init__.py +0 -0
  132. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/fw_tools/build_msp.elf +0 -0
  133. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/fw_tools/build_nrf.elf +0 -0
  134. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/fw_tools/conftest.py +0 -0
  135. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/fw_tools/test_converter.py +0 -0
  136. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/fw_tools/test_patcher.py +0 -0
  137. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/fw_tools/test_validation.py +0 -0
  138. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/inventory/__init__.py +0 -0
  139. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/inventory/test_inventory.py +0 -0
  140. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/test_examples.py +0 -0
  141. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/test_logger.py +0 -0
  142. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/test_reader.py +0 -0
  143. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/testbed_client/__init__.py +0 -0
  144. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/vsource/__init__.py +0 -0
  145. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/vsource/conftest.py +0 -0
  146. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/vsource/test_harvester.py +0 -0
  147. {shepherd_core-2025.6.3 → shepherd_core-2025.6.4}/tests/vsource/test_z.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shepherd_core
3
- Version: 2025.6.3
3
+ Version: 2025.6.4
4
4
  Summary: Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed
5
5
  Author-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
6
6
  Maintainer-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
@@ -18,7 +18,6 @@ Classifier: Development Status :: 5 - Production/Stable
18
18
  Classifier: Intended Audience :: Developers
19
19
  Classifier: Intended Audience :: Information Technology
20
20
  Classifier: Intended Audience :: Science/Research
21
- Classifier: Programming Language :: Python :: 3.9
22
21
  Classifier: Programming Language :: Python :: 3.10
23
22
  Classifier: Programming Language :: Python :: 3.11
24
23
  Classifier: Programming Language :: Python :: 3.12
@@ -26,7 +25,7 @@ Classifier: Programming Language :: Python :: 3.13
26
25
  Classifier: License :: OSI Approved :: MIT License
27
26
  Classifier: Operating System :: OS Independent
28
27
  Classifier: Natural Language :: English
29
- Requires-Python: >=3.9
28
+ Requires-Python: >=3.10
30
29
  Description-Content-Type: text/markdown
31
30
  Requires-Dist: h5py
32
31
  Requires-Dist: numpy
@@ -1,6 +1,5 @@
1
1
  datatype: Experiment
2
2
  parameters:
3
- id: 4567
4
3
  name: meaningful Test-Name
5
4
  time_start: 2033-03-13 14:15:16
6
5
  target_configs:
@@ -30,7 +30,6 @@ if do_connect:
30
30
  WebClient()
31
31
 
32
32
  xp = sm.Experiment(
33
- id="4567",
34
33
  name="meaningful_TestName",
35
34
  # time_start could be "2033-03-13 14:15:16" or "datetime.now() + timedelta(minutes=30)"
36
35
  duration=30,
@@ -28,7 +28,6 @@ if do_connect:
28
28
  WebClient()
29
29
 
30
30
  xp = sm.Experiment(
31
- id="4567",
32
31
  name="meaningful_TestName",
33
32
  # time_start could be "2033-03-13 14:15:16" or "datetime.now() + timedelta(minutes=30)"
34
33
  duration=30,
@@ -58,7 +58,6 @@ target_cfgs = [
58
58
  ]
59
59
 
60
60
  xperi1 = sm.Experiment(
61
- id="4567",
62
61
  name="meaningful Test-Name",
63
62
  time_start="2033-03-13 14:15:16", # or: datetime.now() + timedelta(minutes=30)
64
63
  target_configs=target_cfgs,
@@ -14,7 +14,6 @@ classifiers = [
14
14
  "Intended Audience :: Developers",
15
15
  "Intended Audience :: Information Technology",
16
16
  "Intended Audience :: Science/Research",
17
- "Programming Language :: Python :: 3.9",
18
17
  "Programming Language :: Python :: 3.10",
19
18
  "Programming Language :: Python :: 3.11",
20
19
  "Programming Language :: Python :: 3.12",
@@ -24,7 +23,7 @@ classifiers = [
24
23
  "Natural Language :: English",
25
24
  ]
26
25
 
27
- requires-python = ">=3.9"
26
+ requires-python = ">=3.10"
28
27
  dependencies = [
29
28
  "h5py",
30
29
  "numpy",
@@ -110,7 +109,7 @@ source = ["shepherd_core"]
110
109
  omit = ["*/shepherd_data/*"]
111
110
 
112
111
  [tool.mypy]
113
- python_version = 3.9
112
+ python_version = 3.10
114
113
  ignore_missing_imports = true
115
114
  disable_error_code = ["call-arg", ]
116
115
  exclude = [
@@ -1,7 +1,6 @@
1
1
  """Models for the process of calibration a device by measurements."""
2
2
 
3
3
  from typing import Annotated
4
- from typing import Optional
5
4
 
6
5
  import numpy as np
7
6
  from pydantic import Field
@@ -91,11 +90,11 @@ class CalMeasurementEmulator(ShpModel):
91
90
  class CalMeasurementCape(ShpModel):
92
91
  """Container for the values of the calibration-measurement."""
93
92
 
94
- cape: Optional[CapeData] = None
95
- host: Optional[str] = None
93
+ cape: CapeData | None = None
94
+ host: str | None = None
96
95
 
97
- harvester: Optional[CalMeasurementHarvester] = None
98
- emulator: Optional[CalMeasurementEmulator] = None
96
+ harvester: CalMeasurementHarvester | None = None
97
+ emulator: CalMeasurementEmulator | None = None
99
98
 
100
99
  def to_cal(self) -> CalibrationCape:
101
100
  dv = self.model_dump()
@@ -1,13 +1,11 @@
1
1
  """Models for the calibration-data to convert between raw & SI-Values."""
2
2
 
3
3
  import struct
4
+ from collections.abc import Callable
4
5
  from collections.abc import Generator
5
6
  from collections.abc import Mapping
6
7
  from collections.abc import Sequence
7
- from typing import Callable
8
- from typing import Optional
9
8
  from typing import TypeVar
10
- from typing import Union
11
9
 
12
10
  import numpy as np
13
11
  from numpy.typing import NDArray
@@ -29,7 +27,7 @@ Calc_t = TypeVar("Calc_t", NDArray[np.float64], float)
29
27
 
30
28
 
31
29
  def dict_generator(
32
- in_dict: Union[Mapping, Sequence], pre: Optional[list] = None
30
+ in_dict: Mapping | Sequence, pre: list | None = None
33
31
  ) -> Generator[list, None, None]:
34
32
  """Recursive helper-function to generate a 1D-List(or not?).
35
33
 
@@ -54,7 +52,7 @@ class CalibrationPair(ShpModel):
54
52
 
55
53
  gain: PositiveFloat
56
54
  offset: float = 0
57
- unit: Optional[str] = None # TODO: add units when used
55
+ unit: str | None = None # TODO: add units when used
58
56
 
59
57
  def raw_to_si(self, values_raw: Calc_t, *, allow_negative: bool = True) -> Calc_t:
60
58
  """Convert between physical units and raw unsigned integers."""
@@ -81,7 +79,7 @@ class CalibrationPair(ShpModel):
81
79
  return values_raw
82
80
 
83
81
  @classmethod
84
- def from_fn(cls, fn: Callable, unit: Optional[str] = None) -> Self:
82
+ def from_fn(cls, fn: Callable, unit: str | None = None) -> Self:
85
83
  """Probe linear function to determine scaling values."""
86
84
  offset = fn(0, limited=False)
87
85
  gain_inv = fn(1.0, limited=False) - offset
@@ -217,14 +215,14 @@ class CalibrationCape(ShpModel):
217
215
  YAML: .to_file() and .from_file() already in ShpModel
218
216
  """
219
217
 
220
- cape: Optional[CapeData] = None
221
- host: Optional[str] = None
218
+ cape: CapeData | None = None
219
+ host: str | None = None
222
220
 
223
221
  harvester: CalibrationHarvester = CalibrationHarvester()
224
222
  emulator: CalibrationEmulator = CalibrationEmulator()
225
223
 
226
224
  @classmethod
227
- def from_bytestr(cls, data: bytes, cape: Optional[CapeData] = None) -> Self:
225
+ def from_bytestr(cls, data: bytes, cape: CapeData | None = None) -> Self:
228
226
  """Instantiate calibration data based on byte string.
229
227
 
230
228
  This is mainly used to deserialize data read from an EEPROM memory.
@@ -276,7 +274,7 @@ class CalibrationSeries(ShpModel):
276
274
  @validate_call(validate_return=False)
277
275
  def from_cal(
278
276
  cls,
279
- cal: Union[CalibrationHarvester, CalibrationEmulator],
277
+ cal: CalibrationHarvester | CalibrationEmulator,
280
278
  *,
281
279
  emu_port_a: bool = True,
282
280
  ) -> Self:
@@ -2,7 +2,6 @@
2
2
 
3
3
  from datetime import datetime
4
4
  from typing import Annotated
5
- from typing import Optional
6
5
  from uuid import uuid4
7
6
 
8
7
  from pydantic import Field
@@ -37,8 +36,8 @@ class ContentModel(ShpModel):
37
36
  default_factory=id_default,
38
37
  )
39
38
  name: NameStr
40
- description: Annotated[Optional[SafeStr], Field(description="Required when public")] = None
41
- comment: Optional[SafeStr] = None
39
+ description: Annotated[SafeStr | None, Field(description="Required when public")] = None
40
+ comment: SafeStr | None = None
42
41
  created: datetime = Field(default_factory=datetime.now)
43
42
  updated_last: datetime = Field(default_factory=datetime.now)
44
43
 
@@ -8,8 +8,6 @@ from datetime import timedelta
8
8
  from ipaddress import IPv4Address
9
9
  from pathlib import Path
10
10
  from typing import Any
11
- from typing import Optional
12
- from typing import Union
13
11
  from uuid import UUID
14
12
 
15
13
  import yaml
@@ -24,7 +22,7 @@ from .wrapper import Wrapper
24
22
 
25
23
 
26
24
  def path2str(
27
- dumper: SafeDumper, data: Union[pathlib.Path, pathlib.WindowsPath, pathlib.PosixPath]
25
+ dumper: SafeDumper, data: pathlib.Path | pathlib.WindowsPath | pathlib.PosixPath
28
26
  ) -> Node:
29
27
  """Add a yaml-representation for a specific datatype."""
30
28
  return dumper.represent_scalar("tag:yaml.org,2002:str", str(data.as_posix()))
@@ -132,7 +130,7 @@ class ShpModel(BaseModel):
132
130
  yield key, self[key]
133
131
 
134
132
  @classmethod
135
- def schema_to_file(cls, path: Union[str, Path]) -> None:
133
+ def schema_to_file(cls, path: str | Path) -> None:
136
134
  """Store schema to yaml (for frontend-generators)."""
137
135
  model_dict = cls.model_json_schema()
138
136
  model_yaml = yaml.safe_dump(model_dict, default_flow_style=False, sort_keys=False)
@@ -141,8 +139,8 @@ class ShpModel(BaseModel):
141
139
 
142
140
  def to_file(
143
141
  self,
144
- path: Union[str, Path],
145
- comment: Optional[str] = None,
142
+ path: str | Path,
143
+ comment: str | None = None,
146
144
  *,
147
145
  minimal: bool = True,
148
146
  use_pickle: bool = False,
@@ -176,12 +174,12 @@ class ShpModel(BaseModel):
176
174
 
177
175
  if not model_path.parent.exists():
178
176
  model_path.parent.mkdir(parents=True)
179
- with model_path.open("w") as f:
177
+ with model_path.open("wb" if use_pickle else "w") as f:
180
178
  f.write(model_serial)
181
179
  return model_path
182
180
 
183
181
  @classmethod
184
- def from_file(cls, path: Union[str, Path]) -> Self:
182
+ def from_file(cls, path: str | Path) -> Self:
185
183
  """Load from YAML or pickle file."""
186
184
  path: Path = Path(path)
187
185
  if not Path(path).exists():
@@ -2,7 +2,6 @@
2
2
 
3
3
  from datetime import datetime
4
4
  from typing import Annotated
5
- from typing import Optional
6
5
 
7
6
  from pydantic import BaseModel
8
7
  from pydantic import StringConstraints
@@ -18,10 +17,10 @@ class Wrapper(BaseModel):
18
17
 
19
18
  datatype: str
20
19
  """ ⤷ model-name"""
21
- comment: Optional[SafeStrClone] = None
22
- created: Optional[datetime] = None
20
+ comment: SafeStrClone | None = None
21
+ created: datetime | None = None
23
22
  """ ⤷ Optional metadata"""
24
- lib_ver: Optional[str] = version
23
+ lib_ver: str | None = version
25
24
  """ ⤷ for debug-purposes and later compatibility-checks"""
26
25
  parameters: dict
27
26
  """ ⤷ ShpModel"""
@@ -3,7 +3,6 @@
3
3
  from enum import Enum
4
4
  from pathlib import Path
5
5
  from typing import Any
6
- from typing import Optional
7
6
 
8
7
  from pydantic import PositiveFloat
9
8
  from pydantic import model_validator
@@ -40,10 +39,10 @@ class EnergyEnvironment(ContentModel):
40
39
  # TODO: harvester, transducer
41
40
 
42
41
  # additional descriptive metadata, TODO: these are very solar-centered -> generalize
43
- light_source: Optional[str] = None
44
- weather_conditions: Optional[str] = None
45
- indoor: Optional[bool] = None
46
- location: Optional[str] = None
42
+ light_source: str | None = None
43
+ weather_conditions: str | None = None
44
+ indoor: bool | None = None
45
+ location: str | None = None
47
46
 
48
47
  @model_validator(mode="before")
49
48
  @classmethod
@@ -6,9 +6,7 @@ TODO: should be more generalized - currently only supports msp & nRF
6
6
  from pathlib import Path
7
7
  from typing import Annotated
8
8
  from typing import Any
9
- from typing import Optional
10
9
  from typing import TypedDict
11
- from typing import Union
12
10
 
13
11
  from pydantic import StringConstraints
14
12
  from pydantic import model_validator
@@ -58,9 +56,9 @@ class Firmware(ContentModel, title="Firmware of Target"):
58
56
 
59
57
  mcu: MCU
60
58
 
61
- data: Union[FirmwareStr, Path]
59
+ data: FirmwareStr | Path
62
60
  data_type: FirmwareDType
63
- data_hash: Optional[str] = None
61
+ data_hash: str | None = None
64
62
  data_local: bool = True
65
63
  """ ⤷ signals that file has to be copied to testbed"""
66
64
 
@@ -147,7 +145,7 @@ class Firmware(ContentModel, title="Firmware of Target"):
147
145
  kwargs["name"] = file.name
148
146
  return cls(**kwargs)
149
147
 
150
- def compare_hash(self, path: Optional[Path] = None) -> bool:
148
+ def compare_hash(self, path: Path | None = None) -> bool:
151
149
  if self.data_hash is None:
152
150
  return True
153
151
 
@@ -4,7 +4,6 @@ from collections.abc import Mapping
4
4
  from enum import Enum
5
5
  from typing import Annotated
6
6
  from typing import Any
7
- from typing import Optional
8
7
 
9
8
  from pydantic import Field
10
9
  from pydantic import model_validator
@@ -214,7 +213,7 @@ class VirtualHarvesterConfig(ContentModel, title="Config for the Harvester"):
214
213
  (constant current tracking).
215
214
  """
216
215
 
217
- voltage_step_mV: Optional[Annotated[float, Field(ge=1, le=1_000_000)]] = None
216
+ voltage_step_mV: Annotated[float, Field(ge=1, le=1000000)] | None = None
218
217
  """The difference between two adjacent voltage samples.
219
218
 
220
219
  This value is implicitly derived from the other ramp parameters:
@@ -384,7 +383,7 @@ class VirtualHarvesterConfig(ContentModel, title="Config for the Harvester"):
384
383
 
385
384
  def calc_window_size(
386
385
  self,
387
- dtype_in: Optional[EnergyDType] = None,
386
+ dtype_in: EnergyDType | None = None,
388
387
  *,
389
388
  for_emu: bool,
390
389
  ) -> int:
@@ -468,9 +467,9 @@ class HarvesterPRUConfig(ShpModel):
468
467
  def from_vhrv(
469
468
  cls,
470
469
  data: VirtualHarvesterConfig,
471
- dtype_in: Optional[EnergyDType] = EnergyDType.ivsample,
472
- window_size: Optional[u32] = None,
473
- voltage_step_V: Optional[float] = None,
470
+ dtype_in: EnergyDType | None = EnergyDType.ivsample,
471
+ window_size: u32 | None = None,
472
+ voltage_step_V: float | None = None,
474
473
  *,
475
474
  for_emu: bool = False,
476
475
  ) -> Self:
@@ -4,15 +4,12 @@ from collections.abc import Iterable
4
4
  from datetime import datetime
5
5
  from datetime import timedelta
6
6
  from typing import Annotated
7
- from typing import Optional
8
7
 
9
8
  from pydantic import Field
10
9
  from pydantic import model_validator
11
10
  from typing_extensions import Self
12
- from typing_extensions import deprecated
13
11
 
14
12
  from shepherd_core.config import config
15
- from shepherd_core.data_models.base.content import IdInt
16
13
  from shepherd_core.data_models.base.content import NameStr
17
14
  from shepherd_core.data_models.base.content import SafeStr
18
15
  from shepherd_core.data_models.base.shepherd import ShpModel
@@ -33,10 +30,10 @@ class Experiment(ShpModel, title="Config of an Experiment"):
33
30
 
34
31
  # General Properties
35
32
  name: NameStr
36
- description: Annotated[
37
- Optional[SafeStr], Field(description="Required for public instances")
38
- ] = None
39
- comment: Optional[SafeStr] = None
33
+ description: Annotated[SafeStr | None, Field(description="Required for public instances")] = (
34
+ None
35
+ )
36
+ comment: SafeStr | None = None
40
37
 
41
38
  # feedback
42
39
  email_results: bool = True
@@ -44,20 +41,14 @@ class Experiment(ShpModel, title="Config of an Experiment"):
44
41
  sys_logging: SystemLogging = sys_log_all
45
42
 
46
43
  # schedule
47
- time_start: Optional[datetime] = None # = ASAP
48
- duration: Optional[timedelta] = None # = till EOF
44
+ time_start: datetime | None = None # = ASAP
45
+ duration: timedelta | None = None # = till EOF
49
46
 
50
47
  # targets
51
48
  target_configs: Annotated[list[TargetConfig], Field(min_length=1, max_length=128)]
52
49
 
53
50
  # debug
54
- lib_ver: Optional[str] = version
55
-
56
- # deprecated fields, TODO: remove before public release
57
- id: Annotated[Optional[int], deprecated("not needed")] = None
58
- created: Annotated[Optional[datetime], deprecated("not needed")] = None
59
- abort_on_error: Annotated[bool, deprecated("has no effect")] = False
60
- owner_id: Annotated[Optional[IdInt], deprecated("not needed")] = None
51
+ lib_ver: str | None = version
61
52
 
62
53
  @model_validator(mode="after")
63
54
  def post_validation(self) -> Self:
@@ -109,7 +100,8 @@ class Experiment(ShpModel, title="Config of an Experiment"):
109
100
  msg = f"Target-ID {target_id} was not found in Experiment '{self.name}'"
110
101
  raise ValueError(msg)
111
102
 
112
- def folder_name(self, custom_date: Optional[datetime] = None) -> str:
103
+ def folder_name(self, custom_date: datetime | None = None) -> str:
104
+ # TODO: custom date should not overrule time_start
113
105
  date = custom_date if custom_date is not None else self.time_start
114
106
  timestamp = local_now() if date is None else date
115
107
  timestrng = timestamp.strftime("%Y-%m-%d_%H-%M-%S")
@@ -3,7 +3,6 @@
3
3
  from datetime import timedelta
4
4
  from enum import Enum
5
5
  from typing import Annotated
6
- from typing import Optional
7
6
 
8
7
  import numpy as np
9
8
  from annotated_types import Interval
@@ -11,7 +10,6 @@ from pydantic import Field
11
10
  from pydantic import PositiveFloat
12
11
  from pydantic import model_validator
13
12
  from typing_extensions import Self
14
- from typing_extensions import deprecated
15
13
 
16
14
  from shepherd_core.data_models.base.shepherd import ShpModel
17
15
  from shepherd_core.data_models.testbed.gpio import GPIO
@@ -22,10 +20,7 @@ zero_duration = timedelta(seconds=0)
22
20
 
23
21
 
24
22
  class PowerTracing(ShpModel, title="Config for Power-Tracing"):
25
- """Configuration for recording the Power-Consumption of the Target Nodes.
26
-
27
- TODO: postprocessing not implemented ATM
28
- """
23
+ """Configuration for recording the Power-Consumption of the Target Nodes."""
29
24
 
30
25
  intermediate_voltage: bool = False
31
26
  """
@@ -35,20 +30,20 @@ class PowerTracing(ShpModel, title="Config for Power-Tracing"):
35
30
  # time
36
31
  delay: timedelta = zero_duration
37
32
  """start recording after experiment started"""
38
- duration: Optional[timedelta] = None # till EOF
33
+ duration: timedelta | None = None # till EOF
39
34
  """duration of recording after delay starts the process.
40
35
 
41
36
  default is None, recording till EOF"""
42
37
 
43
- # post-processing
44
- calculate_power: bool = False
45
- """ ⤷ reduce file-size by calculating power -> not implemented ATM"""
38
+ # further processing of IV-Samples
39
+ only_power: bool = False
40
+ """ ⤷ reduce file-size by calculating power and automatically discard I&V"""
46
41
  samplerate: Annotated[int, Field(ge=10, le=100_000)] = 100_000
47
- """ ⤷ reduce file-size by down-sampling -> not implemented ATM"""
48
- discard_current: bool = False
49
- """ reduce file-size by omitting current -> not implemented ATM"""
50
- discard_voltage: bool = False
51
- """ ⤷ reduce file-size by omitting voltage -> not implemented ATM"""
42
+ """ ⤷ reduce file-size by re-sampling (mean over x samples)
43
+ Timestamps will be taken from the start of that sample-window.
44
+ example: 10 Hz samplerate will be binning 10k samples via mean() and
45
+ the timestamp for that new sample will be value[0] of the 10k long vector
46
+ """
52
47
 
53
48
  @model_validator(mode="after")
54
49
  def post_validation(self) -> Self:
@@ -57,22 +52,10 @@ class PowerTracing(ShpModel, title="Config for Power-Tracing"):
57
52
  if self.duration and self.duration.total_seconds() < 0:
58
53
  raise ValueError("Duration can't be negative.")
59
54
 
60
- discard_all = self.discard_current and self.discard_voltage
61
- if not self.calculate_power and discard_all:
62
- raise ValueError("Error in config -> tracing enabled, but output gets discarded")
63
- if self.calculate_power:
64
- raise NotImplementedError(
65
- "Feature PowerTracing.calculate_power reserved for future use."
66
- )
67
- if self.samplerate != 100_000:
68
- raise NotImplementedError("Feature PowerTracing.samplerate reserved for future use.")
69
- if self.discard_current:
70
- raise NotImplementedError(
71
- "Feature PowerTracing.discard_current reserved for future use."
72
- )
73
- if self.discard_voltage:
74
- raise NotImplementedError(
75
- "Feature PowerTracing.discard_voltage reserved for future use."
55
+ rates_allowed = (10, 100, 1_000, 100_000)
56
+ if self.samplerate not in rates_allowed:
57
+ raise ValueError(
58
+ "Feature PowerTracing.samplerate only supports specific rates: %s", rates_allowed
76
59
  )
77
60
  return self
78
61
 
@@ -175,7 +158,7 @@ class GpioTracing(ShpModel, title="Config for GPIO-Tracing"):
175
158
 
176
159
  # time
177
160
  delay: timedelta = zero_duration
178
- duration: Optional[timedelta] = None # till EOF
161
+ duration: timedelta | None = None # till EOF
179
162
 
180
163
  # post-processing,
181
164
  uart_decode: bool = False
@@ -264,11 +247,6 @@ class SystemLogging(ShpModel, title="Config for System-Logging"):
264
247
  sheep: bool = True
265
248
  sys_util: bool = True
266
249
 
267
- # deprecated, TODO: remove lines below before public release
268
- dmesg: Annotated[bool, deprecated("for sheep v0.9.0+, use 'kernel' instead")] = True
269
- ptp: Annotated[bool, deprecated("for sheep v0.9.0+, use 'time_sync' instead")] = True
270
- shepherd: Annotated[bool, deprecated("for sheep v0.9.0+, use 'sheep' instead")] = True
271
-
272
250
 
273
251
  # TODO: some more interaction would be good
274
252
  # - execute limited python-scripts
@@ -1,7 +1,6 @@
1
1
  """Configuration related to Target Nodes (DuT)."""
2
2
 
3
3
  from typing import Annotated
4
- from typing import Optional
5
4
 
6
5
  from pydantic import Field
7
6
  from pydantic import model_validator
@@ -28,7 +27,7 @@ class TargetConfig(ShpModel, title="Target Config"):
28
27
  """Configuration related to Target Nodes (DuT)."""
29
28
 
30
29
  target_IDs: Annotated[list[IdInt], Field(min_length=1, max_length=128)]
31
- custom_IDs: Optional[Annotated[list[IdInt16], Field(min_length=1, max_length=128)]] = None
30
+ custom_IDs: Annotated[list[IdInt16], Field(min_length=1, max_length=128)] | None = None
32
31
  """ ⤷ custom ID will replace 'const uint16_t SHEPHERD_NODE_ID' in firmware.
33
32
 
34
33
  if no custom ID is provided, the original ID of target is used
@@ -37,9 +36,9 @@ class TargetConfig(ShpModel, title="Target Config"):
37
36
  energy_env: EnergyEnvironment
38
37
  """ input for the virtual source """
39
38
  virtual_source: VirtualSourceConfig = vsrc_neutral
40
- target_delays: Optional[
41
- Annotated[list[Annotated[int, Field(ge=0)]], Field(min_length=1, max_length=128)]
42
- ] = None
39
+ target_delays: (
40
+ Annotated[list[Annotated[int, Field(ge=0)]], Field(min_length=1, max_length=128)] | None
41
+ ) = None
43
42
  """ ⤷ individual starting times
44
43
 
45
44
  - allows to use the same environment
@@ -48,13 +47,13 @@ class TargetConfig(ShpModel, title="Target Config"):
48
47
 
49
48
  firmware1: Firmware
50
49
  """ ⤷ omitted FW gets set to neutral deep-sleep"""
51
- firmware2: Optional[Firmware] = None
50
+ firmware2: Firmware | None = None
52
51
  """ ⤷ omitted FW gets set to neutral deep-sleep"""
53
52
 
54
- power_tracing: Optional[PowerTracing] = None
55
- gpio_tracing: Optional[GpioTracing] = None
56
- gpio_actuation: Optional[GpioActuation] = None
57
- uart_logging: Optional[UartLogging] = None
53
+ power_tracing: PowerTracing | None = None
54
+ gpio_tracing: GpioTracing | None = None
55
+ gpio_actuation: GpioActuation | None = None
56
+ uart_logging: UartLogging | None = None
58
57
 
59
58
  @model_validator(mode="after")
60
59
  def post_validation(self) -> Self:
@@ -96,7 +95,7 @@ class TargetConfig(ShpModel, title="Target Config"):
96
95
  raise NotImplementedError("Feature GpioActuation reserved for future use.")
97
96
  return self
98
97
 
99
- def get_custom_id(self, target_id: int) -> Optional[int]:
98
+ def get_custom_id(self, target_id: int) -> int | None:
100
99
  if self.custom_IDs is not None and target_id in self.target_IDs:
101
100
  return self.custom_IDs[self.target_IDs.index(target_id)]
102
101
  return None
@@ -5,8 +5,6 @@ These models import externally from all other model-modules!
5
5
 
6
6
  import pickle
7
7
  from pathlib import Path
8
- from typing import Optional
9
- from typing import Union
10
8
 
11
9
  import yaml
12
10
 
@@ -35,7 +33,7 @@ __all__ = [
35
33
  ]
36
34
 
37
35
 
38
- def prepare_task(config: Union[ShpModel, Path, str], observer: Optional[str] = None) -> Wrapper:
36
+ def prepare_task(config: ShpModel | Path | str, observer: str | None = None) -> Wrapper:
39
37
  """Open file and extract tasks.
40
38
 
41
39
  - Open file (from Path or str of Path)