oep-client-python 0.0.24__py3-none-any.whl → 0.0.25__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.
oep_client/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.0.24"
5
+ __version__ = "0.0.25"
oep_client/endpoint.py CHANGED
@@ -36,7 +36,8 @@ define:
36
36
  - port_speed (core §3.5, optional): on when the profile's describe declares it (`port_speed_base`, the boot speed;
37
37
  None = off: the op is unknown_operation). try / commit / revert on the UART bridge the request came in on (else
38
38
  unavailable cause 6), a rate the fake UART cannot make (outside 300..5000000) unsupported; a try reverts after
39
- verify_ms without a commit or at a broken candidate, a commit after idle_ms with no good frame or 3 broken
39
+ verify_ms without a commit or at a broken candidate, a commit after idle_ms (at most port_speed_idle_max_ms, 3000;
40
+ 0 and anything longer count as that maximum) with no good frame or 3 broken
40
41
  candidates within 1 s, the session's end reverts after its answer. The line itself is modelled by `broken_rates`
41
42
  (rate -> BrokenRate): frames at such a rate break, from a size and in the directions given (`fake_serial` applies it).
42
43
 
@@ -321,6 +322,7 @@ class BrokenRate:
321
322
  PORT_SPEED_TAG = reg.CORE.tlv["describe"]["port_speed"]
322
323
  OP_PORT_SPEED = reg.CORE.op["port_speed"]
323
324
  SPEED_STEP = reg.CORE.enum["port_speed_step"]
325
+ SPEED_IDLE_MAX_MS = reg.TIMING["port_speed_idle_max_ms"] # committed: idle_ms at most this (0 and longer: this)
324
326
  SPEED_BAD_MAX, SPEED_BAD_WINDOW_MS = 3, 1000 # committed: this many broken candidates within the window revert
325
327
  SPEED_RATES = (300, 5_000_000) # what the fake's UART makes (anything between, exactly)
326
328
 
@@ -472,7 +474,7 @@ class Endpoint:
472
474
  self.speed_rate = 0 # the rate it runs at
473
475
  self.speed_asked = 0 # the baud the try asked (the commit names it again)
474
476
  self.speed_until_ms = 0 # try: the commit's deadline (verify_ms)
475
- self.speed_idle_ms = 0 # committed: revert after this long with no good frame (0 never)
477
+ self.speed_idle_ms = 0 # committed: revert after this long with no good frame
476
478
  self.speed_good_ms = 0 # the last good frame on that port
477
479
  self.speed_bad: list[int] = [] # committed: the times of the recent broken candidates
478
480
  self.speed_pending: tuple | None = None # ("switch", port, baud, verify_ms) / ("revert",): after the answer
@@ -1203,7 +1205,7 @@ class Endpoint:
1203
1205
  if self.speed_state == "base" or port != self.speed_port or baud != self.speed_asked:
1204
1206
  raise unavailable("wrong_state") # nothing tried, or another baud
1205
1207
  self.speed_state = "committed"
1206
- self.speed_idle_ms = idle_ms
1208
+ self.speed_idle_ms = idle_ms if 0 < idle_ms <= SPEED_IDLE_MAX_MS else SPEED_IDLE_MAX_MS
1207
1209
  self.speed_good_ms = self.now()
1208
1210
  self.speed_bad.clear()
1209
1211
  return self._answer(struct.pack("<I", self.speed_rate), ignored)
@@ -1264,7 +1266,7 @@ class Endpoint:
1264
1266
  now = self.now()
1265
1267
  if self.speed_state == "try" and now >= self.speed_until_ms:
1266
1268
  self._speed_revert() # no commit within verify_ms
1267
- elif self.speed_state == "committed" and self.speed_idle_ms and now - self.speed_good_ms >= self.speed_idle_ms:
1269
+ elif self.speed_state == "committed" and now - self.speed_good_ms >= self.speed_idle_ms:
1268
1270
  self._speed_revert()
1269
1271
 
1270
1272
  def _page(self, tlvs: list[bytes], first: int) -> bytes:
oep_client/link.py CHANGED
@@ -26,6 +26,10 @@ transfer both ways (link_source / link_sink with max_frame-sized frames) that co
26
26
  throughput, then commit it, or revert and wait the probe out and re-confirm at the boot speed. The report stays on the
27
27
  link (`link.speed`). Once raised, a request whose answer never comes even after its resend sends the link back to the
28
28
  boot speed (the probe reverts by itself) and goes once more there: the link never wedges at a rate the probe left.
29
+ The probe also goes back after port_speed_idle_max_ms (3 s) with no good frame, so while raised the link sends a
30
+ keepalive before a request when it has been quiet for 1 s, and `keep_alive()` does the same for a caller that sits
31
+ idle for long. A host opening a serial port retries its first confirm for that maximum and a little (4 s in all): a
32
+ host that raised the speed and died leaves the probe at its rate until then.
29
33
  """
30
34
 
31
35
  from __future__ import annotations
@@ -55,6 +59,10 @@ class PortBusy(OSError):
55
59
 
56
60
 
57
61
  BASE_BAUD = 115200 # the boot speed of every reference UART bridge (the board's profile decides; core §3.5)
62
+ IDLE_MAX_MS = reg.TIMING["port_speed_idle_max_ms"] # a committed rate goes back after this with no good frame (§3.5)
63
+ KEEPALIVE_S = 1.0 # raised: a keepalive once the link has been quiet this long (well inside IDLE_MAX_MS)
64
+ OPEN_RETRY_S = IDLE_MAX_MS / 1000 + 1.0 # opening a serial port: confirm retried this long (a raised rate left over)
65
+ OPEN_TRY_S = 0.5 # each of those confirms waits this long (at most the link's timeout)
58
66
 
59
67
 
60
68
  def open_serial(port: str, baud: int = BASE_BAUD):
@@ -158,6 +166,8 @@ class SerialLink:
158
166
  self.speed_lost = 0 # times a raised rate was found gone (back to the boot speed)
159
167
  self.fallback = True # a raised rate that stops answering: back to the boot speed
160
168
  self.corr_source = self._own_corr # the host's correlation counter once bound (open_host)
169
+ self.keepalive_frame = None # raised: a keepalive request in the session, once bound (attach_host)
170
+ self.last_tx = time.monotonic() # when the link last wrote (raised: quiet for KEEPALIVE_S = keepalive)
161
171
  self.held = lambda: False # a session holds the port (its raw transfer stopped): broken = resend
162
172
  self.blind = lambda: [] # the host's blind stops (unsubscribe / end) once bound
163
173
  self._corr_n = 0x8000
@@ -178,6 +188,7 @@ class SerialLink:
178
188
  self.frames.send_many(messages)
179
189
  else:
180
190
  self.stream.write(b"".join(cobs.frame(msg) for msg in messages))
191
+ self.last_tx = time.monotonic()
181
192
 
182
193
  def _recv(self) -> bytes:
183
194
  if self.framing == "length":
@@ -250,10 +261,17 @@ class SerialLink:
250
261
  n = 0
251
262
  try:
252
263
  while True:
264
+ if self._raised(): # a long pump at a raised rate keeps the line alive (core §3.5)
265
+ self.timeout = saved
266
+ self._keep_raised()
253
267
  self.timeout = max(0.0, deadline - time.monotonic())
268
+ if self._raised():
269
+ self.timeout = min(self.timeout, KEEPALIVE_S)
254
270
  try:
255
271
  frame = self._recv()
256
272
  except TimeoutError:
273
+ if self._raised() and time.monotonic() < deadline:
274
+ continue
257
275
  return n
258
276
  except FramingLost:
259
277
  self.timeout = saved
@@ -307,6 +325,7 @@ class SerialLink:
307
325
  self.resync()
308
326
 
309
327
  def send(self, message: bytes) -> bytes:
328
+ self._keep_raised()
310
329
  try:
311
330
  reply = self._send(message)
312
331
  except TimeoutError:
@@ -355,6 +374,7 @@ class SerialLink:
355
374
  answered go once more with the same corr (oep-core §5.2: the probe answers a repeat from what it kept); a second
356
375
  failure is raised.
357
376
  """
377
+ self._keep_raised()
358
378
  replies: list[bytes] = []
359
379
  try:
360
380
  return self._exchange_once(messages, max_inflight, window_bytes, replies)
@@ -397,6 +417,15 @@ class SerialLink:
397
417
  finally:
398
418
  self.timeout = saved
399
419
 
420
+ def _confirm_within(self, wait_s: float, each_s: float) -> bool:
421
+ """Confirms, each waiting `each_s`, until one is answered (True) or `wait_s` has passed (False)."""
422
+ deadline = time.monotonic() + wait_s
423
+ while True:
424
+ if self.confirm_raw(each_s):
425
+ return True
426
+ if time.monotonic() >= deadline:
427
+ return False
428
+
400
429
  def back_to_base(self, wait_s: float = 3.0) -> bool:
401
430
  """The host at the boot speed again, and the probe confirmed there: confirms every 0.25 s up to `wait_s` (a
402
431
  probe still trying waits out its verify_ms; one committed reverts at the broken candidates these make)."""
@@ -404,12 +433,31 @@ class SerialLink:
404
433
  if self.base_baud is None:
405
434
  return False
406
435
  self.set_baud(self.base_baud)
407
- deadline = time.monotonic() + wait_s
408
- while True:
409
- if self.confirm_raw(0.25):
410
- return True
411
- if time.monotonic() >= deadline:
412
- return False
436
+ return self._confirm_within(wait_s, 0.25)
437
+
438
+ def _raised(self) -> bool:
439
+ return self.base_baud is not None and self.baud != self.base_baud
440
+
441
+ def keep_alive(self) -> bool:
442
+ """While a raised rate is in force and a session holds the port: a keepalive when the link has been quiet for
443
+ KEEPALIVE_S (1 s). The probe goes back to the boot speed after port_speed_idle_max_ms (3 s) with no good frame
444
+ (core §3.5); every request already does this before it goes out, so only a caller that sits idle for long
445
+ (waiting on a person, a sleep between requests) calls it - often is fine, it sends nothing otherwise.
446
+ True when a keepalive went out."""
447
+ if not self._raised() or self.keepalive_frame is None or not self.held():
448
+ return False
449
+ if time.monotonic() - self.last_tx < KEEPALIVE_S:
450
+ return False
451
+ self.last_tx = time.monotonic() # before sending: send() asks again and must not recurse
452
+ self.send(self.keepalive_frame())
453
+ return True
454
+
455
+ def _keep_raised(self) -> None:
456
+ """keep_alive before a request; a keepalive that fails is left to the request itself to find out."""
457
+ try:
458
+ self.keep_alive()
459
+ except (TimeoutError, cobs.CorruptFrame, FramingLost):
460
+ pass
413
461
 
414
462
  def _speed_fallback(self) -> bool:
415
463
  """A request went unanswered (its resend too) while the link ran above the boot speed: the probe went back
@@ -461,12 +509,23 @@ class SerialLink:
461
509
  self.corr_source = hst.next_corr
462
510
  self.blind = hst.blind_stop
463
511
  self.held = lambda: hst.session is not None
512
+ self.keepalive_frame = lambda: m.Request(hst.next_corr(), m.CORE_FN, m.OP_KEEPALIVE, b"", hst.session).pack()
464
513
  hst.link = self
514
+ if self.framing == "cobs" and getattr(self, "transport", None) == "serial":
515
+ self.wait_boot_speed()
465
516
  limits = hst.confirm()
466
517
  hst.exchange = self.bind(limits)
467
518
  if self.framing == "length" and limits.get("max_frame"):
468
519
  self.frames.max_frame = limits["max_frame"]
469
520
 
521
+ def wait_boot_speed(self, wait_s: float | None = None) -> None:
522
+ """A serial port just opened: confirm at the boot speed, retried for OPEN_RETRY_S (port_speed_idle_max_ms and
523
+ a second; at least the link's timeout) - a host that raised the speed and died leaves the probe at that rate
524
+ until its idle limit runs out (core §3.5 item 6). TimeoutError when none was answered."""
525
+ wait_s = max(OPEN_RETRY_S, self.timeout) if wait_s is None else wait_s
526
+ if not self._confirm_within(wait_s, min(self.timeout, OPEN_TRY_S)):
527
+ raise TimeoutError(f"no answer to confirm at {self.baud} for {wait_s:.1f} s")
528
+
470
529
  def close(self) -> None:
471
530
  self.stream.close()
472
531
 
@@ -736,7 +795,7 @@ SWITCH_SETTLE_S = 0.02 # after a baud change, before the first byte at the new
736
795
 
737
796
 
738
797
  def raise_speed(hst, rates: list[int], *, verify_bytes: int = 32768, verify_s: float = 1.0,
739
- verify_ms: int | None = None, idle_ms: int = 0, port: int | None = None) -> SpeedReport:
798
+ verify_ms: int | None = None, idle_ms: int = IDLE_MAX_MS, port: int | None = None) -> SpeedReport:
740
799
  """port_speed (oep-core §3.5), opt-in: try `rates` in order on the UART bridge this host opened, and commit the
741
800
  first that passes. Each: try (answered at the speed now) -> the host switches -> verify both ways with
742
801
  max_frame-sized frames for verify_bytes or verify_s in all (broken frames counted, KB/s measured each way) ->
@@ -745,7 +804,8 @@ def raise_speed(hst, rates: list[int], *, verify_bytes: int = 32768, verify_s: f
745
804
  probe's UART cannot make is skipped (unsupported). The session must be open (the rate lasts as long as it does).
746
805
 
747
806
  verify_ms: how long the probe waits for the commit (default: verify_s + 1.5 s, at most 65535). idle_ms: once
748
- committed, the probe reverts after this long with no good frame (0: never; it reverts at the session's end anyway).
807
+ committed, the probe reverts after this long with no good frame (default and at most port_speed_idle_max_ms,
808
+ 3000; 0 and anything longer mean that maximum). The link keeps the line alive meanwhile (`keep_alive`).
749
809
  port: the transport index (default: the probe's first UART bridge). -> the report, also kept as `hst.link.speed`."""
750
810
  lk = getattr(hst, "link", None)
751
811
  base = getattr(lk, "base_baud", None)
@@ -766,6 +826,7 @@ def raise_speed(hst, rates: list[int], *, verify_bytes: int = 32768, verify_s: f
766
826
  report.supported = True
767
827
  wait = (verify_ms if verify_ms is not None else min(65535, int(verify_s * 1000) + 1500))
768
828
  lk.fallback = False # every failure here is handled here
829
+ idle_ms = idle_ms if 0 < idle_ms <= IDLE_MAX_MS else IDLE_MAX_MS
769
830
  try:
770
831
  return _raise(hst, lk, report, rates, port, base, wait, verify_bytes, verify_s, idle_ms)
771
832
  finally:
oep_client/registry.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  from types import SimpleNamespace as _NS
4
4
 
5
- REGISTRY_HASH = "1043a67bfcb96a43"
5
+ REGISTRY_HASH = "f98b4992f5b8ebe7"
6
6
  SCHEMA = 1
7
7
  PROTOCOL_REVISION = 1
8
8
  CONFIRM_REQUEST_MAGIC = 'OEP?'
@@ -20,7 +20,7 @@ OUTCOMES = {"success": 0x00, "failed": 0x01, "partial": 0x02}
20
20
  REJECT_REASONS = {"unknown_function": 0x01, "unknown_operation": 0x02, "malformed": 0x03, "unavailable": 0x04, "busy": 0x05, "window_exceeded": 0x06, "no_session": 0x07, "locked": 0x08, "session_required": 0x09, "no_connection": 0x0A, "unsupported": 0x0B, "result_lost": 0x0C, "corr_reused": 0x0D, "expired": 0x0E}
21
21
  STATUS = {"ok": 0x00, "wait": 0x01, "line": 0x02, "fault": 0x03, "timeout": 0x04, "state": 0x05}
22
22
  DESCRIBE_COMMON = {"role_channels": 0x01, "max_clock_hz": 0x02, "max_length": 0x03, "min_clock_hz": 0x05, "features": 0x06, "implementation": 0x07, "channel_group": 0x08}
23
- TIMING = {"resync_quiet_ms": 0x32, "probe_frame_gap_ms": 0xC8, "host_frame_pause_max_ms": 0x64, "heartbeat_default_ms": 0x3E8}
23
+ TIMING = {"resync_quiet_ms": 0x32, "probe_frame_gap_ms": 0xC8, "host_frame_pause_max_ms": 0x64, "heartbeat_default_ms": 0x3E8, "port_speed_idle_max_ms": 0xBB8}
24
24
  USB = {"iproduct_prefix": 'OEP', "vendor_bulk_class": 0xFF, "vendor_bulk_subclass": 0x4F, "vendor_bulk_protocol": 0x45, "hid_usage_page": 0xFF4F, "hid_usage": 0x45, "reference_vid": 0x1209, "reference_pid": 0x4F45}
25
25
  LIMITS = {"lease_min_ms": 0x3E8, "lease_max_ms": 0xEA60, "owner_max_bytes": 0x20, "unit_id_max_bytes": 0x20, "slot_name_max_bytes": 0x20, "interface_name_max_bytes": 0x40, "max_op_ms_reference": 0x2710}
26
26
  COMMON = _NS(enum={"read_from": {"position": 0x00, "oldest": 0x01, "now": 0x02, "last_mark": 0x03}, "read_flags": {"more": 0x01, "gap": 0x02}, "mark_kind": {"reset": 0x01, "restart": 0x02, "attach": 0x03, "detach": 0x04, "lost": 0x05, "clear": 0x06, "host": 0x07, "link_lost": 0x08, "closed": 0x09}, "mark_detail_reset": {"ndmreset": 0x01, "nrst": 0x02, "attach_reset": 0x03}, "mark_detail_restart": {"havereset": 0x01, "resync": 0x02}, "mark_detail_lost": {"overflow": 0x01, "framing": 0x02, "parity": 0x03, "target_timeout": 0x04}, "mark_detail_closed": {"all_released": 0x01, "expired": 0x02, "slot_changed": 0x03, "connection_closed": 0x04}})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: oep-client-python
3
- Version: 0.0.24
3
+ Version: 0.0.25
4
4
  Summary: Open Embedded Probe (OEP) v1 host: serial / USB / TCP transports, the session rules, the standard interfaces, and a fake probe
5
5
  Project-URL: Homepage, https://github.com/Open-Embedded-Probe/oep-client-python
6
6
  Project-URL: Repository, https://github.com/Open-Embedded-Probe/oep-client-python
@@ -129,7 +129,10 @@ but not 1500000 towards the host: oep-spec docs/uart-speed-negotiation.ja.md), s
129
129
  (`link.speed`: `rate`, `chosen`, `in_kb_s` / `out_kb_s`, `trials`) is there to budget a capture or a write.
130
130
 
131
131
  The probe goes back to the boot speed by itself when the session ends (`end`, a lapse, a force), when frames break or the
132
- line goes quiet (`idle_ms`): the link follows an `end` at once, and a request that goes unanswered at a raised rate (its
132
+ line goes quiet (`idle_ms`, at most `port_speed_idle_max_ms` = 3 s; a host that died leaves the rate no longer than
133
+ that): while raised the link sends a keepalive before a request when it has been quiet for 1 s, and `hst.link.keep_alive()`
134
+ does the same for a caller that sits idle for long; opening a serial port retries its first confirm for about 4 s to
135
+ wait out a rate left over. The link follows an `end` at once, and a request that goes unanswered at a raised rate (its
133
136
  resend too) takes the link back to the boot speed, confirmed, and goes once more there - it never wedges. A probe
134
137
  without the feature answers `not supported` and stays at its speed. Behind a broker (TCP) the broker does this, not the
135
138
  client. Serial ports are also opened in the driver's low-latency mode where it has one (an FTDI's latency timer 16 -> 1 ms
@@ -1,4 +1,4 @@
1
- oep_client/__init__.py,sha256=7PyV8fyij6tsSg9yAupMCbleZUUqr8ywU7_McgXM7UE,164
1
+ oep_client/__init__.py,sha256=5RMk_SvbzmZ15kSrpyg7dnKWUVbx3F3FFoPTMBCFOUU,164
2
2
  oep_client/__main__.py,sha256=xrdBG4uBsJjYF5CLKcYmWdf392S-JUhyDGoOkUsk4R8,19682
3
3
  oep_client/arm.py,sha256=JGrevyxH8W-ke33rCv1_zyfekDDZrUv2kJhNRGyKFCA,12708
4
4
  oep_client/capture.py,sha256=goD0of-bClOK88PHR0PpWZ_XJqOWhOL9UVtVU0k3NLA,31994
@@ -10,7 +10,7 @@ oep_client/console.py,sha256=Srzlbto7-NZmkxUFMy_nUAanf9X0ZW1ib5tl6tX4rXU,9790
10
10
  oep_client/core.py,sha256=tbRV2eZNtGtQihNVthZytwVGkXFPAvSKamr2I0Uj3Bc,11525
11
11
  oep_client/decode.py,sha256=6pTFVBT0MLAKedZLVKyd5yT8hjrRw4fdDjnoDiE9XRs,2380
12
12
  oep_client/dump.py,sha256=GAnmu2abuDmGmbWcbbEfC3EUuPp5Hady9vQVNcQ-724,6743
13
- oep_client/endpoint.py,sha256=dnYv8V7S89u1uSGL03Kg2UoTRRqv-cdEXwq8Ya1EQ4A,136740
13
+ oep_client/endpoint.py,sha256=4-o5nDd2bCJsQ-AlqJaedqCoTuzutmRF_kovtlfaKFA,136966
14
14
  oep_client/fake.py,sha256=LG56WG0RrFtmgfodVZhfLWvbojtNFWnk2lycjR6zhiE,19385
15
15
  oep_client/fake_capture.py,sha256=6oo-2byIBuZS0g5hk5KXHkqHNrO9PSRO-5MuetZvk80,26916
16
16
  oep_client/fake_serial.py,sha256=bPzQifttzfQ6SedZ11KBI3aiWuKbN2WXuBnVEqYJoQE,8381
@@ -20,16 +20,16 @@ oep_client/frames.py,sha256=xjgjnXmXUqNJZ5m0h91r4Cy48WoVK1mEMW4gRg-mlMI,3991
20
20
  oep_client/hid_stream.py,sha256=99Dsm4Io1keukuETG_UNqjBGiVYZZeb__Pv4ytaKg9k,10695
21
21
  oep_client/host.py,sha256=3NiPV5rnruaC6PR48LOCEoMRpC6985PA8VpSnr7gB2A,20296
22
22
  oep_client/interfaces.py,sha256=8HXr9iGJASIwBpTHBrCK_0b6NfbclEjCbBCsc62euzg,5693
23
- oep_client/link.py,sha256=0HS79DOse4xmUCWUXIshhebGInPLex-VdK6ztm_Jj34,42438
23
+ oep_client/link.py,sha256=kLigInSw4Ch93MobxW8SjORYSqvwdaOlCIXvxEdfHhs,46609
24
24
  oep_client/message.py,sha256=eQ-27lxN2Y9JadnUFpEmkEW2X7oucrKFFFs4_nnDClU,12322
25
25
  oep_client/names.py,sha256=ztCZFWs__aR-a5G14TnJP-Q4YfLhbyrzvOVOMJuG93k,3653
26
- oep_client/registry.py,sha256=vp-D_4W6KI7zSN2IgL-khcBD_qaR_TSrM3y5yhUsOnc,15693
26
+ oep_client/registry.py,sha256=YEL_iMWFmqAaUY0zTkhs5CqbXBHBx4W8kjm37KPs190,15726
27
27
  oep_client/riscv.py,sha256=vqd2aiLf2MaXcsGqh7Hsg51ng_OQi1DgI-vLZvHJ8VQ,29291
28
28
  oep_client/rp2350.py,sha256=7OMyj270k3AY1e3-ljicPwOjf9jOlokbT6QNkA0b0yY,4227
29
29
  oep_client/uiapduino.py,sha256=kDB8C9GvIPBw94PaCKMzVWNtoQDu_axrz_n_6zbYJGU,6082
30
30
  oep_client/usb_stream.py,sha256=_KQvWq906DnQ4EjW1to7d9ufh3pnGkkkbCzti6GYVCY,11131
31
- oep_client_python-0.0.24.dist-info/METADATA,sha256=5KPnkaDN_mXTZySkNLXlBhK7s4lwPkcdaTWA0kfHJ-E,12869
32
- oep_client_python-0.0.24.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
33
- oep_client_python-0.0.24.dist-info/entry_points.txt,sha256=h6_8QX89Ww1ogALEGG5g4kspT3IOV6O51lwKqf5BWco,49
34
- oep_client_python-0.0.24.dist-info/licenses/LICENSE,sha256=ntlalztb3L1OaNAxmQdHlubu5fVhjMc9oRZi3PeQhXg,1076
35
- oep_client_python-0.0.24.dist-info/RECORD,,
31
+ oep_client_python-0.0.25.dist-info/METADATA,sha256=NXXpVUcXthoYvn9LFMVhCDziB2oapvAXQ-8bU9Qp2rk,13224
32
+ oep_client_python-0.0.25.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
33
+ oep_client_python-0.0.25.dist-info/entry_points.txt,sha256=h6_8QX89Ww1ogALEGG5g4kspT3IOV6O51lwKqf5BWco,49
34
+ oep_client_python-0.0.25.dist-info/licenses/LICENSE,sha256=ntlalztb3L1OaNAxmQdHlubu5fVhjMc9oRZi3PeQhXg,1076
35
+ oep_client_python-0.0.25.dist-info/RECORD,,