shepherd-core 2024.7.2__tar.gz → 2024.7.3__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 (140) hide show
  1. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/PKG-INFO +1 -1
  2. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/experiment_generic_var1.py +6 -8
  3. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/experiment_generic_var2.py +6 -8
  4. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/experiment_models.py +6 -8
  5. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/firmware_model.py +2 -4
  6. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/vharvester_simulation.py +0 -12
  7. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/vsource_simulation.py +6 -8
  8. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/pyproject.toml +1 -1
  9. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/__init__.py +4 -5
  10. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/base/wrapper.py +4 -0
  11. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/content/energy_environment.py +1 -1
  12. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/content/firmware.py +1 -0
  13. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/experiment/experiment.py +8 -7
  14. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/task/testbed_tasks.py +3 -2
  15. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/testbed.py +9 -0
  16. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/testbed_client/__init__.py +3 -1
  17. shepherd_core-2024.7.3/shepherd_core/testbed_client/client_abc_fix.py +126 -0
  18. shepherd_core-2024.7.3/shepherd_core/testbed_client/client_web.py +157 -0
  19. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/testbed_client/fixtures.py +14 -8
  20. shepherd_core-2024.7.3/shepherd_core/version.py +3 -0
  21. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core.egg-info/PKG-INFO +1 -1
  22. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core.egg-info/SOURCES.txt +3 -1
  23. shepherd_core-2024.7.2/shepherd_core/testbed_client/client.py +0 -161
  24. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/README.md +0 -0
  25. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/experiment_from_yaml.yaml +0 -0
  26. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/firmware_modification.py +0 -0
  27. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/inventory.py +0 -0
  28. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/uart_decode_waveform.py +0 -0
  29. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/examples/uart_raw2.csv +0 -0
  30. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/setup.cfg +0 -0
  31. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/calibration_hw_def.py +0 -0
  32. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/commons.py +0 -0
  33. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/__init__.py +0 -0
  34. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/base/__init__.py +0 -0
  35. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/base/cal_measurement.py +0 -0
  36. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/base/calibration.py +0 -0
  37. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/base/content.py +0 -0
  38. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/base/shepherd.py +0 -0
  39. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/base/timezone.py +0 -0
  40. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/content/__init__.py +0 -0
  41. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/content/_external_fixtures.yaml +0 -0
  42. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/content/energy_environment_fixture.yaml +0 -0
  43. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/content/firmware_datatype.py +0 -0
  44. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/content/virtual_harvester.py +0 -0
  45. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/content/virtual_harvester_fixture.yaml +0 -0
  46. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/content/virtual_source.py +0 -0
  47. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/content/virtual_source_fixture.yaml +0 -0
  48. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/experiment/__init__.py +0 -0
  49. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/experiment/observer_features.py +0 -0
  50. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/experiment/target_config.py +0 -0
  51. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/readme.md +0 -0
  52. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/task/__init__.py +0 -0
  53. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/task/emulation.py +0 -0
  54. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/task/firmware_mod.py +0 -0
  55. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/task/harvest.py +0 -0
  56. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/task/observer_tasks.py +0 -0
  57. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/task/programming.py +0 -0
  58. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/__init__.py +0 -0
  59. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/cape.py +0 -0
  60. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/cape_fixture.yaml +0 -0
  61. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/gpio.py +0 -0
  62. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/gpio_fixture.yaml +0 -0
  63. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/mcu.py +0 -0
  64. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/mcu_fixture.yaml +0 -0
  65. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/observer.py +0 -0
  66. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/observer_fixture.yaml +0 -0
  67. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/target.py +0 -0
  68. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/target_fixture.yaml +0 -0
  69. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/testbed/testbed_fixture.yaml +0 -0
  70. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/data_models/virtual_source_doc.txt +0 -0
  71. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/decoder_waveform/__init__.py +0 -0
  72. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/decoder_waveform/uart.py +0 -0
  73. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/fw_tools/__init__.py +0 -0
  74. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/fw_tools/converter.py +0 -0
  75. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/fw_tools/converter_elf.py +0 -0
  76. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/fw_tools/patcher.py +0 -0
  77. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/fw_tools/validation.py +0 -0
  78. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/inventory/__init__.py +0 -0
  79. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/inventory/python.py +0 -0
  80. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/inventory/system.py +0 -0
  81. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/inventory/target.py +0 -0
  82. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/logger.py +0 -0
  83. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/reader.py +0 -0
  84. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/testbed_client/cache_path.py +0 -0
  85. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/testbed_client/user_model.py +0 -0
  86. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/vsource/__init__.py +0 -0
  87. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/vsource/virtual_converter_model.py +0 -0
  88. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/vsource/virtual_harvester_model.py +0 -0
  89. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/vsource/virtual_source_model.py +0 -0
  90. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core/writer.py +0 -0
  91. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core.egg-info/dependency_links.txt +0 -0
  92. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core.egg-info/requires.txt +0 -0
  93. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core.egg-info/top_level.txt +0 -0
  94. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/shepherd_core.egg-info/zip-safe +0 -0
  95. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/__init__.py +0 -0
  96. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/conftest.py +0 -0
  97. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/__init__.py +0 -0
  98. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/conftest.py +0 -0
  99. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_cal_data.yaml +0 -0
  100. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_cal_data_faulty.yaml +0 -0
  101. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_cal_meas.yaml +0 -0
  102. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_cal_meas_faulty1.yaml +0 -0
  103. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_cal_meas_faulty2.yaml +0 -0
  104. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_config_emulator.yaml +0 -0
  105. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_config_experiment.yaml +0 -0
  106. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_config_experiment_alternative.yaml +0 -0
  107. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_config_harvester.yaml +0 -0
  108. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_config_testbed.yaml +0 -0
  109. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/example_config_virtsource.yaml +0 -0
  110. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/test_base_models.py +0 -0
  111. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/test_content_fixtures.py +0 -0
  112. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/test_content_models.py +0 -0
  113. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/test_examples.py +0 -0
  114. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/test_experiment_models.py +0 -0
  115. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/test_task_generation.py +0 -0
  116. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/test_task_models.py +0 -0
  117. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/test_testbed_fixtures.py +0 -0
  118. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/data_models/test_testbed_models.py +0 -0
  119. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/decoder_waveform/__init__.py +0 -0
  120. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/decoder_waveform/test_decoder.py +0 -0
  121. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/fw_tools/__init__.py +0 -0
  122. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/fw_tools/build_msp.elf +0 -0
  123. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/fw_tools/build_nrf.elf +0 -0
  124. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/fw_tools/conftest.py +0 -0
  125. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/fw_tools/test_converter.py +0 -0
  126. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/fw_tools/test_patcher.py +0 -0
  127. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/fw_tools/test_validation.py +0 -0
  128. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/inventory/__init__.py +0 -0
  129. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/inventory/test_inventory.py +0 -0
  130. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/test_cal_hw.py +0 -0
  131. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/test_examples.py +0 -0
  132. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/test_logger.py +0 -0
  133. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/test_reader.py +0 -0
  134. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/test_writer.py +0 -0
  135. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/testbed_client/__init__.py +0 -0
  136. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/vsource/__init__.py +0 -0
  137. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/vsource/conftest.py +0 -0
  138. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/vsource/test_converter.py +0 -0
  139. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/vsource/test_harvester.py +0 -0
  140. {shepherd_core-2024.7.2 → shepherd_core-2024.7.3}/tests/vsource/test_z.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: shepherd_core
3
- Version: 2024.7.2
3
+ Version: 2024.7.3
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>
@@ -15,7 +15,7 @@ What the code does:
15
15
 
16
16
  from pathlib import Path
17
17
 
18
- from shepherd_core import TestbedClient
18
+ from shepherd_core import WebClient
19
19
  from shepherd_core.data_models import FirmwareDType
20
20
  from shepherd_core.data_models import GpioTracing
21
21
  from shepherd_core.data_models.content import EnergyEnvironment
@@ -25,16 +25,14 @@ from shepherd_core.data_models.experiment import TargetConfig
25
25
  from shepherd_core.data_models.task import TestbedTasks
26
26
  from shepherd_core.data_models.testbed import MCU
27
27
 
28
- # for online-queries the lib can be connected to the testbed-server
28
+ # For online-queries the lib can be connected to the testbed-server.
29
29
  # NOTE: there are 3 states:
30
- # - unconnected -> demo-fixture is queried (locally)
31
- # - connected -> publicly available data is queried online
32
- # - logged in with token -> also private data is queried online
33
- tb_client = TestbedClient()
30
+ # - unconnected -> demo-fixtures are queried (locally)
31
+ # - connected -> publicly available data is queried online
32
+ # - logged in with valid token -> also private data is queried online
34
33
  do_connect = False
35
-
36
34
  if do_connect:
37
- tb_client.connect()
35
+ WebClient()
38
36
 
39
37
  xp = Experiment(
40
38
  id="4567",
@@ -14,7 +14,7 @@
14
14
 
15
15
  from pathlib import Path
16
16
 
17
- from shepherd_core import TestbedClient
17
+ from shepherd_core import WebClient
18
18
  from shepherd_core.data_models import GpioTracing
19
19
  from shepherd_core.data_models.content import EnergyEnvironment
20
20
  from shepherd_core.data_models.content import Firmware
@@ -22,16 +22,14 @@ from shepherd_core.data_models.experiment import Experiment
22
22
  from shepherd_core.data_models.experiment import TargetConfig
23
23
  from shepherd_core.data_models.task import TestbedTasks
24
24
 
25
- # for online-queries the lib can be connected to the testbed-server
25
+ # For online-queries the lib can be connected to the testbed-server.
26
26
  # NOTE: there are 3 states:
27
- # - unconnected -> demo-fixture is queried (locally)
28
- # - connected -> publicly available data is queried online
29
- # - logged in with token -> also private data is queried online
30
- tb_client = TestbedClient()
27
+ # - unconnected -> demo-fixtures are queried (locally)
28
+ # - connected -> publicly available data is queried online
29
+ # - logged in with valid token -> also private data is queried online
31
30
  do_connect = False
32
-
33
31
  if do_connect:
34
- tb_client.connect()
32
+ WebClient()
35
33
 
36
34
  xp = Experiment(
37
35
  id="4567",
@@ -18,7 +18,7 @@ How to define an experiment:
18
18
 
19
19
  """
20
20
 
21
- from shepherd_core import TestbedClient
21
+ from shepherd_core import WebClient
22
22
  from shepherd_core.data_models.content import EnergyEnvironment
23
23
  from shepherd_core.data_models.content import Firmware
24
24
  from shepherd_core.data_models.content import VirtualHarvesterConfig
@@ -30,16 +30,14 @@ from shepherd_core.data_models.task import TestbedTasks
30
30
  # generate description for all parameters -> base for web-forms
31
31
  Experiment.schema_to_file("experiment_schema.yaml")
32
32
 
33
- # for online-queries the lib can be connected to the testbed-server
33
+ # For online-queries the lib can be connected to the testbed-server.
34
34
  # NOTE: there are 3 states:
35
- # - unconnected -> demo-fixture is queried (locally)
36
- # - connected -> publicly available data is queried online
37
- # - logged in with token -> also private data is queried online
38
- tb_client = TestbedClient()
35
+ # - unconnected -> demo-fixtures are queried (locally)
36
+ # - connected -> publicly available data is queried online
37
+ # - logged in with valid token -> also private data is queried online
39
38
  do_connect = False
40
-
41
39
  if do_connect:
42
- tb_client.connect()
40
+ WebClient()
43
41
 
44
42
  # Defining an Experiment in Python
45
43
  hrv = VirtualHarvesterConfig(name="mppt_bq_thermoelectric")
@@ -6,7 +6,7 @@ or shepherd-core[elf].
6
6
 
7
7
  from pathlib import Path
8
8
 
9
- from shepherd_core import TestbedClient
9
+ from shepherd_core import WebClient
10
10
  from shepherd_core import fw_tools
11
11
  from shepherd_core.data_models import Firmware
12
12
  from shepherd_core.data_models import FirmwareDType
@@ -41,9 +41,7 @@ print(f"stored firmware to '{path_elf2.name}'")
41
41
 
42
42
  # Option 3 - fully automatic (with login) -> owner and group get prefilled
43
43
 
44
- tb_client = TestbedClient()
45
44
  do_connect = False
46
-
47
45
  if do_connect:
48
- tb_client.connect(token="your_personal_login_token") # noqa: S106
46
+ WebClient(token="your_personal_login_token") # noqa: S106
49
47
  fw3 = Firmware.from_firmware(file=path_elf, name="msp_deep_sleep3")
@@ -9,7 +9,6 @@
9
9
  from pathlib import Path
10
10
 
11
11
  from shepherd_core import Reader
12
- from shepherd_core import TestbedClient
13
12
  from shepherd_core.data_models import VirtualHarvesterConfig
14
13
  from shepherd_core.data_models.content.virtual_harvester import HarvesterPRUConfig
15
14
  from shepherd_core.vsource import VirtualHarvesterModel
@@ -33,17 +32,6 @@ hrv_list = [
33
32
  "mppt_opt",
34
33
  ]
35
34
 
36
- # for online-queries the lib can be connected to the testbed-server
37
- # NOTE: there are 3 states:
38
- # - unconnected -> demo-fixture is queried (locally)
39
- # - connected -> publicly available data is queried online
40
- # - logged in with token -> also private data is queried online
41
- tb_client = TestbedClient()
42
- do_connect = False
43
-
44
- if do_connect:
45
- tb_client.connect()
46
-
47
35
  # convert IVonne to IVCurve
48
36
  if not file_ivcurve.exists():
49
37
  with ivonne.Reader(file_ivonne) as db:
@@ -16,7 +16,7 @@ import matplotlib.pyplot as plt
16
16
  import numpy as np
17
17
 
18
18
  from shepherd_core import CalibrationEmulator
19
- from shepherd_core import TestbedClient
19
+ from shepherd_core import WebClient
20
20
  from shepherd_core.data_models import VirtualSourceConfig
21
21
  from shepherd_core.vsource import VirtualSourceModel
22
22
 
@@ -38,16 +38,14 @@ src_list = [
38
38
  I_mcu_sleep_A = 200e-9
39
39
  I_mcu_active_A = 1e-3
40
40
 
41
- # for online-queries the lib can be connected to the testbed-server
41
+ # For online-queries the lib can be connected to the testbed-server.
42
42
  # NOTE: there are 3 states:
43
- # - unconnected -> demo-fixture is queried (locally)
44
- # - connected -> publicly available data is queried online
45
- # - logged in with token -> also private data is queried online
46
- tb_client = TestbedClient()
43
+ # - unconnected -> demo-fixtures are queried (locally)
44
+ # - connected -> publicly available data is queried online
45
+ # - logged in with valid token -> also private data is queried online
47
46
  do_connect = False
48
-
49
47
  if do_connect:
50
- tb_client.connect()
48
+ WebClient()
51
49
 
52
50
  for vs_name, v_hrv_mV, samples in product(src_list, v_hrv_mV_list, sample_dur_list):
53
51
  # prepare simulation
@@ -94,7 +94,7 @@ shepherd_core = [
94
94
  ]
95
95
 
96
96
  [tool.setuptools.dynamic]
97
- version = {attr = "shepherd_core.__version__"}
97
+ version = {attr = "shepherd_core.version.version"}
98
98
 
99
99
  [tool.pytest.ini_options]
100
100
  markers = [
@@ -19,11 +19,11 @@ from .logger import get_verbose_level
19
19
  from .logger import increase_verbose_level
20
20
  from .logger import logger
21
21
  from .reader import Reader
22
- from .testbed_client.client import TestbedClient
23
- from .testbed_client.client import tb_client
22
+ from .testbed_client.client_web import WebClient
23
+ from .version import version
24
24
  from .writer import Writer
25
25
 
26
- __version__ = "2024.7.2"
26
+ __version__ = version
27
27
 
28
28
  __all__ = [
29
29
  "Reader",
@@ -40,7 +40,6 @@ __all__ = [
40
40
  "local_now",
41
41
  "Calc_t",
42
42
  "Compression",
43
- "TestbedClient",
44
- "tb_client", # using this (instead of the Class) is the cleaner, but less pythonic way
43
+ "WebClient",
45
44
  "Inventory",
46
45
  ]
@@ -7,6 +7,8 @@ from pydantic import BaseModel
7
7
  from pydantic import StringConstraints
8
8
  from typing_extensions import Annotated
9
9
 
10
+ from ...version import version
11
+
10
12
  SafeStrClone = Annotated[str, StringConstraints(pattern=r"^[ -~]+$")]
11
13
  # ⤷ copy avoids circular import
12
14
 
@@ -19,5 +21,7 @@ class Wrapper(BaseModel):
19
21
  comment: Optional[SafeStrClone] = None
20
22
  created: Optional[datetime] = None
21
23
  # ⤷ Optional metadata
24
+ lib_ver: Optional[str] = version
25
+ # ⤷ for debug-purposes and later comp-checks
22
26
  parameters: dict
23
27
  # ⤷ ShpModel
@@ -35,7 +35,7 @@ class EnergyEnvironment(ContentModel):
35
35
 
36
36
  # TODO: scale up/down voltage/current
37
37
 
38
- # additional descriptive metadata
38
+ # additional descriptive metadata, TODO: these are very solar-centered -> generalize
39
39
  light_source: Optional[str] = None
40
40
  weather_conditions: Optional[str] = None
41
41
  indoor: Optional[bool] = None
@@ -152,6 +152,7 @@ class Firmware(ContentModel, title="Firmware of Target"):
152
152
 
153
153
  if not match:
154
154
  logger.warning("FW-Hash does not match with stored value!")
155
+ # TODO: it might be more appropriate to raise here
155
156
  return match
156
157
 
157
158
  @validate_call
@@ -13,6 +13,7 @@ from pydantic import model_validator
13
13
  from typing_extensions import Annotated
14
14
  from typing_extensions import Self
15
15
 
16
+ from ...version import version
16
17
  from ..base.content import IdInt
17
18
  from ..base.content import NameStr
18
19
  from ..base.content import SafeStr
@@ -54,18 +55,20 @@ class Experiment(ShpModel, title="Config of an Experiment"):
54
55
  # targets
55
56
  target_configs: Annotated[List[TargetConfig], Field(min_length=1, max_length=128)]
56
57
 
57
- # TODO: we probably need to remember the lib-version for content &| experiment
58
+ # for debug-purposes and later comp-checks
59
+ lib_ver: Optional[str] = version
58
60
 
59
61
  @model_validator(mode="after")
60
62
  def post_validation(self) -> Self:
61
- self.validate_targets(self.target_configs)
62
- self.validate_observers(self.target_configs)
63
+ testbed = Testbed() # this will query the first (and only) entry of client
64
+ self._validate_targets(self.target_configs)
65
+ self._validate_observers(self.target_configs, testbed)
63
66
  if self.duration and self.duration.total_seconds() < 0:
64
67
  raise ValueError("Duration of experiment can't be negative.")
65
68
  return self
66
69
 
67
70
  @staticmethod
68
- def validate_targets(configs: List[TargetConfig]) -> None:
71
+ def _validate_targets(configs: List[TargetConfig]) -> None:
69
72
  target_ids = []
70
73
  custom_ids = []
71
74
  for _config in configs:
@@ -83,10 +86,8 @@ class Experiment(ShpModel, title="Config of an Experiment"):
83
86
  raise ValueError("Custom Target-ID are faulty (some form of id-collisions)!")
84
87
 
85
88
  @staticmethod
86
- def validate_observers(configs: List[TargetConfig]) -> None:
89
+ def _validate_observers(configs: List[TargetConfig], testbed: Testbed) -> None:
87
90
  target_ids = [_id for _config in configs for _id in _config.target_IDs]
88
-
89
- testbed = Testbed(name="shepherd_tud_nes")
90
91
  obs_ids = [testbed.get_observer(_id).id for _id in target_ids]
91
92
  if len(target_ids) > len(set(obs_ids)):
92
93
  raise ValueError(
@@ -32,8 +32,9 @@ class TestbedTasks(ShpModel):
32
32
  @validate_call
33
33
  def from_xp(cls, xp: Experiment, tb: Optional[Testbed] = None) -> Self:
34
34
  if tb is None:
35
- # TODO: just for testing OK
36
- tb = Testbed(name="shepherd_tud_nes")
35
+ # TODO: is tb-argument really needed? prob. not
36
+ tb = Testbed() # this will query the first (and only) entry of client
37
+
37
38
  tgt_ids = xp.get_target_ids()
38
39
  obs_tasks = [ObserverTasks.from_xp(xp, tb, _id) for _id in tgt_ids]
39
40
  return cls(
@@ -11,6 +11,7 @@ from pydantic import model_validator
11
11
  from typing_extensions import Annotated
12
12
  from typing_extensions import Self
13
13
 
14
+ from ... import logger
14
15
  from ...testbed_client import tb_client
15
16
  from ..base.content import IdInt
16
17
  from ..base.content import NameStr
@@ -42,6 +43,14 @@ class Testbed(ShpModel):
42
43
  @model_validator(mode="before")
43
44
  @classmethod
44
45
  def query_database(cls, values: dict) -> dict:
46
+ # allow instantiating an empty Testbed
47
+ # -> query the first (and only) entry of client
48
+ if len(values) == 0:
49
+ ids = tb_client.query_ids(cls.__name__)
50
+ if len(ids) > 1:
51
+ logger.warning("More than one testbed defined?!?")
52
+ values = {"id": ids[0]}
53
+
45
54
  values, _ = tb_client.try_completing_model(cls.__name__, values)
46
55
  return values
47
56
 
@@ -1,9 +1,11 @@
1
1
  """Client to access a testbed-instance for controlling experiments."""
2
2
 
3
- from .client import tb_client
3
+ from .client_abc_fix import tb_client
4
+ from .client_web import WebClient
4
5
  from .user_model import User
5
6
 
6
7
  __all__ = [
7
8
  "tb_client",
9
+ "WebClient",
8
10
  "User",
9
11
  ]
@@ -0,0 +1,126 @@
1
+ """AbstractBase-Class & Client-Class to access the file based fixtures.
2
+
3
+ Fixtures == OffLineDemoInstances
4
+ offline: core - fixtClient
5
+ webDev: core - webClient <-> webSrv - fixtClient
6
+ webUser: core - webClient <-> webSrv - DbClient
7
+ webInfra: core - webClient+ <-> webSrv - DbClient
8
+
9
+ Users, Sheep and ServerApps should have access to the same DB via WebClient
10
+
11
+ Note: ABC and FixClient can't be in separate files when tb_client should
12
+ default to FixClient (circular import)
13
+
14
+ TODO: Comfort functions missing
15
+ - fixtures to DB, and vice versa
16
+ """
17
+
18
+ from abc import ABC
19
+ from abc import abstractmethod
20
+ from typing import List
21
+ from typing import Optional
22
+
23
+ from ..data_models.base.shepherd import ShpModel
24
+ from ..data_models.base.wrapper import Wrapper
25
+ from .fixtures import Fixtures
26
+
27
+
28
+ class AbcClient(ABC):
29
+ """AbstractBase-Class to access a testbed instance."""
30
+
31
+ def __init__(self) -> None:
32
+ global tb_client # noqa: PLW0603
33
+ tb_client = self
34
+
35
+ @abstractmethod
36
+ def insert(self, data: ShpModel) -> bool:
37
+ """Insert (and probably replace) entry.
38
+
39
+ TODO: fixtures get replaced, but is that wanted for web?
40
+ """
41
+
42
+ @abstractmethod
43
+ def query_ids(self, model_type: str) -> List[int]:
44
+ pass
45
+
46
+ @abstractmethod
47
+ def query_names(self, model_type: str) -> List[str]:
48
+ pass
49
+
50
+ @abstractmethod
51
+ def query_item(
52
+ self, model_type: str, uid: Optional[int] = None, name: Optional[str] = None
53
+ ) -> dict:
54
+ pass
55
+
56
+ @abstractmethod
57
+ def try_inheritance(self, model_type: str, values: dict) -> (dict, list):
58
+ # TODO: maybe internal? yes
59
+ pass
60
+
61
+ def try_completing_model(self, model_type: str, values: dict) -> (dict, list):
62
+ """Init by name/id, for none existing instances raise Exception.
63
+
64
+ This is the main entry-point for querying a model (used be the core-lib).
65
+ """
66
+ if len(values) == 1 and next(iter(values.keys())) in {"id", "name"}:
67
+ try:
68
+ values = self.query_item(model_type, name=values.get("name"), uid=values.get("id"))
69
+ except ValueError as err:
70
+ raise ValueError(
71
+ "Query %s by name / ID failed - %s is unknown!", model_type, values
72
+ ) from err
73
+ return self.try_inheritance(model_type, values)
74
+
75
+ @abstractmethod
76
+ def fill_in_user_data(self, values: dict) -> dict:
77
+ # TODO: is it really helpful and needed?
78
+ pass
79
+
80
+
81
+ class FixturesClient(AbcClient):
82
+ """Client-Class to access the file based fixtures."""
83
+
84
+ def __init__(self) -> None:
85
+ super().__init__()
86
+ self._fixtures: Optional[Fixtures] = Fixtures()
87
+
88
+ def insert(self, data: ShpModel) -> bool:
89
+ wrap = Wrapper(
90
+ datatype=type(data).__name__,
91
+ parameters=data.model_dump(),
92
+ )
93
+ self._fixtures.insert_model(wrap)
94
+ return True
95
+
96
+ def query_ids(self, model_type: str) -> List[int]:
97
+ return list(self._fixtures[model_type].elements_by_id.keys())
98
+
99
+ def query_names(self, model_type: str) -> List[str]:
100
+ return list(self._fixtures[model_type].elements_by_name.keys())
101
+
102
+ def query_item(
103
+ self, model_type: str, uid: Optional[int] = None, name: Optional[str] = None
104
+ ) -> dict:
105
+ if uid is not None:
106
+ return self._fixtures[model_type].query_id(uid)
107
+ if name is not None:
108
+ return self._fixtures[model_type].query_name(name)
109
+ raise ValueError("Query needs either uid or name of object")
110
+
111
+ def try_inheritance(self, model_type: str, values: dict) -> (dict, list):
112
+ return self._fixtures[model_type].inheritance(values)
113
+
114
+ def fill_in_user_data(self, values: dict) -> dict:
115
+ """Add fake user-data when offline-client is used.
116
+
117
+ Hotfix until WebClient is working.
118
+ """
119
+ if values.get("owner") is None:
120
+ values["owner"] = "unknown"
121
+ if values.get("group") is None:
122
+ values["group"] = "unknown"
123
+ return values
124
+
125
+
126
+ tb_client: AbcClient = FixturesClient()
@@ -0,0 +1,157 @@
1
+ """Client-Class to access a testbed instance over the web."""
2
+
3
+ from importlib import import_module
4
+ from pathlib import Path
5
+ from typing import List
6
+ from typing import Optional
7
+ from typing import Union
8
+
9
+ from pydantic import validate_call
10
+
11
+ from ..commons import testbed_server_default
12
+ from ..data_models.base.shepherd import ShpModel
13
+ from ..data_models.base.wrapper import Wrapper
14
+ from .client_abc_fix import AbcClient
15
+ from .user_model import User
16
+
17
+
18
+ class WebClient(AbcClient):
19
+ """Client-Class to access a testbed instance over the web.
20
+
21
+ For online-queries the lib can be connected to the testbed-server.
22
+ NOTE: there are 3 states:
23
+ - unconnected -> demo-fixtures are queried (locally)
24
+ - connected -> publicly available data is queried online
25
+ - logged in with valid token -> also private data is queried online
26
+ """
27
+
28
+ testbed_server_default = "https://shepherd.cfaed.tu-dresden.de:8000/testbed"
29
+
30
+ def __init__(self, server: Optional[str] = None, token: Union[str, Path, None] = None) -> None:
31
+ """Connect to Testbed-Server with optional token and server-address.
32
+
33
+ server: optional address to shepherd-server-endpoint
34
+ token: your account validation. if omitted, only public data is available
35
+ """
36
+ super().__init__()
37
+ if not hasattr(self, "_token"):
38
+ # add default values
39
+ self._token: str = "basic_public_access"
40
+ self._server: str = testbed_server_default
41
+ self._user: Optional[User] = None
42
+ self._key: Optional[str] = None
43
+ self._connected: bool = False
44
+ self._req = None
45
+
46
+ if not self._connected:
47
+ self._connect(server, token)
48
+
49
+ # ABC Functions below
50
+
51
+ def insert(self, data: ShpModel) -> bool:
52
+ wrap = Wrapper(
53
+ datatype=type(data).__name__,
54
+ parameters=data.model_dump(),
55
+ )
56
+ r = self._req.post(self._server + "/add", data=wrap.model_dump_json(), timeout=2)
57
+ r.raise_for_status()
58
+ return True
59
+
60
+ def query_ids(self, model_type: str) -> List[int]:
61
+ raise NotImplementedError("TODO")
62
+
63
+ def query_names(self, model_type: str) -> List[str]:
64
+ raise NotImplementedError("TODO")
65
+
66
+ def query_item(
67
+ self, model_type: str, uid: Optional[int] = None, name: Optional[str] = None
68
+ ) -> dict:
69
+ raise NotImplementedError("TODO")
70
+
71
+ def try_inheritance(self, model_type: str, values: dict) -> (dict, list):
72
+ raise NotImplementedError("TODO")
73
+
74
+ def fill_in_user_data(self, values: dict) -> dict:
75
+ if values.get("owner") is None:
76
+ values["owner"] = self._user.name
77
+ if values.get("group") is None:
78
+ values["group"] = self._user.group
79
+ return values
80
+
81
+ # Below are extra FNs not in ABC
82
+
83
+ @validate_call
84
+ def _connect(self, server: Optional[str] = None, token: Union[str, Path, None] = None) -> bool:
85
+ """Establish connection to testbed-server.
86
+
87
+ TODO: totally not finished
88
+ """
89
+ if isinstance(token, Path):
90
+ if not token.exists():
91
+ raise FileNotFoundError("Token-Path does not exist")
92
+ with token.resolve().open() as file:
93
+ self._token = file.read()
94
+ elif isinstance(token, str):
95
+ self._token = self._token
96
+
97
+ if isinstance(server, str):
98
+ self._server = server.lower()
99
+
100
+ self._req = import_module("requests") # here due to slow startup
101
+
102
+ # extended connection-test:
103
+ self._query_session_key()
104
+ self._connected = True
105
+ return self._query_user_data()
106
+
107
+ def _query_session_key(self) -> bool:
108
+ if self._server:
109
+ r = self._req.get(self._server + "/session_key", timeout=2)
110
+ r.raise_for_status()
111
+ self._key = r.json()["value"] # TODO: not finished
112
+ return True
113
+ return False
114
+
115
+ def _query_user_data(self) -> bool:
116
+ if self._server:
117
+ r = self._req.get(self._server + "/user?token=" + self._token, timeout=2)
118
+ # TODO: possibly a security nightmare (send via json or encrypted via public key?)
119
+ r.raise_for_status()
120
+ self._user = User(**r.json())
121
+ return True
122
+ return False
123
+
124
+ def submit_experiment(self, xp: ShpModel) -> str:
125
+ """Transmit XP to server to validate its feasibility.
126
+
127
+ - Experiment will be added to DB (if not present)
128
+ - if the same experiment is resubmitted it will just return the ID of that XP
129
+ - Experiment will be validated by converting it into a task-set (additional validation)
130
+ - optional: the scheduler should validate there are no time-collisions
131
+
132
+ Will return an ID if valid, otherwise an empty string.
133
+ TODO: maybe its better to throw specific errors if validation fails
134
+ TODO: is it better to include these experiment-related FNs in Xp-Class?
135
+ TODO: Experiment-typehint for argument triggers circular import
136
+ """
137
+ raise NotImplementedError("TODO")
138
+
139
+ def schedule_experiment(self, id_xp: str) -> bool:
140
+ """Enqueue XP on testbed."""
141
+ raise NotImplementedError("TODO")
142
+
143
+ def get_experiment_status(self, id_xp: str) -> str:
144
+ """Ask server about current state of XP.
145
+
146
+ - after valid submission: disabled / deactivated
147
+ - after scheduling: scheduled
148
+ - before start-time: preparing
149
+ - during run: active
150
+ - after run: post-processing (collecting & assembling data)
151
+ - finished: ready to download
152
+ """
153
+ raise NotImplementedError("TODO")
154
+
155
+ def get_experiment_results(self, id_xp: str, path: Path) -> bool:
156
+ """Download resulting files."""
157
+ raise NotImplementedError("TODO")
@@ -183,12 +183,18 @@ class Fixtures:
183
183
  else:
184
184
  self.file_path = file_path
185
185
  self.components: Dict[str, Fixture] = {}
186
- save_path = cache_user_path / "fixtures.pickle"
187
-
188
- if save_path.exists() and not file_older_than(save_path, timedelta(hours=24)) and not reset:
189
- # speedup
186
+ cache_file = cache_user_path / "fixtures.pickle"
187
+ sheep_detect = Path("/lib/firmware/am335x-pru0-fw").exists()
188
+
189
+ if (
190
+ not sheep_detect
191
+ and cache_file.exists()
192
+ and not file_older_than(cache_file, timedelta(hours=24))
193
+ and not reset
194
+ ):
195
+ # speedup by loading from cache
190
196
  # TODO: also add version as criterion
191
- with save_path.open("rb", buffering=-1) as fd:
197
+ with cache_file.open("rb", buffering=-1) as fd:
192
198
  self.components = pickle.load(fd) # noqa: S301
193
199
  logger.debug(" -> found & used pickled fixtures")
194
200
  else:
@@ -204,9 +210,9 @@ class Fixtures:
204
210
 
205
211
  if len(self.components) < 1:
206
212
  logger.error(f"No fixture-components found at {self.file_path.as_posix()}")
207
- else:
208
- save_path.parent.mkdir(parents=True, exist_ok=True)
209
- with save_path.open("wb", buffering=-1) as fd:
213
+ elif sheep_detect:
214
+ cache_file.parent.mkdir(parents=True, exist_ok=True)
215
+ with cache_file.open("wb", buffering=-1) as fd:
210
216
  pickle.dump(self.components, fd)
211
217
 
212
218
  @validate_call