shepherd-core 2025.2.1__tar.gz → 2025.4.1__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 (145) hide show
  1. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/PKG-INFO +2 -2
  2. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/pyproject.toml +1 -0
  3. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/base/calibration.py +6 -4
  4. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/content/firmware.py +2 -1
  5. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/content/virtual_source.py +1 -1
  6. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/experiment/experiment.py +3 -2
  7. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/readme.md +2 -1
  8. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/task/programming.py +1 -1
  9. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/fw_tools/validation.py +8 -10
  10. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/inventory/__init__.py +2 -2
  11. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/reader.py +9 -7
  12. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/testbed_client/fixtures.py +6 -29
  13. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/version.py +1 -1
  14. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/writer.py +2 -1
  15. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core.egg-info/PKG-INFO +2 -2
  16. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/README.md +0 -0
  17. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/eenv_generator.py +0 -0
  18. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/experiment_from_yaml.yaml +0 -0
  19. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/experiment_generic_var1.py +0 -0
  20. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/experiment_generic_var2.py +0 -0
  21. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/experiment_models.py +0 -0
  22. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/firmware_model.py +0 -0
  23. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/firmware_modification.py +0 -0
  24. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/inventory.py +0 -0
  25. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/simulate_vharvester.py +0 -0
  26. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/simulate_vsource.py +0 -0
  27. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/uart_decode_waveform.py +0 -0
  28. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/uart_raw2.csv +0 -0
  29. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/examples/vsource_debug_sim.py +0 -0
  30. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/setup.cfg +0 -0
  31. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/__init__.py +0 -0
  32. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/calibration_hw_def.py +0 -0
  33. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/commons.py +0 -0
  34. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/__init__.py +0 -0
  35. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/base/__init__.py +0 -0
  36. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/base/cal_measurement.py +0 -0
  37. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/base/content.py +0 -0
  38. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/base/shepherd.py +0 -0
  39. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/base/timezone.py +0 -0
  40. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/base/wrapper.py +0 -0
  41. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/content/__init__.py +0 -0
  42. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/content/_external_fixtures.yaml +0 -0
  43. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/content/energy_environment.py +0 -0
  44. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/content/energy_environment_fixture.yaml +0 -0
  45. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/content/firmware_datatype.py +0 -0
  46. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/content/virtual_harvester.py +0 -0
  47. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/content/virtual_harvester_fixture.yaml +0 -0
  48. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/content/virtual_source_fixture.yaml +0 -0
  49. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/experiment/__init__.py +0 -0
  50. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/experiment/observer_features.py +0 -0
  51. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/experiment/target_config.py +0 -0
  52. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/task/__init__.py +0 -0
  53. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/task/emulation.py +0 -0
  54. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/task/firmware_mod.py +0 -0
  55. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/task/harvest.py +0 -0
  56. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/task/observer_tasks.py +0 -0
  57. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/task/testbed_tasks.py +0 -0
  58. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/__init__.py +0 -0
  59. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/cape.py +0 -0
  60. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/cape_fixture.yaml +0 -0
  61. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/gpio.py +0 -0
  62. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/gpio_fixture.yaml +0 -0
  63. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/mcu.py +0 -0
  64. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/mcu_fixture.yaml +0 -0
  65. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/observer.py +0 -0
  66. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/observer_fixture.yaml +0 -0
  67. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/target.py +0 -0
  68. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/target_fixture.old1 +0 -0
  69. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/target_fixture.yaml +0 -0
  70. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/testbed.py +0 -0
  71. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/testbed/testbed_fixture.yaml +0 -0
  72. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/data_models/virtual_source_doc.txt +0 -0
  73. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/decoder_waveform/__init__.py +0 -0
  74. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/decoder_waveform/uart.py +0 -0
  75. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/fw_tools/__init__.py +0 -0
  76. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/fw_tools/converter.py +0 -0
  77. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/fw_tools/converter_elf.py +0 -0
  78. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/fw_tools/patcher.py +0 -0
  79. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/inventory/python.py +0 -0
  80. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/inventory/system.py +0 -0
  81. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/inventory/target.py +0 -0
  82. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/logger.py +0 -0
  83. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/testbed_client/__init__.py +0 -0
  84. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/testbed_client/cache_path.py +0 -0
  85. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/testbed_client/client_abc_fix.py +0 -0
  86. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/testbed_client/client_web.py +0 -0
  87. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/testbed_client/user_model.py +0 -0
  88. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/vsource/__init__.py +0 -0
  89. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/vsource/target_model.py +0 -0
  90. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/vsource/virtual_converter_model.py +0 -0
  91. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/vsource/virtual_harvester_model.py +0 -0
  92. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/vsource/virtual_harvester_simulation.py +0 -0
  93. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/vsource/virtual_source_model.py +0 -0
  94. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core/vsource/virtual_source_simulation.py +0 -0
  95. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core.egg-info/SOURCES.txt +0 -0
  96. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core.egg-info/dependency_links.txt +0 -0
  97. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core.egg-info/requires.txt +0 -0
  98. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core.egg-info/top_level.txt +0 -0
  99. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/shepherd_core.egg-info/zip-safe +0 -0
  100. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/__init__.py +0 -0
  101. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/conftest.py +0 -0
  102. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/__init__.py +0 -0
  103. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/conftest.py +0 -0
  104. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_cal_data.yaml +0 -0
  105. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_cal_data_faulty.yaml +0 -0
  106. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_cal_meas.yaml +0 -0
  107. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_cal_meas_faulty1.yaml +0 -0
  108. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_cal_meas_faulty2.yaml +0 -0
  109. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_config_emulator.yaml +0 -0
  110. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_config_experiment.yaml +0 -0
  111. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_config_experiment_alternative.yaml +0 -0
  112. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_config_harvester.yaml +0 -0
  113. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_config_testbed.yaml +0 -0
  114. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/example_config_virtsource.yaml +0 -0
  115. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/test_base_models.py +0 -0
  116. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/test_content_fixtures.py +0 -0
  117. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/test_content_models.py +0 -0
  118. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/test_examples.py +0 -0
  119. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/test_experiment_models.py +0 -0
  120. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/test_task_generation.py +0 -0
  121. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/test_task_models.py +0 -0
  122. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/test_testbed_fixtures.py +0 -0
  123. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/data_models/test_testbed_models.py +0 -0
  124. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/decoder_waveform/__init__.py +0 -0
  125. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/decoder_waveform/test_decoder.py +0 -0
  126. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/fw_tools/__init__.py +0 -0
  127. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/fw_tools/build_msp.elf +0 -0
  128. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/fw_tools/build_nrf.elf +0 -0
  129. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/fw_tools/conftest.py +0 -0
  130. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/fw_tools/test_converter.py +0 -0
  131. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/fw_tools/test_patcher.py +0 -0
  132. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/fw_tools/test_validation.py +0 -0
  133. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/inventory/__init__.py +0 -0
  134. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/inventory/test_inventory.py +0 -0
  135. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/test_cal_hw.py +0 -0
  136. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/test_examples.py +0 -0
  137. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/test_logger.py +0 -0
  138. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/test_reader.py +0 -0
  139. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/test_writer.py +0 -0
  140. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/testbed_client/__init__.py +0 -0
  141. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/vsource/__init__.py +0 -0
  142. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/vsource/conftest.py +0 -0
  143. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/vsource/test_converter.py +0 -0
  144. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/vsource/test_harvester.py +0 -0
  145. {shepherd_core-2025.2.1 → shepherd_core-2025.4.1}/tests/vsource/test_z.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: shepherd_core
3
- Version: 2025.2.1
3
+ Version: 2025.4.1
4
4
  Summary: Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed
5
5
  Author-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
6
6
  Maintainer-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
@@ -113,3 +113,4 @@ omit = ["*/shepherd_data/*"]
113
113
  [tool.mypy]
114
114
  python_version = 3.8
115
115
  ignore_missing_imports = true
116
+ disable_error_code = ["call-arg", ]
@@ -3,7 +3,9 @@
3
3
  import struct
4
4
  from typing import Callable
5
5
  from typing import Generator
6
+ from typing import Mapping
6
7
  from typing import Optional
8
+ from typing import Sequence
7
9
  from typing import TypeVar
8
10
  from typing import Union
9
11
 
@@ -26,18 +28,18 @@ Calc_t = TypeVar("Calc_t", NDArray[np.float64], float)
26
28
 
27
29
 
28
30
  def dict_generator(
29
- in_dict: Union[dict, list], pre: Optional[list] = None
31
+ in_dict: Union[Mapping, Sequence], pre: Optional[list] = None
30
32
  ) -> Generator[list, None, None]:
31
33
  """Recursive helper-function to generate a 1D-List(or not?).
32
34
 
33
35
  TODO: isn't that a 1D-List generator?
34
36
  """
35
37
  pre = pre[:] if pre else []
36
- if isinstance(in_dict, dict):
38
+ if isinstance(in_dict, Mapping):
37
39
  for key, value in in_dict.items():
38
- if isinstance(value, dict):
40
+ if isinstance(value, Mapping):
39
41
  yield from dict_generator(value, [*pre, key])
40
- elif isinstance(value, (list, tuple)):
42
+ elif isinstance(value, Sequence):
41
43
  for v in value:
42
44
  yield from dict_generator(v, [*pre, key])
43
45
  else:
@@ -127,8 +127,9 @@ class Firmware(ContentModel, title="Firmware of Target"):
127
127
  arch = fw_tools.read_arch(file)
128
128
  if "msp430" in arch and not fw_tools.is_elf_msp430(file):
129
129
  raise ValueError("File is not a ELF for msp430")
130
- if "nrf52" in arch and not fw_tools.is_elf_nrf52(file):
130
+ if ("nrf52" in arch or "arm" in arch) and not fw_tools.is_elf_nrf52(file):
131
131
  raise ValueError("File is not a ELF for nRF52")
132
+ logger.debug("ELF-File '%s' has arch: %s", file.name, arch)
132
133
  if "mcu" not in kwargs:
133
134
  kwargs["mcu"] = arch_to_mcu[arch]
134
135
 
@@ -346,7 +346,7 @@ class ConverterPRUConfig(ShpModel):
346
346
  [min(255, round(256 * ival)) for ival in il] for il in data.LUT_input_efficiency
347
347
  ],
348
348
  LUT_out_inv_efficiency_n4=[
349
- min((2**14), round((2**4) / value)) if (value > 0) else int(2**14)
349
+ min((2**14), round((2**4) / value)) if (value > 0) else (2**14)
350
350
  for value in data.LUT_output_efficiency
351
351
  ],
352
352
  )
@@ -2,6 +2,7 @@
2
2
 
3
3
  from datetime import datetime
4
4
  from datetime import timedelta
5
+ from typing import Iterable
5
6
  from typing import List
6
7
  from typing import Optional
7
8
  from typing import Union
@@ -68,7 +69,7 @@ class Experiment(ShpModel, title="Config of an Experiment"):
68
69
  return self
69
70
 
70
71
  @staticmethod
71
- def _validate_targets(configs: List[TargetConfig]) -> None:
72
+ def _validate_targets(configs: Iterable[TargetConfig]) -> None:
72
73
  target_ids = []
73
74
  custom_ids = []
74
75
  for _config in configs:
@@ -86,7 +87,7 @@ class Experiment(ShpModel, title="Config of an Experiment"):
86
87
  raise ValueError("Custom Target-ID are faulty (some form of id-collisions)!")
87
88
 
88
89
  @staticmethod
89
- def _validate_observers(configs: List[TargetConfig], testbed: Testbed) -> None:
90
+ def _validate_observers(configs: Iterable[TargetConfig], testbed: Testbed) -> None:
90
91
  target_ids = [_id for _config in configs for _id in _config.target_IDs]
91
92
  obs_ids = [testbed.get_observer(_id).id for _id in target_ids]
92
93
  if len(target_ids) > len(set(obs_ids)):
@@ -46,6 +46,7 @@
46
46
  - these do not work
47
47
 
48
48
  ```Python
49
+ from typing import Dict
49
50
  from pydantic import Field
50
51
  from shepherd_core.data_models import ShpModel
51
52
 
@@ -54,7 +55,7 @@ class Experiment(ShpModel, title="Config of an Experiment"):
54
55
  super().__init__()
55
56
  self.Config.fields["output_path"].description = "test description"
56
57
  class Config:
57
- fields: dict[str, Field] = {}
58
+ fields: Dict[str, Field] = {}
58
59
  fields["output_path"] = Field(description="test description")
59
60
  ```
60
61
 
@@ -31,7 +31,7 @@ class ProgrammingTask(ShpModel):
31
31
  mcu_type: SafeStr
32
32
  # ⤷ must be either "nrf52" or "msp430" ATM, TODO: clean xp to tasks
33
33
  voltage: Annotated[float, Field(ge=1, lt=5)] = 3
34
- datarate: Annotated[int, Field(gt=0, le=1_000_000)] = 500_000
34
+ datarate: Annotated[int, Field(gt=0, le=1_000_000)] = 200_000
35
35
  protocol: ProgrammerProtocol
36
36
 
37
37
  simulate: bool = False
@@ -66,16 +66,14 @@ def is_hex_nrf52(file: Path) -> bool:
66
66
  """Try to detect specifics for that MCU.
67
67
 
68
68
  Observations:
69
- - addresses begin at 0x0
69
+ - addresses begin mostly at 0x0 (no must)
70
70
  - only one segment (.get_segments), todo
71
71
  """
72
72
  if is_hex(file):
73
73
  ih = IntelHex(file.as_posix())
74
- if ih.minaddr() != 0x0000:
75
- return False
76
-
77
- # conservative test for now - should be well below 1 MB + 256 kB
78
- return ih.get_memory_size() < 1310720
74
+ # conservative test for now - should be between 0 and 1 MB + 256 kB,
75
+ # but lately showed much higher values > 4 MB
76
+ return ih.get_memory_size() > 0
79
77
  return False
80
78
 
81
79
 
@@ -145,15 +143,15 @@ def determine_arch(file: Path) -> str:
145
143
  """Figure out arch (msp430 or nrf52)."""
146
144
  file_t = determine_type(file)
147
145
  if file_t == FirmwareDType.path_elf:
148
- if is_elf_nrf52(file):
149
- return "nrf52"
150
146
  if is_elf_msp430(file):
151
147
  return "msp430"
148
+ if is_elf_nrf52(file):
149
+ return "nrf52"
152
150
  raise ValueError("Arch of ELF '%s' could not be determined", file.name)
153
151
  if file_t == FirmwareDType.path_hex:
154
- if is_hex_nrf52(file):
155
- return "nrf52"
156
152
  if is_hex_msp430(file):
157
153
  return "msp430"
154
+ if is_hex_nrf52(file):
155
+ return "nrf52"
158
156
  raise ValueError("Arch of HEX '%s' could not be determined", file.name)
159
157
  raise ValueError("Arch of file '%s' could not be determined", file.name)
@@ -82,8 +82,8 @@ class InventoryList(ShpModel):
82
82
  if (_e.created.timestamp() - ts_earl) > 10:
83
83
  warnings["time_delta"] = f"[{self.hostname}] time-sync has failed"
84
84
 
85
- # turn dict[hostname][type] = val
86
- # to dict[type][val] = list[hostnames]
85
+ # turn Dict[hostname][type] = val
86
+ # to Dict[type][val] = List[hostnames]
87
87
  _inp = {
88
88
  _e.hostname: _e.model_dump(exclude_unset=True, exclude_defaults=True)
89
89
  for _e in self.elements
@@ -194,6 +194,7 @@ class Reader:
194
194
  self,
195
195
  start_n: int = 0,
196
196
  end_n: Optional[int] = None,
197
+ n_samples_per_buffer: Optional[int] = None,
197
198
  *,
198
199
  is_raw: bool = False,
199
200
  omit_ts: bool = False,
@@ -201,27 +202,28 @@ class Reader:
201
202
  """Read the specified range of buffers from the hdf5 file.
202
203
 
203
204
  Generator - can be configured on first call
204
- TODO: reconstruct - start/end mark samples &
205
- each call can request a certain number of samples.
206
205
 
207
206
  Args:
208
207
  ----
209
208
  :param start_n: (int) Index of first buffer to be read
210
209
  :param end_n: (int) Index of last buffer to be read
210
+ :param n_samples_per_buffer: (int) allows changing
211
211
  :param is_raw: (bool) output original data, not transformed to SI-Units
212
212
  :param omit_ts: (bool) optimize reading if timestamp is never used
213
213
  Yields: Buffers between start and end (tuple with time, voltage, current)
214
214
 
215
215
  """
216
- if end_n is None:
217
- end_n = int(self.ds_voltage.shape[0] // self.samples_per_buffer)
216
+ if n_samples_per_buffer is None:
217
+ n_samples_per_buffer = self.samples_per_buffer
218
+ end_max = int(self.ds_voltage.shape[0] // n_samples_per_buffer)
219
+ end_n = end_max if end_n is None else min(end_n, end_max)
218
220
  self._logger.debug("Reading blocks %d to %d from source-file", start_n, end_n)
219
221
  _raw = is_raw
220
222
  _wts = not omit_ts
221
223
 
222
224
  for i in range(start_n, end_n):
223
- idx_start = i * self.samples_per_buffer
224
- idx_end = idx_start + self.samples_per_buffer
225
+ idx_start = i * n_samples_per_buffer
226
+ idx_end = idx_start + n_samples_per_buffer
225
227
  if _raw:
226
228
  yield (
227
229
  self.ds_time[idx_start:idx_end] if _wts else None,
@@ -673,7 +675,7 @@ class Reader:
673
675
  return data != data_1
674
676
 
675
677
  def gpio_to_waveforms(self, name: Optional[str] = None) -> dict:
676
- waveforms: dict[str, np.ndarray] = {}
678
+ waveforms: Dict[str, np.ndarray] = {}
677
679
  if "gpio" not in self.h5file:
678
680
  return waveforms
679
681
 
@@ -1,14 +1,13 @@
1
1
  """Current implementation of a file-based database."""
2
2
 
3
3
  import copy
4
- import os
5
4
  import pickle
6
5
  from datetime import datetime
7
6
  from datetime import timedelta
8
7
  from pathlib import Path
9
8
  from typing import Any
10
9
  from typing import Dict
11
- from typing import List
10
+ from typing import Mapping
12
11
  from typing import Optional
13
12
  from typing import Union
14
13
 
@@ -144,7 +143,7 @@ class Fixture:
144
143
  return values, chain
145
144
 
146
145
  @staticmethod
147
- def fill_model(model: dict, base: dict) -> dict:
146
+ def fill_model(model: Mapping, base: dict) -> dict:
148
147
  base = copy.copy(base)
149
148
  for key, value in model.items():
150
149
  # keep previous entries
@@ -201,7 +200,10 @@ class Fixtures:
201
200
  if self.file_path.is_file():
202
201
  files = [self.file_path]
203
202
  elif self.file_path.is_dir():
204
- files = get_files(self.file_path, self.suffix)
203
+ files = list(
204
+ self.file_path.glob("**/*" + self.suffix)
205
+ ) # for py>=3.12: case_sensitive=False
206
+ logger.debug(" -> got %s %s-files", len(files), self.suffix)
205
207
  else:
206
208
  raise ValueError("Path must either be file or directory (or empty)")
207
209
 
@@ -245,28 +247,3 @@ class Fixtures:
245
247
  def to_file(file: Path) -> None:
246
248
  msg = f"TODO (val={file})"
247
249
  raise NotImplementedError(msg)
248
-
249
-
250
- def get_files(start_path: Path, suffix: str, recursion_depth: int = 0) -> List[Path]:
251
- """Generate a recursive list of all files in a directory."""
252
- if recursion_depth == 0:
253
- suffix = suffix.lower().split(".")[-1]
254
- dir_items = os.scandir(start_path)
255
- recursion_depth += 1
256
- files = []
257
-
258
- for item in dir_items:
259
- if item.is_dir():
260
- files += get_files(Path(item.path), suffix, recursion_depth)
261
- continue
262
-
263
- item_name = str(item.name).lower()
264
- item_ext = item_name.split(".")[-1]
265
- if item_ext == suffix and item_ext != item_name:
266
- files.append(Path(item.path))
267
- if not suffix and item_ext == item_name:
268
- files.append(Path(item.path))
269
-
270
- if recursion_depth == 1 and len(files) > 0:
271
- logger.debug(" -> got %s files with the suffix '%s'", len(files), suffix)
272
- return files
@@ -1,3 +1,3 @@
1
1
  """Separated string avoids circular imports."""
2
2
 
3
- version: str = "2025.02.1"
3
+ version: str = "2025.04.1"
@@ -8,6 +8,7 @@ from itertools import product
8
8
  from pathlib import Path
9
9
  from types import TracebackType
10
10
  from typing import Any
11
+ from typing import Mapping
11
12
  from typing import Optional
12
13
  from typing import Type
13
14
  from typing import Union
@@ -364,7 +365,7 @@ class Writer(Reader):
364
365
  """Conveniently store relevant key-value data (attribute) in H5-structure."""
365
366
  self.h5file.attrs.__setitem__(key, item)
366
367
 
367
- def store_config(self, data: dict) -> None:
368
+ def store_config(self, data: Mapping) -> None:
368
369
  """Get a better self-describing Output-File.
369
370
 
370
371
  TODO: use data-model?
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: shepherd_core
3
- Version: 2025.2.1
3
+ Version: 2025.4.1
4
4
  Summary: Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed
5
5
  Author-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
6
6
  Maintainer-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>