shepherd-core 2025.5.3__py3-none-any.whl → 2025.6.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. shepherd_core/__init__.py +2 -2
  2. shepherd_core/commons.py +3 -5
  3. shepherd_core/config.py +34 -0
  4. shepherd_core/data_models/__init__.py +1 -1
  5. shepherd_core/data_models/base/calibration.py +13 -8
  6. shepherd_core/data_models/base/shepherd.py +28 -11
  7. shepherd_core/data_models/base/wrapper.py +4 -4
  8. shepherd_core/data_models/content/energy_environment.py +1 -1
  9. shepherd_core/data_models/content/firmware.py +13 -8
  10. shepherd_core/data_models/content/virtual_harvester.py +13 -13
  11. shepherd_core/data_models/content/virtual_source.py +41 -33
  12. shepherd_core/data_models/content/virtual_source_fixture.yaml +1 -1
  13. shepherd_core/data_models/experiment/experiment.py +28 -18
  14. shepherd_core/data_models/experiment/observer_features.py +32 -13
  15. shepherd_core/data_models/experiment/target_config.py +17 -7
  16. shepherd_core/data_models/task/__init__.py +8 -4
  17. shepherd_core/data_models/task/emulation.py +52 -30
  18. shepherd_core/data_models/task/firmware_mod.py +15 -6
  19. shepherd_core/data_models/task/harvest.py +19 -13
  20. shepherd_core/data_models/task/helper_paths.py +15 -0
  21. shepherd_core/data_models/task/observer_tasks.py +20 -18
  22. shepherd_core/data_models/task/programming.py +10 -4
  23. shepherd_core/data_models/task/testbed_tasks.py +16 -7
  24. shepherd_core/data_models/testbed/cape_fixture.yaml +1 -1
  25. shepherd_core/data_models/testbed/observer.py +1 -1
  26. shepherd_core/data_models/testbed/observer_fixture.yaml +2 -2
  27. shepherd_core/data_models/testbed/target.py +1 -1
  28. shepherd_core/data_models/testbed/target_fixture.old1 +1 -1
  29. shepherd_core/data_models/testbed/target_fixture.yaml +1 -1
  30. shepherd_core/data_models/testbed/testbed.py +8 -9
  31. shepherd_core/decoder_waveform/uart.py +7 -7
  32. shepherd_core/fw_tools/patcher.py +13 -14
  33. shepherd_core/fw_tools/validation.py +2 -2
  34. shepherd_core/inventory/system.py +3 -5
  35. shepherd_core/logger.py +3 -3
  36. shepherd_core/reader.py +9 -2
  37. shepherd_core/testbed_client/cache_path.py +1 -1
  38. shepherd_core/testbed_client/client_web.py +2 -2
  39. shepherd_core/testbed_client/fixtures.py +5 -5
  40. shepherd_core/version.py +1 -1
  41. shepherd_core/vsource/virtual_harvester_model.py +2 -2
  42. shepherd_core/vsource/virtual_source_simulation.py +2 -2
  43. shepherd_core/writer.py +2 -2
  44. {shepherd_core-2025.5.3.dist-info → shepherd_core-2025.6.2.dist-info}/METADATA +12 -12
  45. shepherd_core-2025.6.2.dist-info/RECORD +83 -0
  46. {shepherd_core-2025.5.3.dist-info → shepherd_core-2025.6.2.dist-info}/WHEEL +1 -1
  47. shepherd_core-2025.5.3.dist-info/RECORD +0 -81
  48. {shepherd_core-2025.5.3.dist-info → shepherd_core-2025.6.2.dist-info}/top_level.txt +0 -0
  49. {shepherd_core-2025.5.3.dist-info → shepherd_core-2025.6.2.dist-info}/zip-safe +0 -0
@@ -1,12 +1,15 @@
1
1
  """Collection of tasks for all observers included in experiment."""
2
2
 
3
3
  from pathlib import Path
4
+ from pathlib import PurePosixPath
5
+ from typing import TYPE_CHECKING
4
6
  from typing import Annotated
5
7
  from typing import Optional
6
8
 
7
9
  from pydantic import Field
8
10
  from pydantic import validate_call
9
11
  from typing_extensions import Self
12
+ from typing_extensions import deprecated
10
13
 
11
14
  from shepherd_core.data_models.base.content import IdInt
12
15
  from shepherd_core.data_models.base.content import NameStr
@@ -16,6 +19,9 @@ from shepherd_core.data_models.testbed.testbed import Testbed
16
19
 
17
20
  from .observer_tasks import ObserverTasks
18
21
 
22
+ if TYPE_CHECKING:
23
+ from collections.abc import Set as AbstractSet
24
+
19
25
 
20
26
  class TestbedTasks(ShpModel):
21
27
  """Collection of tasks for all observers included in experiment."""
@@ -23,11 +29,9 @@ class TestbedTasks(ShpModel):
23
29
  name: NameStr
24
30
  observer_tasks: Annotated[list[ObserverTasks], Field(min_length=1, max_length=128)]
25
31
 
26
- # POST PROCESS
27
- email_results: bool = False
28
- owner_id: Optional[IdInt]
29
- # TODO: had real email previously, does it really need these at all?
30
- # DB stores experiment and knows when to email
32
+ # deprecated, TODO: remove before public release
33
+ email_results: Annotated[Optional[bool], deprecated("not needed anymore")] = False
34
+ owner_id: Annotated[Optional[IdInt], deprecated("not needed anymore")] = None
31
35
 
32
36
  @classmethod
33
37
  @validate_call
@@ -41,8 +45,6 @@ class TestbedTasks(ShpModel):
41
45
  return cls(
42
46
  name=xp.name,
43
47
  observer_tasks=obs_tasks,
44
- email_results=xp.email_results,
45
- owner_id=xp.owner_id,
46
48
  )
47
49
 
48
50
  def get_observer_tasks(self, observer: str) -> Optional[ObserverTasks]:
@@ -59,3 +61,10 @@ class TestbedTasks(ShpModel):
59
61
  for obt in self.observer_tasks:
60
62
  values = {**values, **obt.get_output_paths()}
61
63
  return values
64
+
65
+ def is_contained(self) -> bool:
66
+ paths_allowed: AbstractSet[PurePosixPath] = {
67
+ PurePosixPath("/var/shepherd/"),
68
+ PurePosixPath("/tmp/"), # noqa: S108
69
+ }
70
+ return all(obt.is_contained(paths_allowed) for obt in self.observer_tasks)
@@ -1,7 +1,7 @@
1
1
  ---
2
2
 
3
3
  # more human-readable test-protocol @
4
- # https://github.com/orgua/shepherd_v2_planning/blob/main/doc_testbed/Cape_pre-deployment-tests.xlsx
4
+ # https://github.com/orgua/shepherd-v2-planning/blob/main/doc_testbed/Cape_pre-deployment-tests.xlsx
5
5
  - datatype: cape
6
6
  parameters:
7
7
  id: 1270051
@@ -43,7 +43,7 @@ class Observer(ShpModel, title="Shepherd-Sheep"):
43
43
 
44
44
  latitude: Annotated[float, Field(ge=-90, le=90)] = 51.026573
45
45
  longitude: Annotated[float, Field(ge=-180, le=180)] = 13.723291
46
- # ⤷ cfaed-floor
46
+ """ ⤷ cfaed-floor"""
47
47
 
48
48
  active: bool = True
49
49
  cape: Optional[Cape] = None
@@ -1,6 +1,6 @@
1
1
  ---
2
- # observer-cape-target-relation: https://github.com/orgua/shepherd_v2_planning/blob/main/doc_testbed/Cape_pre-deployment-tests.xlsx
3
- # network data: https://github.com/orgua/shepherd_v2_planning/blob/main/doc_testbed/ethernet_MAC_addresses_bbones.ods
2
+ # observer-cape-target-relation: https://github.com/orgua/shepherd-v2-planning/blob/main/doc_testbed/Cape_pre-deployment-tests.xlsx
3
+ # network data: https://github.com/orgua/shepherd-v2-planning/blob/main/doc_testbed/ethernet_MAC_addresses_bbones.ods
4
4
  - datatype: observer
5
5
  parameters:
6
6
  id: 0
@@ -36,7 +36,7 @@ class Target(ShpModel, title="Target Node (DuT)"):
36
36
  created: datetime = Field(default_factory=datetime.now)
37
37
 
38
38
  testbed_id: Optional[IdInt16] = None
39
- # ⤷ is derived from ID (targets are still selected by id!)
39
+ """ ⤷ is derived from ID (targets are still selected by id!)"""
40
40
  mcu1: Union[MCU, NameStr]
41
41
  mcu2: Union[MCU, NameStr, None] = None
42
42
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  # more human-readable test-protocol @
3
- # https://github.com/orgua/shepherd_v2_planning/blob/main/doc_testbed/Target_pre-deployment-tests.xlsx
3
+ # https://github.com/orgua/shepherd-v2-planning/blob/main/doc_testbed/Target_pre-deployment-tests.xlsx
4
4
  - datatype: target
5
5
  parameters:
6
6
  id: 6 # Outer ID - selected by user for XP - can be rearranged
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  # more human-readable test-protocol @
3
- # https://github.com/orgua/shepherd_v2_planning/blob/main/doc_testbed/Target_pre-deployment-tests.xlsx
3
+ # https://github.com/orgua/shepherd-v2-planning/blob/main/doc_testbed/Target_pre-deployment-tests.xlsx
4
4
  - datatype: target
5
5
  parameters:
6
6
  id: 2 # Outer ID - selected by user for XP - can be rearranged
@@ -11,15 +11,17 @@ from pydantic import HttpUrl
11
11
  from pydantic import model_validator
12
12
  from typing_extensions import Self
13
13
 
14
+ from shepherd_core.config import config
14
15
  from shepherd_core.data_models.base.content import IdInt
15
16
  from shepherd_core.data_models.base.content import NameStr
16
17
  from shepherd_core.data_models.base.content import SafeStr
17
18
  from shepherd_core.data_models.base.shepherd import ShpModel
18
- from shepherd_core.logger import logger
19
19
  from shepherd_core.testbed_client import tb_client
20
20
 
21
21
  from .observer import Observer
22
22
 
23
+ duration_5min = timedelta(minutes=5)
24
+
23
25
 
24
26
  class Testbed(ShpModel):
25
27
  """meta-data representation of a testbed-component (physical object)."""
@@ -36,21 +38,18 @@ class Testbed(ShpModel):
36
38
  shared_storage: bool = True
37
39
  data_on_server: Path
38
40
  data_on_observer: Path
39
- # ⤷ storage layout: root_path/content_type/group/owner/[object]
41
+ """ ⤷ storage layout: root_path/content_type/group/owner/[object]"""
42
+ # TODO: we might need individual paths for experiments & content
40
43
 
41
- prep_duration: timedelta = timedelta(minutes=5)
44
+ prep_duration: timedelta = duration_5min
42
45
  # TODO: one BBone is currently time-keeper
43
46
 
44
47
  @model_validator(mode="before")
45
48
  @classmethod
46
49
  def query_database(cls, values: dict[str, Any]) -> dict[str, Any]:
47
- # allow instantiating an empty Testbed
48
- # -> query the first (and only) entry of client
50
+ # allow instantiating an empty Testbed, take default in config
49
51
  if len(values) == 0:
50
- ids = tb_client.query_ids(cls.__name__)
51
- if len(ids) > 1:
52
- logger.warning("More than one testbed defined?!?")
53
- values = {"id": ids[0]}
52
+ values = {"name": config.TESTBED}
54
53
 
55
54
  values, _ = tb_client.try_completing_model(cls.__name__, values)
56
55
  return values
@@ -28,7 +28,7 @@ from typing import Union
28
28
 
29
29
  import numpy as np
30
30
 
31
- from shepherd_core.logger import logger
31
+ from shepherd_core.logger import log
32
32
 
33
33
 
34
34
  class Parity(str, Enum):
@@ -109,10 +109,10 @@ class Uart:
109
109
  raise ValueError("Only bit-order LSB-first is supported ATM")
110
110
 
111
111
  if self.inversion:
112
- logger.debug("inversion was detected / issued -> will invert signal")
112
+ log.debug("inversion was detected / issued -> will invert signal")
113
113
  self._convert_analog2digital(invert=True)
114
114
  if self.detect_inversion():
115
- logger.error("Signal still inverted?!? Check parameters and input")
115
+ log.error("Signal still inverted?!? Check parameters and input")
116
116
 
117
117
  # results
118
118
  self.events_symbols: Optional[np.ndarray] = None
@@ -136,7 +136,7 @@ class Uart:
136
136
  self.events_sig = self.events_sig[data_f == 1]
137
137
 
138
138
  if len(data_0) > len(self.events_sig):
139
- logger.debug(
139
+ log.debug(
140
140
  "filtered out %d/%d events (redundant)",
141
141
  len(data_0) - len(self.events_sig),
142
142
  len(data_0),
@@ -145,7 +145,7 @@ class Uart:
145
145
  def _add_duration(self) -> None:
146
146
  """Calculate third column -> duration of state in [baud-ticks]."""
147
147
  if self.events_sig.shape[1] > 2:
148
- logger.warning("Tried to add state-duration, but it seems already present")
148
+ log.warning("Tried to add state-duration, but it seems already present")
149
149
  return
150
150
  if not hasattr(self, "dur_tick"):
151
151
  raise ValueError("Make sure that baud-rate was calculated before running add_dur()")
@@ -223,7 +223,7 @@ class Uart:
223
223
  symbol = 0
224
224
  pos_df = None
225
225
  else:
226
- logger.debug("Error - Long pause - but SigLow (@%d)", time)
226
+ log.debug("Error - Long pause - but SigLow (@%d)", time)
227
227
  continue
228
228
  if pos_df is None and value == 0:
229
229
  # Start of frame (first low after pause / EOF)
@@ -245,7 +245,7 @@ class Uart:
245
245
  symbol = 0
246
246
  pos_df = None
247
247
  if off_tick and value == 0:
248
- logger.debug("Error - Off-sized step - but SigLow (@%d)", time)
248
+ log.debug("Error - Off-sized step - but SigLow (@%d)", time)
249
249
  self.events_symbols = np.concatenate(content).reshape((len(content), 2))
250
250
  # TODO: numpy is converting timestamp to string -> must be added as tuple (ts, symbol)
251
251
  # symbol_events[:, 0] = symbol_events[:, 0].astype(float) # noqa: ERA001
@@ -7,9 +7,8 @@ from typing import Optional
7
7
  from pydantic import Field
8
8
  from pydantic import validate_call
9
9
 
10
- from shepherd_core.commons import UID_NAME
11
- from shepherd_core.commons import UID_SIZE
12
- from shepherd_core.logger import logger
10
+ from shepherd_core.config import config
11
+ from shepherd_core.logger import log
13
12
 
14
13
  from .validation import is_elf
15
14
 
@@ -36,9 +35,9 @@ def find_symbol(file_elf: Path, symbol: str) -> bool:
36
35
  except KeyError:
37
36
  addr = None
38
37
  if addr is None:
39
- logger.debug("Symbol '%s' not found in ELF-File %s", symbol, file_elf.name)
38
+ log.debug("Symbol '%s' not found in ELF-File %s", symbol, file_elf.name)
40
39
  return False
41
- logger.debug(
40
+ log.debug(
42
41
  "Symbol '%s' found in ELF-File %s, arch=%s, order=%s",
43
42
  symbol,
44
43
  file_elf.name,
@@ -50,7 +49,7 @@ def find_symbol(file_elf: Path, symbol: str) -> bool:
50
49
 
51
50
 
52
51
  @validate_call
53
- def read_symbol(file_elf: Path, symbol: str, length: int = UID_SIZE) -> Optional[int]:
52
+ def read_symbol(file_elf: Path, symbol: str, length: int) -> Optional[int]:
54
53
  """Read value of symbol in ELF-File.
55
54
 
56
55
  Will be interpreted as int.
@@ -68,7 +67,7 @@ def read_symbol(file_elf: Path, symbol: str, length: int = UID_SIZE) -> Optional
68
67
 
69
68
  def read_uid(file_elf: Path) -> Optional[int]:
70
69
  """Read value of UID-symbol for shepherd testbed."""
71
- return read_symbol(file_elf, symbol=UID_NAME, length=UID_SIZE)
70
+ return read_symbol(file_elf, symbol=config.UID_NAME, length=config.UID_SIZE)
72
71
 
73
72
 
74
73
  def read_arch(file_elf: Path) -> Optional[str]:
@@ -80,7 +79,7 @@ def read_arch(file_elf: Path) -> Optional[str]:
80
79
  elf = ELF(path=file_elf)
81
80
  if "exec" in elf.elftype.lower():
82
81
  return elf.arch.lower()
83
- logger.error("ELF is not Executable")
82
+ log.error("ELF is not Executable")
84
83
  return None
85
84
 
86
85
 
@@ -88,7 +87,7 @@ def read_arch(file_elf: Path) -> Optional[str]:
88
87
  def modify_symbol_value(
89
88
  file_elf: Path,
90
89
  symbol: str,
91
- value: Annotated[int, Field(ge=0, lt=2 ** (8 * UID_SIZE))],
90
+ value: Annotated[int, Field(ge=0, lt=2 ** (8 * config.UID_SIZE))],
92
91
  *,
93
92
  overwrite: bool = False,
94
93
  ) -> Optional[Path]:
@@ -106,21 +105,21 @@ def modify_symbol_value(
106
105
  raise RuntimeError(elf_error_text)
107
106
  elf = ELF(path=file_elf)
108
107
  addr = elf.symbols[symbol]
109
- value_raw = elf.read(address=addr, count=UID_SIZE)[-UID_SIZE:]
108
+ value_raw = elf.read(address=addr, count=config.UID_SIZE)[-config.UID_SIZE :]
110
109
  # ⤷ cutting needed -> msp produces 4b instead of 2
111
110
  value_old = int.from_bytes(bytes=value_raw, byteorder=elf.endian, signed=False)
112
- value_raw = value.to_bytes(length=UID_SIZE, byteorder=elf.endian, signed=False)
111
+ value_raw = value.to_bytes(length=config.UID_SIZE, byteorder=elf.endian, signed=False)
113
112
 
114
113
  try:
115
114
  elf.write(address=addr, data=value_raw)
116
115
  except AttributeError:
117
- logger.warning("ELF-Modifier failed @%s for symbol '%s'", f"0x{addr:X}", symbol)
116
+ log.warning("ELF-Modifier failed @%s for symbol '%s'", f"0x{addr:X}", symbol)
118
117
  return None
119
118
 
120
119
  file_new = file_elf if overwrite else file_elf.with_stem(file_elf.stem + "_" + str(value))
121
120
  elf.save(path=file_new)
122
121
  elf.close()
123
- logger.debug(
122
+ log.debug(
124
123
  "Value of Symbol '%s' modified: %s -> %s @%s",
125
124
  symbol,
126
125
  hex(value_old),
@@ -132,4 +131,4 @@ def modify_symbol_value(
132
131
 
133
132
  def modify_uid(file_elf: Path, value: int) -> Optional[Path]:
134
133
  """Replace value of UID-symbol for shepherd testbed."""
135
- return modify_symbol_value(file_elf, symbol=UID_NAME, value=value, overwrite=True)
134
+ return modify_symbol_value(file_elf, symbol=config.UID_NAME, value=value, overwrite=True)
@@ -13,7 +13,7 @@ from intelhex import IntelHexError
13
13
  from pydantic import validate_call
14
14
 
15
15
  from shepherd_core.data_models.content.firmware_datatype import FirmwareDType
16
- from shepherd_core.logger import logger
16
+ from shepherd_core.logger import log
17
17
 
18
18
  from .converter_elf import elf_to_hex
19
19
 
@@ -94,7 +94,7 @@ def is_elf(file: Path) -> bool:
94
94
  try:
95
95
  _ = ELF(path=file)
96
96
  except ELFError:
97
- logger.debug("File %s is not ELF - Magic number does not match", file.name)
97
+ log.debug("File %s is not ELF - Magic number does not match", file.name)
98
98
  return False
99
99
  return True
100
100
 
@@ -14,7 +14,7 @@ from typing import Optional
14
14
  from typing_extensions import Self
15
15
 
16
16
  from shepherd_core.data_models.base.timezone import local_now
17
- from shepherd_core.logger import logger
17
+ from shepherd_core.logger import log
18
18
 
19
19
  try:
20
20
  import psutil
@@ -31,10 +31,8 @@ class SystemInventory(ShpModel):
31
31
  """System / OS related inventory model."""
32
32
 
33
33
  uptime: PositiveInt
34
- # ⤷ seconds
34
+ """ ⤷ seconds"""
35
35
  timestamp: datetime
36
- # time_delta: timedelta = timedelta(seconds=0) # noqa: ERA001
37
- # ⤷ lag behind earliest observer, TODO: wrong place
38
36
 
39
37
  system: str
40
38
  release: str
@@ -64,7 +62,7 @@ class SystemInventory(ShpModel):
64
62
  if psutil is None:
65
63
  ifs2 = {}
66
64
  uptime = 0
67
- logger.warning(
65
+ log.warning(
68
66
  "Inventory-Parameters will be missing. "
69
67
  "Please install functionality with "
70
68
  "'pip install shepherd_core[inventory] -U' first"
shepherd_core/logger.py CHANGED
@@ -7,8 +7,8 @@ from typing import Union
7
7
  import chromalog
8
8
 
9
9
  chromalog.basicConfig(format="%(message)s")
10
- logger = logging.getLogger("SHPCore")
11
- logger.addHandler(logging.NullHandler())
10
+ log = logging.getLogger("SHPCore")
11
+ log.addHandler(logging.NullHandler())
12
12
 
13
13
  verbose_level: int = 2
14
14
 
@@ -47,7 +47,7 @@ def increase_verbose_level(verbose: int) -> None:
47
47
  global verbose_level # noqa: PLW0603
48
48
  if verbose >= verbose_level:
49
49
  verbose_level = min(max(verbose, 0), 3)
50
- set_log_verbose_level(logger, verbose_level)
50
+ set_log_verbose_level(log, verbose_level)
51
51
 
52
52
 
53
53
  increase_verbose_level(2)
shepherd_core/reader.py CHANGED
@@ -7,6 +7,7 @@ import errno
7
7
  import logging
8
8
  import math
9
9
  import os
10
+ from datetime import datetime
10
11
  from itertools import product
11
12
  from pathlib import Path
12
13
  from types import MappingProxyType
@@ -24,9 +25,10 @@ from tqdm import trange
24
25
  from typing_extensions import Self
25
26
  from typing_extensions import deprecated
26
27
 
27
- from .commons import SAMPLERATE_SPS_DEFAULT
28
+ from .config import config
28
29
  from .data_models.base.calibration import CalibrationPair
29
30
  from .data_models.base.calibration import CalibrationSeries
31
+ from .data_models.base.timezone import local_tz
30
32
  from .data_models.content.energy_environment import EnergyDType
31
33
  from .decoder_waveform import Uart
32
34
 
@@ -75,7 +77,7 @@ class Reader:
75
77
  self._logger.setLevel(logging.DEBUG if verbose else logging.INFO)
76
78
 
77
79
  if not hasattr(self, "samplerate_sps"):
78
- self.samplerate_sps: int = SAMPLERATE_SPS_DEFAULT
80
+ self.samplerate_sps: int = config.SAMPLERATE_SPS
79
81
  self.sample_interval_ns: int = round(10**9 // self.samplerate_sps)
80
82
  self.sample_interval_s: float = 1 / self.samplerate_sps
81
83
 
@@ -263,6 +265,11 @@ class Reader:
263
265
  omit_timestamps=omit_ts,
264
266
  )
265
267
 
268
+ def get_time_start(self) -> Optional[datetime]:
269
+ if self.samples_n < 1:
270
+ return None
271
+ return datetime.fromtimestamp(self._cal.time.raw_to_si(self.ds_time[0]), tz=local_tz())
272
+
266
273
  def get_calibration_data(self) -> CalibrationSeries:
267
274
  """Read calibration-data from hdf5 file.
268
275
 
@@ -14,4 +14,4 @@ def _get_xdg_path(variable_name: str, default_path: Path) -> Path:
14
14
  user_path = Path("~").expanduser()
15
15
 
16
16
  cache_xdg_path = _get_xdg_path("XDG_CACHE_HOME", user_path / ".cache")
17
- cache_user_path = cache_xdg_path / "shepherd_datalib"
17
+ cache_user_path = cache_xdg_path / "shepherd"
@@ -8,7 +8,7 @@ from typing import Union
8
8
 
9
9
  from pydantic import validate_call
10
10
 
11
- from shepherd_core.commons import TESTBED_SERVER_URI
11
+ from shepherd_core.config import config
12
12
  from shepherd_core.data_models.base.shepherd import ShpModel
13
13
  from shepherd_core.data_models.base.wrapper import Wrapper
14
14
 
@@ -38,7 +38,7 @@ class WebClient(AbcClient):
38
38
  if not hasattr(self, "_token"):
39
39
  # add default values
40
40
  self._token: str = "basic_public_access" # noqa: S105
41
- self._server: str = TESTBED_SERVER_URI
41
+ self._server: str = config.TESTBED_SERVER
42
42
  self._user: Optional[User] = None
43
43
  self._key: Optional[str] = None
44
44
  self._connected: bool = False
@@ -18,7 +18,7 @@ from typing_extensions import Self
18
18
  from shepherd_core.data_models.base.timezone import local_now
19
19
  from shepherd_core.data_models.base.timezone import local_tz
20
20
  from shepherd_core.data_models.base.wrapper import Wrapper
21
- from shepherd_core.logger import logger
21
+ from shepherd_core.logger import log
22
22
 
23
23
  from .cache_path import cache_user_path
24
24
 
@@ -109,7 +109,7 @@ class Fixture:
109
109
  raise ValueError(msg)
110
110
  chain.append(base_name)
111
111
  fixture_base = copy.copy(self[fixture_name])
112
- logger.debug("'%s' will inherit from '%s'", self.model_type, fixture_name)
112
+ log.debug("'%s' will inherit from '%s'", self.model_type, fixture_name)
113
113
  fixture_base["name"] = fixture_name
114
114
  chain.append(fixture_name)
115
115
  base_dict, chain = self.inheritance(values=fixture_base, chain=chain)
@@ -196,7 +196,7 @@ class Fixtures:
196
196
  # TODO: also add version as criterion
197
197
  with cache_file.open("rb", buffering=-1) as fd:
198
198
  self.components = pickle.load(fd) # noqa: S301
199
- logger.debug(" -> found & used pickled fixtures")
199
+ log.debug(" -> found & used pickled fixtures")
200
200
  else:
201
201
  if self.file_path.is_file():
202
202
  files = [self.file_path]
@@ -204,7 +204,7 @@ class Fixtures:
204
204
  files = list(
205
205
  self.file_path.glob("**/*" + self.suffix)
206
206
  ) # for py>=3.12: case_sensitive=False
207
- logger.debug(" -> got %s %s-files", len(files), self.suffix)
207
+ log.debug(" -> got %s %s-files", len(files), self.suffix)
208
208
  else:
209
209
  raise ValueError("Path must either be file or directory (or empty)")
210
210
 
@@ -212,7 +212,7 @@ class Fixtures:
212
212
  self.insert_file(file)
213
213
 
214
214
  if len(self.components) < 1:
215
- logger.error(f"No fixture-components found at {self.file_path.as_posix()}")
215
+ log.error(f"No fixture-components found at {self.file_path.as_posix()}")
216
216
  elif sheep_detect:
217
217
  cache_file.parent.mkdir(parents=True, exist_ok=True)
218
218
  with cache_file.open("wb", buffering=-1) as fd:
shepherd_core/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Separated string avoids circular imports."""
2
2
 
3
- version: str = "2025.05.3"
3
+ version: str = "2025.06.2"
@@ -17,7 +17,7 @@ Compromises:
17
17
  """
18
18
 
19
19
  from shepherd_core.data_models.content.virtual_harvester import HarvesterPRUConfig
20
- from shepherd_core.logger import logger
20
+ from shepherd_core.logger import log
21
21
 
22
22
 
23
23
  class VirtualHarvesterModel:
@@ -37,7 +37,7 @@ class VirtualHarvesterModel:
37
37
 
38
38
  self.is_emu: bool = bool(self._cfg.hrv_mode & (2**0))
39
39
  if not self.is_emu:
40
- logger.warning(
40
+ log.warning(
41
41
  "This VSrc-config is not meant for emulation-mode -> activate 'is_emu' flag."
42
42
  )
43
43
 
@@ -16,7 +16,7 @@ from tqdm import tqdm
16
16
 
17
17
  from shepherd_core.data_models.base.calibration import CalibrationEmulator
18
18
  from shepherd_core.data_models.content.virtual_source import VirtualSourceConfig
19
- from shepherd_core.logger import logger
19
+ from shepherd_core.logger import log
20
20
  from shepherd_core.reader import Reader
21
21
  from shepherd_core.writer import Writer
22
22
 
@@ -68,7 +68,7 @@ def simulate_source(
68
68
  # keep dependencies low
69
69
  from matplotlib import pyplot as plt
70
70
  except ImportError:
71
- logger.warning("Matplotlib not installed, plotting of internals disabled")
71
+ log.warning("Matplotlib not installed, plotting of internals disabled")
72
72
  stats_internal = None
73
73
  else:
74
74
  stats_internal = None
shepherd_core/writer.py CHANGED
@@ -20,7 +20,7 @@ from typing_extensions import Self
20
20
  from yaml import Node
21
21
  from yaml import SafeDumper
22
22
 
23
- from .commons import SAMPLERATE_SPS_DEFAULT
23
+ from .config import config
24
24
  from .data_models.base.calibration import CalibrationEmulator as CalEmu
25
25
  from .data_models.base.calibration import CalibrationHarvester as CalHrv
26
26
  from .data_models.base.calibration import CalibrationSeries as CalSeries
@@ -348,7 +348,7 @@ class Writer(Reader):
348
348
  chunks_n = self.ds_voltage.size / self.CHUNK_SAMPLES_N
349
349
  size_new = int(math.floor(chunks_n) * self.CHUNK_SAMPLES_N)
350
350
  if size_new < self.ds_voltage.size:
351
- if self.samplerate_sps != SAMPLERATE_SPS_DEFAULT:
351
+ if self.samplerate_sps != config.SAMPLERATE_SPS:
352
352
  self._logger.debug("skipped alignment due to altered samplerate")
353
353
  return
354
354
  self._logger.info(
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shepherd_core
3
- Version: 2025.5.3
3
+ Version: 2025.6.2
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>
7
- Project-URL: Documentation, https://github.com/orgua/shepherd-datalib/blob/main/README.md
8
- Project-URL: Issues, https://github.com/orgua/shepherd-datalib/issues
7
+ Project-URL: Documentation, https://github.com/nes-lab/shepherd-tools/blob/main/README.md
8
+ Project-URL: Issues, https://github.com/nes-lab/shepherd-tools/issues
9
9
  Project-URL: Source, https://pypi.org/project/shepherd-core/
10
10
  Keywords: testbed,beaglebone,pru,batteryless,energyharvesting,solar
11
11
  Platform: unix
@@ -56,16 +56,16 @@ Requires-Dist: coverage; extra == "test"
56
56
 
57
57
  # Core Library
58
58
 
59
- [![PyPiVersion](https://img.shields.io/pypi/v/shepherd_core.svg)](https://pypi.org/project/shepherd_core)
59
+ [![PyPIVersion](https://img.shields.io/pypi/v/shepherd_core.svg)](https://pypi.org/project/shepherd_core)
60
60
  [![image](https://img.shields.io/pypi/pyversions/shepherd_core.svg)](https://pypi.python.org/pypi/shepherd-core)
61
- [![Pytest](https://github.com/orgua/shepherd-datalib/actions/workflows/py_unittest.yml/badge.svg)](https://github.com/orgua/shepherd-datalib/actions/workflows/py_unittest.yml)
61
+ [![QA-Tests](https://github.com/nes-lab/shepherd-tools/actions/workflows/quality_assurance.yaml/badge.svg)](https://github.com/nes-lab/shepherd-tools/actions/workflows/quality_assurance.yaml)
62
62
  [![CodeStyle](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
63
63
 
64
- **Main Documentation**: <https://orgua.github.io/shepherd>
64
+ **Main Documentation**: <https://nes-lab.github.io/shepherd>
65
65
 
66
- **Source Code**: <https://github.com/orgua/shepherd-datalib>
66
+ **Source Code**: <https://github.com/nes-lab/shepherd-tools>
67
67
 
68
- **Main Project**: <https://github.com/orgua/shepherd>
68
+ **Main Project**: <https://github.com/nes-lab/shepherd>
69
69
 
70
70
  ---
71
71
 
@@ -87,7 +87,7 @@ For postprocessing shepherds .h5-files usage of [shepherd_data](https://pypi.org
87
87
  - decode waveforms (gpio-state & timestamp) to UART
88
88
  - create an inventory (for deployed versions of software, hardware)
89
89
 
90
- See [official documentation](https://orgua.github.io/shepherd) or [example scripts](https://github.com/orgua/shepherd-datalib/tree/main/shepherd_core/examples) for more details and usage. Most functionality is showcased in both. The [extra](https://github.com/orgua/shepherd-datalib/tree/main/shepherd_core/extra)-directory holds data-generators relevant for the testbed. Notably is a [trafficbench](https://github.com/orgua/TrafficBench)-experiment that's used to derive the link-matrix of the testbed-nodes.
90
+ See [official documentation](https://nes-lab.github.io/shepherd) or [example scripts](https://github.com/nes-lab/shepherd-tools/tree/main/shepherd_core/examples) for more details and usage. Most functionality is showcased in both. The [extra](https://github.com/nes-lab/shepherd-tools/tree/main/shepherd_core/extra)-directory holds data-generators relevant for the testbed. Notably is a [trafficbench](https://github.com/nes-lab/TrafficBench)-experiment that's used to derive the link-matrix of the testbed-nodes.
91
91
 
92
92
  ## Config-Models in Detail
93
93
 
@@ -145,9 +145,9 @@ pip install shepherd-data -U
145
145
  For bleeding-edge-features or dev-work it is possible to install directly from GitHub-Sources (here `dev`-branch):
146
146
 
147
147
  ```Shell
148
- pip install git+https://github.com/orgua/shepherd-datalib.git@dev#subdirectory=shepherd_core -U
148
+ pip install git+https://github.com/nes-lab/shepherd-tools.git@dev#subdirectory=shepherd_core -U
149
149
  # and on sheep with newer debian
150
- sudo pip install git+https://github.com/orgua/shepherd-datalib.git@dev#subdirectory=shepherd_core -U --break-system-packages
150
+ sudo pip install git+https://github.com/nes-lab/shepherd-tools.git@dev#subdirectory=shepherd_core -U --break-system-packages
151
151
  ```
152
152
 
153
153
  If you are working with ``.elf``-files (embedding into experiments) you make "objcopy" accessible to python. In Ubuntu, you can either install ``build-essential`` or ``binutils-$ARCH`` with arch being ``msp430`` or ``arm-none-eabi`` for the nRF52.
@@ -179,7 +179,7 @@ To run the testbench, follow these steps:
179
179
  3. run the testbench (~ 320 tests):
180
180
 
181
181
  ```Shell
182
- cd shepherd-datalib/shepherd_core
182
+ cd shepherd-tools/shepherd_core
183
183
  pip3 install ./[tests]
184
184
  pytest
185
185
  ```