shepherd-core 2024.4.2__py3-none-any.whl → 2024.7.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.
shepherd_core/__init__.py CHANGED
@@ -23,7 +23,7 @@ from .testbed_client.client import TestbedClient
23
23
  from .testbed_client.client import tb_client
24
24
  from .writer import Writer
25
25
 
26
- __version__ = "2024.4.2"
26
+ __version__ = "2024.7.1"
27
27
 
28
28
  __all__ = [
29
29
  "Reader",
@@ -16,8 +16,6 @@ from .calibration import CalibrationPair
16
16
  from .calibration import CapeData
17
17
  from .shepherd import ShpModel
18
18
 
19
- # TODO: move to shepherd_data to remove scipy-dependency from _core
20
-
21
19
 
22
20
  class CalMeasurementPair(ShpModel):
23
21
  """Value-container for a calibration-measurement."""
@@ -32,17 +30,23 @@ CalMeasPairs = Annotated[List[CalMeasurementPair], Field(min_length=2)]
32
30
  @validate_call
33
31
  def meas_to_cal(data: CalMeasPairs, component: str) -> CalibrationPair:
34
32
  """Convert values from calibration-measurement to the calibration itself."""
35
- from scipy import stats # placed here due to massive delay
36
-
37
33
  x = np.empty(len(data))
38
34
  y = np.empty(len(data))
39
35
  for i, pair in enumerate(data):
40
36
  x[i] = pair.shepherd_raw
41
37
  y[i] = pair.reference_si
42
- result = stats.linregress(x, y)
43
- offset = float(result.intercept)
44
- gain = float(result.slope)
45
- rval = result.rvalue # test quality of regression
38
+
39
+ model = np.polyfit(x, y, 1)
40
+ offset = model[1]
41
+ gain = model[0]
42
+
43
+ # r-squared, Pearson correlation coefficient
44
+ p = np.poly1d(model)
45
+ yhat = p(x)
46
+ ybar = np.sum(y) / len(y)
47
+ ssreg = np.sum((yhat - ybar) ** 2)
48
+ sstot = np.sum((y - ybar) ** 2)
49
+ rval = ssreg / sstot
46
50
 
47
51
  if rval < 0.999:
48
52
  msg = (
@@ -71,6 +71,7 @@ class CalibrationPair(ShpModel):
71
71
  if isinstance(values_raw, np.ndarray):
72
72
  values_raw[values_raw < 0.0] = 0.0
73
73
  values_raw = np.around(values_raw)
74
+ # TODO: overflow should also be prevented (add bit-width) -> fail or warn at both?
74
75
  else:
75
76
  values_raw = round(max(values_raw, 0.0))
76
77
  return values_raw
@@ -60,7 +60,7 @@ class EmulationTask(ShpModel):
60
60
  # timestamp or unix epoch time, None = ASAP
61
61
  duration: Optional[timedelta] = None
62
62
  # ⤷ Duration of recording in seconds, None = till EOF
63
- abort_on_error: bool = False
63
+ abort_on_error: bool = False # TODO: remove, should not exist
64
64
 
65
65
  # emulation-specific
66
66
  use_cal_default: bool = False
@@ -43,7 +43,7 @@ class ProgrammingTask(ShpModel):
43
43
  def post_validation(self) -> Self:
44
44
  d_type = suffix_to_DType.get(self.firmware_file.suffix.lower())
45
45
  if d_type != FirmwareDType.base64_hex:
46
- ValueError(f"Firmware is not intel-.hex ('{self.firmware_file}')")
46
+ raise ValueError("Firmware is not intel-.hex ('%s')", self.firmware_file.as_posix())
47
47
  return self
48
48
 
49
49
  @classmethod
@@ -70,11 +70,13 @@ class Observer(ShpModel, title="Shepherd-Sheep"):
70
70
  return self
71
71
 
72
72
  def has_target(self, target_id: int) -> bool:
73
- if self.target_a is not None and target_id == self.target_a.id and self.target_a.active:
74
- return True
75
- if self.target_b is not None and target_id == self.target_b.id and self.target_b.active:
76
- return True
77
- return False
73
+ case_a = (
74
+ self.target_a is not None and target_id == self.target_a.id and self.target_a.active
75
+ )
76
+ case_b = (
77
+ self.target_b is not None and target_id == self.target_b.id and self.target_b.active
78
+ )
79
+ return case_a or case_b
78
80
 
79
81
  def get_target_port(self, target_id: int) -> TargetPort:
80
82
  if self.has_target(target_id):
@@ -17,7 +17,7 @@ try:
17
17
  except ImportError as e:
18
18
  ELF = None
19
19
  elf_error_text = (
20
- "Please install functionality with 'pip install shepherd_core[elf] -U' first, "
20
+ "Please install functionality with 'pip install shepherd-core[elf] -U' first, "
21
21
  f"underlying exception: {e.msg}"
22
22
  )
23
23
 
@@ -23,7 +23,7 @@ except ImportError as e:
23
23
  ELF = None
24
24
  ELFError = None
25
25
  elf_error_text = (
26
- "Please install functionality with 'pip install shepherd_core[elf] -U' first, "
26
+ "Please install functionality with 'pip install shepherd-core[elf] -U' first, "
27
27
  f"underlying exception: {e.msg}"
28
28
  )
29
29
 
@@ -56,10 +56,9 @@ def is_hex_msp430(file: Path) -> bool:
56
56
  value = int.from_bytes(ih.gets(0xFFFE, 2), byteorder="little", signed=False)
57
57
  if 0x4000 > value >= 0xFF80:
58
58
  return False
59
- if ih.get_memory_size() >= 270_000:
60
- # conservative test for now - should be well below 128 kB + 8kB for msp430fr5962
61
- return False
62
- return True
59
+
60
+ # conservative test for now - should be well below 128 kB + 8kB for msp430fr5962
61
+ return ih.get_memory_size() <= 270_000
63
62
  return False
64
63
 
65
64
 
@@ -74,10 +73,9 @@ def is_hex_nrf52(file: Path) -> bool:
74
73
  ih = IntelHex(file.as_posix())
75
74
  if ih.minaddr() != 0x0000:
76
75
  return False
77
- if ih.get_memory_size() >= 1310720:
78
- # conservative test for now - should be well below 1 MB + 256 kB
79
- return False
80
- return True
76
+
77
+ # conservative test for now - should be well below 1 MB + 256 kB
78
+ return ih.get_memory_size() < 1310720
81
79
  return False
82
80
 
83
81
 
@@ -3,8 +3,8 @@
3
3
  import platform
4
4
  import subprocess
5
5
  import time
6
- from contextlib import suppress
7
6
  from datetime import datetime
7
+ from pathlib import Path
8
8
  from typing import Optional
9
9
 
10
10
  from typing_extensions import Self
@@ -48,6 +48,9 @@ class SystemInventory(ShpModel):
48
48
  # ip IPvAnyAddress
49
49
  # mac MACStr
50
50
 
51
+ fs_root: Optional[str] = None
52
+ beagle: Optional[str] = None
53
+
51
54
  model_config = ConfigDict(str_min_length=0)
52
55
 
53
56
  @classmethod
@@ -67,6 +70,31 @@ class SystemInventory(ShpModel):
67
70
  ifs2 = {name: (_if[1].address, _if[0].address) for name, _if in ifs1 if len(_if) > 1}
68
71
  uptime = time.time() - psutil.boot_time()
69
72
 
73
+ fs_cmd = ["/usr/bin/df", "-h", "/"]
74
+ fs_out = None
75
+ if Path(fs_cmd[0]).is_file():
76
+ reply = subprocess.run( # noqa: S603
77
+ fs_cmd, timeout=30, capture_output=True, check=False
78
+ )
79
+ fs_out = str(reply.stdout)
80
+
81
+ beagle_cmd = ["/usr/bin/beagle-version"]
82
+ beagle_out = None
83
+ if Path(beagle_cmd[0]).is_file():
84
+ reply = subprocess.run( # noqa: S603
85
+ beagle_cmd, timeout=30, capture_output=True, check=False
86
+ )
87
+ beagle_out = str(reply.stdout)
88
+
89
+ ptp_cmd = ["/usr/sbin/ptp4l", "-v"]
90
+ ptp_out = None
91
+ if Path(ptp_cmd[0]).is_file():
92
+ reply = subprocess.run( # noqa: S603
93
+ ptp_cmd, timeout=30, capture_output=True, check=False
94
+ )
95
+ ptp_out = f"{ reply.stdout }, { reply.stderr }"
96
+ # alternative: check_output - seems to be lighter
97
+
70
98
  model_dict = {
71
99
  "uptime": round(uptime),
72
100
  "timestamp": ts,
@@ -77,12 +105,9 @@ class SystemInventory(ShpModel):
77
105
  "processor": platform.processor(),
78
106
  "hostname": platform.node(),
79
107
  "interfaces": ifs2,
80
- # TODO: add free space on /
108
+ "fs_root": fs_out,
109
+ "beagle": beagle_out,
110
+ "ptp": ptp_out,
81
111
  }
82
112
 
83
- with suppress(FileNotFoundError):
84
- ret = subprocess.run(["/usr/sbin/ptp4l", "-v"], check=False) # noqa: S603
85
- model_dict["ptp"] = ret.stdout
86
- # alternative: check_output - seems to be lighter
87
-
88
113
  return cls(**model_dict)
shepherd_core/reader.py CHANGED
@@ -124,7 +124,10 @@ class Reader:
124
124
  if not hasattr(self, "_cal"):
125
125
  cal_dict = CalibrationSeries().model_dump()
126
126
  for ds, param in product(["current", "voltage", "time"], ["gain", "offset"]):
127
- cal_dict[ds][param] = self.h5file["data"][ds].attrs[param]
127
+ try:
128
+ cal_dict[ds][param] = self.h5file["data"][ds].attrs[param]
129
+ except KeyError: # noqa: PERF203
130
+ self._logger.debug("Cal-Param '%s' for dataset '%s' not found!", param, ds)
128
131
  self._cal = CalibrationSeries(**cal_dict)
129
132
 
130
133
  self._refresh_file_stats()
@@ -257,6 +260,8 @@ class Reader:
257
260
  return EnergyDType[self.h5file["data"].attrs["datatype"]]
258
261
  except KeyError:
259
262
  return None
263
+ except ValueError:
264
+ return None
260
265
  else:
261
266
  return None
262
267
 
@@ -631,7 +636,7 @@ class Reader:
631
636
  Algo: create an offset-by-one vector and compare against original.
632
637
  """
633
638
  if len(data.shape) > 1:
634
- ValueError("Array must be 1D")
639
+ raise ValueError("Array must be 1D")
635
640
  data_1 = np.concatenate(([not data[0]], data[:-1]))
636
641
  return data != data_1
637
642
 
@@ -168,9 +168,7 @@ def file_older_than(file: Path, delta: timedelta) -> bool:
168
168
  """Decide if file is older than a specific duration of time."""
169
169
  cutoff = local_now() - delta
170
170
  mtime = datetime.fromtimestamp(file.stat().st_mtime, tz=local_tz())
171
- if mtime < cutoff:
172
- return True
173
- return False
171
+ return mtime < cutoff
174
172
 
175
173
 
176
174
  class Fixtures:
shepherd_core/writer.py CHANGED
@@ -229,7 +229,7 @@ class Writer(Reader):
229
229
  """Initialize the structure of the HDF5 file.
230
230
 
231
231
  HDF5 is hierarchically structured and before writing data, we have to
232
- setup this structure, i.e. creating the right groups with corresponding
232
+ set up this structure, i.e. creating the right groups with corresponding
233
233
  data types. We will store 3 types of data in a database: The
234
234
  actual IV samples recorded either from the harvester (during recording)
235
235
  or the target (during emulation). Any log messages, that can be used to
@@ -367,7 +367,7 @@ class Writer(Reader):
367
367
  TODO: use data-model?
368
368
  :param data: from virtual harvester or converter / source.
369
369
  """
370
- self.h5file["data"].attrs["config"] = yaml.safe_dump(
370
+ self.h5file.attrs["config"] = yaml.safe_dump(
371
371
  data, default_flow_style=False, sort_keys=False
372
372
  )
373
373
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: shepherd_core
3
- Version: 2024.4.2
3
+ Version: 2024.7.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>
@@ -33,7 +33,6 @@ Requires-Dist: numpy
33
33
  Requires-Dist: pyYAML
34
34
  Requires-Dist: chromalog
35
35
  Requires-Dist: pydantic[email] >2.0.0
36
- Requires-Dist: scipy
37
36
  Requires-Dist: tqdm
38
37
  Requires-Dist: intelhex
39
38
  Requires-Dist: requests
@@ -1,15 +1,15 @@
1
- shepherd_core/__init__.py,sha256=TuaidDGnc0u0TfDIXiRUviqMXsRSL6ldy4AurQmr71U,1385
1
+ shepherd_core/__init__.py,sha256=8FydSimdy6iX5N_ZPoxm2e4AEJLUg0wikCon87iqsj4,1385
2
2
  shepherd_core/calibration_hw_def.py,sha256=m5HDxHJ_blnn-C0Og5v6by1ApJRDT7RhytFbL-P5730,2548
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=qyc0MBHa-wMGRDglEaMtyB6OxCiODnOMJsxJH8NCcAo,26245
6
- shepherd_core/writer.py,sha256=VeW7AJsMKhfF06QsOjQ7Ez0gLq0NrrHUj2zq9_FtX6Y,14482
5
+ shepherd_core/reader.py,sha256=dZt_q9PJt6FKBMfesk3wLfYdBp0EjCe_-gGZ-Gvd4tk,26473
6
+ shepherd_core/writer.py,sha256=xcLCw-YokKaN8TrkwD0IjRmn8xZU0Q8wwWp_1K8JFVY,14475
7
7
  shepherd_core/data_models/__init__.py,sha256=IVjKbT2Ilz5bev325EvAuuhd9LfQgQ1u7qKo6dhVA2k,1866
8
8
  shepherd_core/data_models/readme.md,sha256=1bdfEypY_0NMhXLxOPRnLAsFca0HuHdq7_01yEWxvUs,2470
9
9
  shepherd_core/data_models/virtual_source_doc.txt,sha256=KizMcfGKj7BnHIbaJHT7KeTF01SV__UXv01qV_DGHSs,6057
10
10
  shepherd_core/data_models/base/__init__.py,sha256=PSJ6acWViqBm0Eiom8DIgKfFVrp5lzYr8OsDvP79vwI,94
11
- shepherd_core/data_models/base/cal_measurement.py,sha256=Ie35wWfH4spjETQ6SKHlbY_Ie2Bkt0dIQAKAn4ELOTc,3354
12
- shepherd_core/data_models/base/calibration.py,sha256=P2fCFzyrrXobkYQkBzqplpIlg5cDXKv0iWWrnaroq_I,10320
11
+ shepherd_core/data_models/base/cal_measurement.py,sha256=YScPG7QLynbUHdjcznYqU8O5KRh0XiROGxGSk9BETMk,3357
12
+ shepherd_core/data_models/base/calibration.py,sha256=HPhDEaApOCKxfX2q9RD8YCvA3Gqls-2bHqvLLvOM7kY,10415
13
13
  shepherd_core/data_models/base/content.py,sha256=13j7GSgT73xn27jgDP508thUEJR4U-nCb5n7CJ50c9Y,2463
14
14
  shepherd_core/data_models/base/shepherd.py,sha256=DNrx59o1VBuy_liJuUzZRzmTTYB73D_pUWiNyMQyjYY,6112
15
15
  shepherd_core/data_models/base/timezone.py,sha256=2T6E46hJ1DAvmqKfu6uIgCK3RSoAKjGXRyzYNaqKyjY,665
@@ -29,11 +29,11 @@ shepherd_core/data_models/experiment/experiment.py,sha256=QX3-oeBe5dRx1a_RHF6kxj
29
29
  shepherd_core/data_models/experiment/observer_features.py,sha256=qxnb7anuQz9ZW5IUlPdUXYPIl5U7O9uXkJqZtMnAb0Y,5156
30
30
  shepherd_core/data_models/experiment/target_config.py,sha256=XIsjbbo7yn_A4q3GMxWbiNzEGA0Kk5gH7-XfQQ7Kg0E,3674
31
31
  shepherd_core/data_models/task/__init__.py,sha256=rZLbgqX-dTWY4026-bqW-IWVHbA6C_xP9y0aeRze8FY,3374
32
- shepherd_core/data_models/task/emulation.py,sha256=75X8xkHx27LrBMntw-TaNGHbAN31_o0eby9kAeBopV8,6342
32
+ shepherd_core/data_models/task/emulation.py,sha256=z3BEqERy2m3_rxqKo6w89sSnBQhFwHDEdCgwJh2XUOQ,6376
33
33
  shepherd_core/data_models/task/firmware_mod.py,sha256=Rw_TA1ykQ7abUd_U0snqZlpZyrS8Nx6f4BEax1Xnji0,2818
34
34
  shepherd_core/data_models/task/harvest.py,sha256=HHnqWwRsJupaZJxuohs7NrK6VaDyoRzGOaG2h9y3s1Y,3360
35
35
  shepherd_core/data_models/task/observer_tasks.py,sha256=XlH_-EGRrdodTn0c2pjGvpcauc0a9NOnLhysKw8iRwk,3511
36
- shepherd_core/data_models/task/programming.py,sha256=6Pmyeze2UxNyyDUACbIL18GzUCN9wn6PuGrYwA2h8VI,2305
36
+ shepherd_core/data_models/task/programming.py,sha256=Mg9_AZHIdG01FheEJAifIRPSB3iZ0UJITf8zeg2jyws,2323
37
37
  shepherd_core/data_models/task/testbed_tasks.py,sha256=yU4YhNN1ObYkcts7UOwkWWhCmW67f_Gjx3dhvzMnKWI,2036
38
38
  shepherd_core/data_models/testbed/__init__.py,sha256=cL3swgijyIpZIW1vl51OVR2seAlWt6Ke9oB_cBkPniU,612
39
39
  shepherd_core/data_models/testbed/cape.py,sha256=D23ZKXpZRPIIOMn6LCoJrwHiRbSaYg-y7B6fAt1ap64,1246
@@ -42,7 +42,7 @@ shepherd_core/data_models/testbed/gpio.py,sha256=m4U8-KotpZbdSkRkXm2GqoADiubr_1-
42
42
  shepherd_core/data_models/testbed/gpio_fixture.yaml,sha256=yXvoXAau2hancKi2yg1xIkErPWQa6gIxNUG3y8JuF9Y,3076
43
43
  shepherd_core/data_models/testbed/mcu.py,sha256=pUyT8gwPcqh18I7FC6iE6gYYISo69TvDfuq2zSwfmxs,1375
44
44
  shepherd_core/data_models/testbed/mcu_fixture.yaml,sha256=lRZMLs27cTeERSFGkbMt5xgxbn11Gh9G1mQqOZK136I,522
45
- shepherd_core/data_models/testbed/observer.py,sha256=AezYNm9mW5WCdxm5TXT-UQUwIhKDHchMIugsLGy1PMA,3225
45
+ shepherd_core/data_models/testbed/observer.py,sha256=hlj6buDzUQKYnlhCJZyxnrAPYKoL4zq9y14sKtYofOU,3246
46
46
  shepherd_core/data_models/testbed/observer_fixture.yaml,sha256=w4VS6lTzaVs5IqWjkHanxcjDhIEydQPCV6z_DlsLFqA,4812
47
47
  shepherd_core/data_models/testbed/target.py,sha256=KeJaLradQ3oHeeowCg_X0lDHDqyi3R3La0YPKC5Rv90,1838
48
48
  shepherd_core/data_models/testbed/target_fixture.yaml,sha256=6YbCV3aTtDUKzC40kPURq9nFwTjT97LNy7imOb_35sk,3668
@@ -53,23 +53,23 @@ shepherd_core/decoder_waveform/uart.py,sha256=sHsXHOsDU1j9zMSZO7CCMTMinT4U_S5Ngs
53
53
  shepherd_core/fw_tools/__init__.py,sha256=_RZpgHsNN1Zhd-x0-A9aJPI3pjULKhR9iuR9eKPa8zQ,2137
54
54
  shepherd_core/fw_tools/converter.py,sha256=3igRT33tghrBCao5njuPmePS-Y_lSa6EUHvwCakMo2s,3539
55
55
  shepherd_core/fw_tools/converter_elf.py,sha256=GQDVqIqMW4twNMvZIV3sowFMezhs2TN-IYREjRP7Xt4,1089
56
- shepherd_core/fw_tools/patcher.py,sha256=ODBADQeomah0NadIuGSAwMVlafOf_KAnz_IMvDgydVE,4108
57
- shepherd_core/fw_tools/validation.py,sha256=2AnBpl5MpW8C-uLlusNZWJRDHa7lG7sB2pB1GKhTMcY,4790
56
+ shepherd_core/fw_tools/patcher.py,sha256=D6MHaCvKRRVQYSZozODAp_l7UnqxVsvnulPzpkfXWW8,4108
57
+ shepherd_core/fw_tools/validation.py,sha256=hBLCKIUumPTA6iuXMVbMYph2jamaxeSTxRqsvl3C4-I,4699
58
58
  shepherd_core/inventory/__init__.py,sha256=nRO11HG4eJ_FaXebSkE0dd1H6qvjrX5n3OQHOzKXVvk,3841
59
59
  shepherd_core/inventory/python.py,sha256=OWNnyEt0IDPW9XGW-WloU0FExwgZzYNA05VpRj4cZGc,1250
60
- shepherd_core/inventory/system.py,sha256=hmUuaeg6_6Xsykp47YAtTeUbDa5B8sxV0EICQJG9rx4,2304
60
+ shepherd_core/inventory/system.py,sha256=GScfYZm0dlWQv4Np6R1JI_XGHVcECAw50Wqef_hW3VU,3121
61
61
  shepherd_core/inventory/target.py,sha256=Lq11j25tWieXheOxIDaQb-lc-2omxYVex5P6uGiLUyk,507
62
62
  shepherd_core/testbed_client/__init__.py,sha256=lzi7F5Go-AsbTbiUCf9Rnu6pzmTZqmpIqoS1yCPal_c,175
63
63
  shepherd_core/testbed_client/cache_path.py,sha256=tS0er9on5fw8wddMCt1jkc2uyYOdSTvX_UmfmYJf6tY,445
64
64
  shepherd_core/testbed_client/client.py,sha256=3vbJ9XdWe9YA28AXgzXThHJtYJU5RUUCpDRBH1mDIr8,5917
65
- shepherd_core/testbed_client/fixtures.py,sha256=db10P0c6kJvG525mLZYuFE98kI0PvoA67jeJgCiUaZ4,9782
65
+ shepherd_core/testbed_client/fixtures.py,sha256=TDRVtxorJ5IFlFwwVcSDpAm1g51ok1PPMt1WmdBpzaM,9748
66
66
  shepherd_core/testbed_client/user_model.py,sha256=5M3vWkAGBwdGDUYAanAjrZwpzMBlh3XLOVvNYWiLmms,2107
67
67
  shepherd_core/vsource/__init__.py,sha256=dS33KYLq5GQ9_D8HfdP8iWSocWTghCi2ZZG2AJWNfaM,391
68
68
  shepherd_core/vsource/virtual_converter_model.py,sha256=ZSoWVLfRmFEjeCNoQCg3BctzhdfayINUBDU_AJK1CR0,10404
69
69
  shepherd_core/vsource/virtual_harvester_model.py,sha256=wCbFfsqDRC5Rfu8qANkmkP9XGJOPHJY9-iSnI850JI4,7817
70
70
  shepherd_core/vsource/virtual_source_model.py,sha256=fjN8myTY3I_LpikF_aGAcxes3RGu1GP23P7XKC_UIyA,2737
71
- shepherd_core-2024.4.2.dist-info/METADATA,sha256=bC_TD-hytcffYDetSqElbilSIM77vvX8f8TjhyzXaCQ,7651
72
- shepherd_core-2024.4.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
73
- shepherd_core-2024.4.2.dist-info/top_level.txt,sha256=wy-t7HRBrKARZxa-Y8_j8d49oVHnulh-95K9ikxVhew,14
74
- shepherd_core-2024.4.2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
75
- shepherd_core-2024.4.2.dist-info/RECORD,,
71
+ shepherd_core-2024.7.1.dist-info/METADATA,sha256=KtwQxX6iIfqe3mvFb3ZLVZXS6Ovjy9Vh2K6nu5lxvy8,7630
72
+ shepherd_core-2024.7.1.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
73
+ shepherd_core-2024.7.1.dist-info/top_level.txt,sha256=wy-t7HRBrKARZxa-Y8_j8d49oVHnulh-95K9ikxVhew,14
74
+ shepherd_core-2024.7.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
75
+ shepherd_core-2024.7.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (70.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5