shepherd-core 2025.2.2__py3-none-any.whl → 2025.4.1__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.
@@ -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:
@@ -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
 
@@ -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
shepherd_core/reader.py CHANGED
@@ -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
shepherd_core/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Separated string avoids circular imports."""
2
2
 
3
- version: str = "2025.02.2"
3
+ version: str = "2025.04.1"
shepherd_core/writer.py CHANGED
@@ -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.2
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>
@@ -2,15 +2,15 @@ shepherd_core/__init__.py,sha256=fCld2mcl0y0h6kRyPal3DP-sWXnKl_0aYWYBdg4QuUk,127
2
2
  shepherd_core/calibration_hw_def.py,sha256=_nMzgNzSnYyqcLnVCGd4tfA2e0avUXbccjmNpFhiDgo,2830
3
3
  shepherd_core/commons.py,sha256=vymKXWcy_1bz7ChzzEATUkJ4p3czCzjIdsSehVjJOY8,218
4
4
  shepherd_core/logger.py,sha256=4Q4hTI-nccOZ1_A68fo4UEctfu3pJx3IeHfa9VuDDEo,1804
5
- shepherd_core/reader.py,sha256=BxVWE-4BfDUjVh03l0SZHT5PwVN0xPEy4aP8Kr858kI,28270
6
- shepherd_core/version.py,sha256=nTwMv1ayLMflxtnNktXAuPy5XKPBgwQv7w-EtHuCMtI,76
7
- shepherd_core/writer.py,sha256=GMR-7vkOgpTNPoknBWsRsC7-b7iGMtT60-KtSKunNe8,14636
5
+ shepherd_core/reader.py,sha256=tgETZPFSPzBk2BYHZ3NyWpY9j6j23FUWv1e3oCQhc6A,28401
6
+ shepherd_core/version.py,sha256=Tb2EjULatpKtVFMAniZ_AGEWDFfyFO0ffsW-t24FgFU,76
7
+ shepherd_core/writer.py,sha256=TD5oXuOFz_PUMWYeXfePz9x2O01DLRBVNMaLcngNjFc,14666
8
8
  shepherd_core/data_models/__init__.py,sha256=bnHSP_HBOYm4WuoiHs_vyiRsWlvkyDjsarMNfKedN-Q,1836
9
- shepherd_core/data_models/readme.md,sha256=1bdfEypY_0NMhXLxOPRnLAsFca0HuHdq7_01yEWxvUs,2470
9
+ shepherd_core/data_models/readme.md,sha256=DHPVmkWqDksWomRHRTVWVHy9wXF9oMJrITgKs4Pnz2g,2494
10
10
  shepherd_core/data_models/virtual_source_doc.txt,sha256=KizMcfGKj7BnHIbaJHT7KeTF01SV__UXv01qV_DGHSs,6057
11
11
  shepherd_core/data_models/base/__init__.py,sha256=PSJ6acWViqBm0Eiom8DIgKfFVrp5lzYr8OsDvP79vwI,94
12
12
  shepherd_core/data_models/base/cal_measurement.py,sha256=YScPG7QLynbUHdjcznYqU8O5KRh0XiROGxGSk9BETMk,3357
13
- shepherd_core/data_models/base/calibration.py,sha256=k5VwAK_cwr0a6QY82Lw-9uHth5KUReFOakuOTzghoso,10725
13
+ shepherd_core/data_models/base/calibration.py,sha256=-eiN9QbuZhw1CLzmyijeMgMVzzDE85p-Q5KryFoo5x8,10788
14
14
  shepherd_core/data_models/base/content.py,sha256=13j7GSgT73xn27jgDP508thUEJR4U-nCb5n7CJ50c9Y,2463
15
15
  shepherd_core/data_models/base/shepherd.py,sha256=DNrx59o1VBuy_liJuUzZRzmTTYB73D_pUWiNyMQyjYY,6112
16
16
  shepherd_core/data_models/base/timezone.py,sha256=2T6E46hJ1DAvmqKfu6uIgCK3RSoAKjGXRyzYNaqKyjY,665
@@ -23,10 +23,10 @@ shepherd_core/data_models/content/firmware.py,sha256=rH74sJPAjUUheVv0y2Y93BeT63C
23
23
  shepherd_core/data_models/content/firmware_datatype.py,sha256=XPU9LOoT3h5qFOlE8WU0vAkw-vymNxzor9kVFyEqsWg,255
24
24
  shepherd_core/data_models/content/virtual_harvester.py,sha256=cf-DrSacZsct9e8eGoR4PX7S7RXlbxQfJHVsLR9njlM,10749
25
25
  shepherd_core/data_models/content/virtual_harvester_fixture.yaml,sha256=LZe5ue1xYhXZwB3a32sva-L4uKhkQA5AtG9JzW4B2hQ,4564
26
- shepherd_core/data_models/content/virtual_source.py,sha256=PPAphxEXvgMM7OVZ2dBkYAvJQkmj5Kb2BYFogVUs7B8,15354
26
+ shepherd_core/data_models/content/virtual_source.py,sha256=EnkjLlh14YBUnoS4yILXraLN0qdnVoEzddJY0N1w3xk,15351
27
27
  shepherd_core/data_models/content/virtual_source_fixture.yaml,sha256=1o-31mGgn7eyCNidKoOUp9vZh3K4Al0kJgmz54Q2DAE,11191
28
28
  shepherd_core/data_models/experiment/__init__.py,sha256=lorsx0M-JWPIrt_UZfexsLwaITv5slFb3krBOt0idm8,618
29
- shepherd_core/data_models/experiment/experiment.py,sha256=wnn6T3czuh4rz6OSYtMltCTbRpPX55TLVAtQcKO7Uhg,4044
29
+ shepherd_core/data_models/experiment/experiment.py,sha256=79iHh2Dr_w4N4Bfq_g0KDr6wMpS_T7x-JIGHZCagEGo,4080
30
30
  shepherd_core/data_models/experiment/observer_features.py,sha256=qxnb7anuQz9ZW5IUlPdUXYPIl5U7O9uXkJqZtMnAb0Y,5156
31
31
  shepherd_core/data_models/experiment/target_config.py,sha256=XIsjbbo7yn_A4q3GMxWbiNzEGA0Kk5gH7-XfQQ7Kg0E,3674
32
32
  shepherd_core/data_models/task/__init__.py,sha256=vOsSeB5IBYYwzOLKom8-XuZyjF86m_svtCsw-agiV7o,3295
@@ -57,7 +57,7 @@ shepherd_core/fw_tools/converter.py,sha256=3igRT33tghrBCao5njuPmePS-Y_lSa6EUHvwC
57
57
  shepherd_core/fw_tools/converter_elf.py,sha256=GQDVqIqMW4twNMvZIV3sowFMezhs2TN-IYREjRP7Xt4,1089
58
58
  shepherd_core/fw_tools/patcher.py,sha256=D6MHaCvKRRVQYSZozODAp_l7UnqxVsvnulPzpkfXWW8,4108
59
59
  shepherd_core/fw_tools/validation.py,sha256=dOweyWwVMq0b4Liha39mGUOiblD7Nz5kSFVrlxUx41o,4707
60
- shepherd_core/inventory/__init__.py,sha256=nRO11HG4eJ_FaXebSkE0dd1H6qvjrX5n3OQHOzKXVvk,3841
60
+ shepherd_core/inventory/__init__.py,sha256=nyDBAE7kdDeh1McyavMWH1cY0WqphjFS1NL4XRAyzUw,3841
61
61
  shepherd_core/inventory/python.py,sha256=OWNnyEt0IDPW9XGW-WloU0FExwgZzYNA05VpRj4cZGc,1250
62
62
  shepherd_core/inventory/system.py,sha256=Q_mtM2zhUsTvzELgpEVxSxL9aFS1RSGcCX6RFpyZ-r8,3155
63
63
  shepherd_core/inventory/target.py,sha256=Lq11j25tWieXheOxIDaQb-lc-2omxYVex5P6uGiLUyk,507
@@ -65,7 +65,7 @@ shepherd_core/testbed_client/__init__.py,sha256=QtbsBUzHwOoM6rk0qa21ywuz63YV7af1
65
65
  shepherd_core/testbed_client/cache_path.py,sha256=tS0er9on5fw8wddMCt1jkc2uyYOdSTvX_UmfmYJf6tY,445
66
66
  shepherd_core/testbed_client/client_abc_fix.py,sha256=BsSkpvJHURRejlS-YPF1f6QRPC_X0fYEsJpinzsx6Jc,4079
67
67
  shepherd_core/testbed_client/client_web.py,sha256=rOg0Gf-s3S8U0z2ssh9_bNnq4aRQINfuuVHionPf38M,5788
68
- shepherd_core/testbed_client/fixtures.py,sha256=4Uk583R4r6I5IB78HxOn-9UNH3sbFha7OPEdcSXvMCU,9939
68
+ shepherd_core/testbed_client/fixtures.py,sha256=W8trHZXyuD0xzb28ZW-2BQ3ZDU2tI3LC4mjrbOUX57E,9215
69
69
  shepherd_core/testbed_client/user_model.py,sha256=5M3vWkAGBwdGDUYAanAjrZwpzMBlh3XLOVvNYWiLmms,2107
70
70
  shepherd_core/vsource/__init__.py,sha256=vTvFWuJn4eurPNzEiMd15c1Rd6o3DTWzCfbhOomflZU,771
71
71
  shepherd_core/vsource/target_model.py,sha256=LaB5ppi2-IIpIepDqDvOliR-BupzccJl44yRxjlF-ms,5113
@@ -74,8 +74,8 @@ shepherd_core/vsource/virtual_harvester_model.py,sha256=GyA0uGl3r42t5c4roYtEaj22
74
74
  shepherd_core/vsource/virtual_harvester_simulation.py,sha256=MFT583s73BJZYyhcqgnDUGTPr9s_lN_lKafzJG6kueE,2457
75
75
  shepherd_core/vsource/virtual_source_model.py,sha256=9tiOzgrEgdEH5Uuhd8hjmmIkquNDuaNjLlblvInIlzg,3036
76
76
  shepherd_core/vsource/virtual_source_simulation.py,sha256=ZOnFd2uPawY2G1salCiLGx9o1OBG99_-EHBtDjx4ZUo,5140
77
- shepherd_core-2025.2.2.dist-info/METADATA,sha256=r7kp-hqRWNI4HjNtagcpvXtUmZLcmrpj4iRTZo34g2Q,7806
78
- shepherd_core-2025.2.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
79
- shepherd_core-2025.2.2.dist-info/top_level.txt,sha256=wy-t7HRBrKARZxa-Y8_j8d49oVHnulh-95K9ikxVhew,14
80
- shepherd_core-2025.2.2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
81
- shepherd_core-2025.2.2.dist-info/RECORD,,
77
+ shepherd_core-2025.4.1.dist-info/METADATA,sha256=3IZbuK5skDrSs1QRlY9uA8MJLsUx0NSYALft4GwVfeQ,7806
78
+ shepherd_core-2025.4.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
79
+ shepherd_core-2025.4.1.dist-info/top_level.txt,sha256=wy-t7HRBrKARZxa-Y8_j8d49oVHnulh-95K9ikxVhew,14
80
+ shepherd_core-2025.4.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
81
+ shepherd_core-2025.4.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5