syndesi 0.4.0__py3-none-any.whl → 0.4.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 (38) hide show
  1. syndesi/adapters/adapter.py +91 -158
  2. syndesi/adapters/auto.py +1 -1
  3. syndesi/adapters/backend/adapter_backend.py +54 -37
  4. syndesi/adapters/backend/adapter_session.py +26 -27
  5. syndesi/adapters/backend/backend_status.py +0 -0
  6. syndesi/adapters/backend/backend_tools.py +1 -1
  7. syndesi/adapters/backend/descriptors.py +3 -2
  8. syndesi/adapters/backend/ip_backend.py +1 -0
  9. syndesi/adapters/backend/serialport_backend.py +9 -10
  10. syndesi/adapters/backend/stop_condition_backend.py +47 -26
  11. syndesi/adapters/backend/visa_backend.py +7 -7
  12. syndesi/adapters/ip.py +6 -10
  13. syndesi/adapters/stop_condition.py +10 -83
  14. syndesi/adapters/timeout.py +3 -30
  15. syndesi/adapters/visa.py +2 -2
  16. syndesi/cli/backend_status.py +7 -9
  17. syndesi/cli/console.py +1 -54
  18. syndesi/cli/shell.py +1 -14
  19. syndesi/cli/shell_tools.py +0 -5
  20. syndesi/protocols/delimited.py +17 -37
  21. syndesi/protocols/modbus.py +17 -14
  22. syndesi/protocols/raw.py +20 -16
  23. syndesi/protocols/scpi.py +18 -15
  24. syndesi/scripts/syndesi.py +1 -3
  25. syndesi/tools/backend_api.py +5 -38
  26. syndesi/tools/backend_logger.py +0 -1
  27. syndesi/tools/errors.py +4 -5
  28. syndesi/tools/log.py +0 -88
  29. syndesi/tools/types.py +0 -44
  30. syndesi/version.py +1 -1
  31. syndesi-0.4.2.dist-info/METADATA +96 -0
  32. syndesi-0.4.2.dist-info/RECORD +60 -0
  33. syndesi-0.4.0.dist-info/METADATA +0 -123
  34. syndesi-0.4.0.dist-info/RECORD +0 -59
  35. {syndesi-0.4.0.dist-info → syndesi-0.4.2.dist-info}/WHEEL +0 -0
  36. {syndesi-0.4.0.dist-info → syndesi-0.4.2.dist-info}/entry_points.txt +0 -0
  37. {syndesi-0.4.0.dist-info → syndesi-0.4.2.dist-info}/licenses/LICENSE +0 -0
  38. {syndesi-0.4.0.dist-info → syndesi-0.4.2.dist-info}/top_level.txt +0 -0
@@ -15,8 +15,8 @@
15
15
  # An adapter is meant to work with bytes objects but it can accept strings.
16
16
  # Strings will automatically be converted to bytes using utf-8 encoding
17
17
 
18
- from enum import Enum
19
18
  import logging
19
+ import os
20
20
  import queue
21
21
  import subprocess
22
22
  import sys
@@ -25,42 +25,44 @@ import time
25
25
  import weakref
26
26
  from abc import ABC, abstractmethod
27
27
  from collections.abc import Callable
28
+ from enum import Enum
28
29
  from multiprocessing.connection import Client, Connection
29
30
  from types import EllipsisType
30
31
  from typing import Any
31
- import os
32
32
 
33
- from .backend.backend_tools import BACKEND_REQUEST_DEFAULT_TIMEOUT
34
33
  from syndesi.tools.types import NumberLike, is_number
35
34
 
36
35
  from ..tools.backend_api import (
37
36
  BACKEND_PORT,
37
+ EXTRA_BUFFER_RESPONSE_TIME,
38
38
  Action,
39
39
  BackendResponse,
40
+ Fragment,
40
41
  default_host,
41
42
  raise_if_error,
42
- EXTRA_BUFFER_RESPONSE_TIME
43
43
  )
44
44
  from ..tools.log_settings import LoggerAlias
45
45
  from .backend.adapter_backend import (
46
46
  AdapterDisconnected,
47
- AdapterResponseTimeout,
48
47
  AdapterReadPayload,
48
+ AdapterResponseTimeout,
49
49
  AdapterSignal,
50
50
  )
51
+ from .backend.backend_tools import BACKEND_REQUEST_DEFAULT_TIMEOUT
51
52
  from .backend.descriptors import Descriptor
52
- from .stop_condition import StopCondition, Continuation, Total
53
+ from .stop_condition import Continuation, StopCondition, StopConditionType
53
54
  from .timeout import Timeout, TimeoutAction, any_to_timeout
54
55
 
55
56
  DEFAULT_STOP_CONDITION = Continuation(time=0.1)
56
57
 
57
- DEFAULT_TIMEOUT = Timeout(response=5, action='error')
58
+ DEFAULT_TIMEOUT = Timeout(response=5, action="error")
58
59
 
59
60
  # Maximum time to let the backend start
60
61
  START_TIMEOUT = 2
61
62
  # Time to shutdown the backend
62
63
  SHUTDOWN_DELAY = 2
63
64
 
65
+
64
66
  class SignalQueue(queue.Queue[AdapterSignal]):
65
67
  def __init__(self) -> None:
66
68
  self._read_payload_counter = 0
@@ -69,12 +71,12 @@ class SignalQueue(queue.Queue[AdapterSignal]):
69
71
  def has_read_payload(self) -> bool:
70
72
  return self._read_payload_counter > 0
71
73
 
72
-
73
- def put(self, signal: AdapterSignal, block: bool = True, timeout: float | None = None) -> None:
74
+ def put(
75
+ self, signal: AdapterSignal, block: bool = True, timeout: float | None = None
76
+ ) -> None:
74
77
  if isinstance(signal, AdapterReadPayload):
75
78
  self._read_payload_counter += 1
76
79
  return super().put(signal, block, timeout)
77
-
78
80
 
79
81
  def get(self, block: bool = True, timeout: float | None = None) -> AdapterSignal:
80
82
  signal = super().get(block, timeout)
@@ -93,19 +95,20 @@ def is_backend_running(address: str, port: int) -> bool:
93
95
  conn.close()
94
96
  return True
95
97
 
98
+
96
99
  def start_backend(port: int | None = None) -> None:
97
100
  arguments = [
98
- sys.executable,
99
- "-m",
100
- "syndesi.adapters.backend.backend",
101
- "-s",
102
- str(SHUTDOWN_DELAY),
103
- "-q",
104
- "-p",
105
- str(BACKEND_PORT if port is None else port),
106
- ]
107
-
108
- stdin = subprocess.DEVNULL
101
+ sys.executable,
102
+ "-m",
103
+ "syndesi.adapters.backend.backend",
104
+ "-s",
105
+ str(SHUTDOWN_DELAY),
106
+ "-q",
107
+ "-p",
108
+ str(BACKEND_PORT if port is None else port),
109
+ ]
110
+
111
+ stdin = subprocess.DEVNULL
109
112
  stdout = subprocess.DEVNULL
110
113
  stderr = subprocess.DEVNULL
111
114
 
@@ -121,8 +124,8 @@ def start_backend(port: int | None = None) -> None:
121
124
 
122
125
  else:
123
126
  # Windows: detach from the parent's console so keyboard Ctrl+C won't propagate.
124
- CREATE_NEW_PROCESS_GROUP = subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore
125
- DETACHED_PROCESS = 0x00000008 # not exposed by subprocess on all Pythons
127
+ CREATE_NEW_PROCESS_GROUP = subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore
128
+ DETACHED_PROCESS = 0x00000008 # not exposed by subprocess on all Pythons
126
129
  # Optional: CREATE_NO_WINDOW (no window even for console apps)
127
130
  CREATE_NO_WINDOW = 0x08000000
128
131
 
@@ -137,9 +140,11 @@ def start_backend(port: int | None = None) -> None:
137
140
  close_fds=True,
138
141
  )
139
142
 
143
+
140
144
  class ReadScope(Enum):
141
- NEXT = 'next'
142
- BUFFERED = 'buffered'
145
+ NEXT = "next"
146
+ BUFFERED = "buffered"
147
+
143
148
 
144
149
  class Adapter(ABC):
145
150
  def __init__(
@@ -214,7 +219,7 @@ class Adapter(ABC):
214
219
  elif isinstance(stop_conditions, list):
215
220
  self._stop_conditions = stop_conditions
216
221
  else:
217
- raise ValueError('Invalid stop_conditions')
222
+ raise ValueError("Invalid stop_conditions")
218
223
 
219
224
  # Set the timeout
220
225
  self.is_default_timeout = False
@@ -334,7 +339,7 @@ class Adapter(ABC):
334
339
  action = Action(response[0])
335
340
 
336
341
  if action == Action.ADAPTER_SIGNAL:
337
- #if is_event(action):
342
+ # if is_event(action):
338
343
  if len(response) <= 1:
339
344
  raise RuntimeError(f"Invalid event response : {response}")
340
345
  signal: AdapterSignal = response[1]
@@ -370,7 +375,9 @@ class Adapter(ABC):
370
375
  self._logger.debug(f"Setting default timeout to {default_timeout}")
371
376
  self._timeout = default_timeout
372
377
 
373
- def set_stop_conditions(self, stop_conditions: StopCondition | None | list[StopCondition]) -> None:
378
+ def set_stop_conditions(
379
+ self, stop_conditions: StopCondition | None | list[StopCondition]
380
+ ) -> None:
374
381
  """
375
382
  Overwrite the stop-condition
376
383
 
@@ -385,7 +392,7 @@ class Adapter(ABC):
385
392
  elif stop_conditions is None:
386
393
  self._stop_conditions = []
387
394
 
388
- self._make_backend_request(Action.SET_STOP_CONDITION, self._stop_conditions)
395
+ self._make_backend_request(Action.SET_STOP_CONDITIONs, self._stop_conditions)
389
396
 
390
397
  def set_default_stop_condition(self, stop_condition: StopCondition) -> None:
391
398
  """
@@ -410,7 +417,6 @@ class Adapter(ABC):
410
417
  self._signal_queue.get(block=False)
411
418
  except queue.Empty:
412
419
  break
413
-
414
420
 
415
421
  def previous_read_buffer_empty(self) -> bool:
416
422
  """
@@ -462,9 +468,9 @@ class Adapter(ABC):
462
468
  def read_detailed(
463
469
  self,
464
470
  timeout: Timeout | EllipsisType | None = ...,
465
- stop_condition: StopCondition | EllipsisType | None = ...,
466
- scope : str = ReadScope.BUFFERED.value,
467
- ) -> AdapterReadPayload | None:
471
+ stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
472
+ scope: str = ReadScope.BUFFERED.value,
473
+ ) -> AdapterReadPayload:
468
474
  """
469
475
  Read data from the device
470
476
 
@@ -481,9 +487,22 @@ class Adapter(ABC):
481
487
  data : bytes
482
488
  signal : AdapterReadPayload
483
489
  """
484
- t = time.time()
485
490
  _scope = ReadScope(scope)
486
491
  output_signal = None
492
+ read_timeout = None
493
+
494
+ if timeout is ...:
495
+ read_timeout = self._timeout
496
+ else:
497
+ read_timeout = any_to_timeout(timeout)
498
+
499
+ if read_timeout is None:
500
+ raise RuntimeError("Cannot read without setting a timeout")
501
+
502
+ if stop_conditions is not ...:
503
+ if isinstance(stop_conditions, StopCondition):
504
+ stop_conditions = [stop_conditions]
505
+ self._make_backend_request(Action.SET_STOP_CONDITIONs, stop_conditions)
487
506
 
488
507
  # First, we check if data is in the buffer and if the scope if set to BUFFERED
489
508
  while _scope == ReadScope.BUFFERED and self._signal_queue.has_read_payload():
@@ -495,42 +514,37 @@ class Adapter(ABC):
495
514
  else:
496
515
  # Nothing was found, ask the backend with a START_READ request. The backend will
497
516
  # respond at most after the response_time with either data or a RESPONSE_TIMEOUT
498
- if timeout is ...:
499
- read_timeout = self._timeout
500
- else:
501
- read_timeout = any_to_timeout(timeout)
502
517
 
503
- if read_timeout is not None:
504
- if not read_timeout.is_initialized():
505
- raise RuntimeError("Timeout needs to be initialized")
518
+ if not read_timeout.is_initialized():
519
+ raise RuntimeError("Timeout needs to be initialized")
506
520
 
507
- _response = read_timeout.response()
521
+ _response = read_timeout.response()
508
522
 
509
- read_init_time = time.time()
510
- start_read_id = self._make_backend_request(Action.START_READ, _response)[0]
511
-
512
- if _response is None:
513
- # Wait indefinitely
514
- read_stop_timestamp = None
515
- else:
516
- # Wait for the response time + a bit more
517
- read_stop_timestamp = read_init_time + _response
523
+ read_init_time = time.time()
524
+ start_read_id = self._make_backend_request(Action.START_READ, _response)[0]
518
525
 
526
+ if _response is None:
527
+ # Wait indefinitely
528
+ read_stop_timestamp = None
519
529
  else:
520
- start_read_id = None
521
- read_init_time = None
530
+ # Wait for the response time + a bit more
531
+ read_stop_timestamp = read_init_time + _response
522
532
 
523
-
524
533
  while True:
525
534
  try:
526
535
  if read_stop_timestamp is None:
527
536
  queue_timeout = None
528
537
  else:
529
- queue_timeout = max(0, read_stop_timestamp - time.time() + EXTRA_BUFFER_RESPONSE_TIME)
538
+ queue_timeout = max(
539
+ 0,
540
+ read_stop_timestamp
541
+ - time.time()
542
+ + EXTRA_BUFFER_RESPONSE_TIME,
543
+ )
530
544
 
531
545
  signal = self._signal_queue.get(timeout=queue_timeout)
532
- except queue.Empty:
533
- raise RuntimeError('Failed to receive response from backend')
546
+ except queue.Empty as e:
547
+ raise RuntimeError("Failed to receive response from backend") from e
534
548
  if isinstance(signal, AdapterReadPayload):
535
549
  output_signal = signal
536
550
  break
@@ -542,113 +556,35 @@ class Adapter(ABC):
542
556
  break
543
557
  # Otherwise ignore it
544
558
 
545
-
546
559
  if output_signal is None:
547
- # TODO : Make read_timeout always Timeout, never None ?
548
560
  match read_timeout.action:
549
- case TimeoutAction.RETURN:
550
- return None
561
+ case TimeoutAction.RETURN_EMPTY:
562
+ t = time.time()
563
+ return AdapterReadPayload(
564
+ fragments=[Fragment(b"", t)],
565
+ stop_timestamp=t,
566
+ stop_condition_type=StopConditionType.TIMEOUT,
567
+ previous_read_buffer_used=False,
568
+ response_timestamp=None,
569
+ response_delay=None,
570
+ )
551
571
  case TimeoutAction.ERROR:
552
572
  raise TimeoutError(
553
573
  f"No response received from device within {read_timeout.response()} seconds"
554
574
  )
555
575
  case _:
556
576
  raise NotImplementedError()
557
-
577
+
558
578
  else:
559
579
  return output_signal
560
580
 
561
-
562
- # Okay idea : Remove the start read and instead ask for the time of the backend.
563
- # Then we read whatever payload comes from the backend and compare that to the time
564
- # If it doesn't match our criteria, we trash it
565
- # When waiting for the backend payload, we wait +0.5s so make sure we received everything
566
- # This 0.5s could be changed if we're local or not by the way
567
-
568
-
569
- # # First, ask for the backend time, this is the official start of the read
570
- # backend_read_start_time = cast(NumberLike, self._make_backend_request(Action.GET_BACKEND_TIME)[0])
571
-
572
- # If not timeout is specified, use the default one
573
-
574
- # Calculate last_valid_timestamp, the limit at which a payload is not accepted anymore
575
- # Calculate the queue timeout (time for a response + small delay)
576
- #last_valid_timestamp = None
577
- # queue_timeout_timestamp = None
578
- # if read_timeout is not None:
579
- # response_delay = read_timeout.response()
580
- # else:
581
- # response_delay = None
582
-
583
- # if response_delay is not None:
584
- # #last_valid_timestamp = backend_read_start_time + response_delay
585
- # queue_timeout_timestamp = time.time() + response_delay + BACKEND_REQUEST_DEFAULT_TIMEOUT
586
-
587
- # output_signal : AdapterReadPayload | None
588
- # # This delay is given by the backend when a fragment is received. It basically says
589
- # # "I've received something, wait at most x seconds before raising an error"
590
- # read_init_end_delay : float | None = None
591
-
592
- # # Ready to read payloads
593
- # while True:
594
- # if read_init_end_delay is not None:
595
- # # Find the next timeout
596
- # queue_timeout = read_init_end_delay + 0.1 # TODO : Make this clean, this is the delay to let data arrive to the frontend
597
- # elif queue_timeout_timestamp is None:
598
- # queue_timeout = None
599
- # else:
600
- # queue_timeout = queue_timeout_timestamp - time.time()
601
- # if queue_timeout < 0:
602
- # queue_timeout = 0
603
-
604
- # try:
605
- # response = self._signal_queue.peek(block=True, timeout=queue_timeout)
606
- # signal = response[1]
607
-
608
- # if isinstance(signal, AdapterReadPayload):
609
- # if response_delay is not None and signal.response_timestamp - backend_read_start_time > response_delay:
610
- # # This signal happened after the max response time, act as if a timeout occured
611
- # # and do not pop it out of the queue
612
- # # TODO : Make _timeout always Timeout, never None ?
613
- # output_signal = None
614
- # break
615
-
616
- # if _scope == ReadScope.NEXT and signal.response_timestamp < backend_read_start_time:
617
- # # The payload happened before the read start
618
- # self._signal_queue.get()
619
- # continue
620
-
621
- # if response_delay is not None:
622
- # if signal.response_timestamp - backend_read_start_time > response_delay:
623
- # self._signal_queue.get()
624
- # output_signal = None
625
- # break
626
-
627
- # # Other wise the payload is valid
628
- # self._signal_queue.get()
629
- # output_signal = signal
630
- # break
631
- # elif isinstance(signal, AdapterReadInit):
632
- # read_init_end_delay = signal.end_delay
633
- # self._signal_queue.get()
634
- # elif isinstance(signal, AdapterDisconnected):
635
- # self._signal_queue.get()
636
-
637
-
638
- # except queue.Empty:
639
- # output_signal = None
640
- # break
641
-
642
581
  def read(
643
582
  self,
644
583
  timeout: Timeout | EllipsisType | None = ...,
645
- stop_condition: StopCondition | EllipsisType | None = ...,
584
+ stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
646
585
  ) -> bytes:
647
- signal = self.read_detailed(timeout=timeout, stop_condition=stop_condition)
648
- if signal is None:
649
- return None
650
- else:
651
- return signal.data()
586
+ signal = self.read_detailed(timeout=timeout, stop_conditions=stop_conditions)
587
+ return signal.data()
652
588
 
653
589
  def _cleanup(self) -> None:
654
590
  if self._init_ok and self.opened:
@@ -658,8 +594,8 @@ class Adapter(ABC):
658
594
  self,
659
595
  data: bytes | str,
660
596
  timeout: Timeout | EllipsisType | None = ...,
661
- stop_condition: StopCondition | EllipsisType | None = ...,
662
- ) -> tuple[bytes, AdapterReadPayload | None]:
597
+ stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
598
+ ) -> AdapterReadPayload:
663
599
  """
664
600
  Shortcut function that combines
665
601
  - flush_read
@@ -668,21 +604,18 @@ class Adapter(ABC):
668
604
  """
669
605
  self.flushRead()
670
606
  self.write(data)
671
- return self.read_detailed(timeout=timeout, stop_condition=stop_condition)
607
+ return self.read_detailed(timeout=timeout, stop_conditions=stop_conditions)
672
608
 
673
609
  def query(
674
610
  self,
675
611
  data: bytes | str,
676
612
  timeout: Timeout | EllipsisType | None = ...,
677
- stop_condition: StopCondition | EllipsisType | None = ...,
613
+ stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
678
614
  ) -> bytes:
679
615
  signal = self.query_detailed(
680
- data=data, timeout=timeout, stop_condition=stop_condition
616
+ data=data, timeout=timeout, stop_conditions=stop_conditions
681
617
  )
682
- if signal is None:
683
- return None
684
- else:
685
- return signal.data()
618
+ return signal.data()
686
619
 
687
620
  def set_event_callback(self, callback: Callable[[AdapterSignal], None]) -> None:
688
621
  self.event_callback = callback
syndesi/adapters/auto.py CHANGED
@@ -37,7 +37,7 @@ def auto_adapter(adapter_or_string: Adapter | str) -> Adapter:
37
37
  return IP(
38
38
  address=descriptor.address,
39
39
  port=descriptor.port,
40
- transport=descriptor.transport,
40
+ transport=descriptor.transport.value,
41
41
  )
42
42
  elif isinstance(descriptor, SerialPortDescriptor):
43
43
  return SerialPort(port=descriptor.port, baudrate=descriptor.baudrate)
@@ -7,19 +7,18 @@
7
7
 
8
8
  import logging
9
9
  import socket
10
+ import time
10
11
  from abc import ABC, abstractmethod
11
12
  from collections.abc import Generator
12
13
  from dataclasses import dataclass
13
14
  from enum import Enum
14
15
  from multiprocessing.connection import Connection
15
16
  from threading import Thread
16
- import time
17
- from typing import Protocol, cast
18
-
19
- from syndesi.tools.types import NumberLike
17
+ from typing import Protocol
20
18
 
21
19
  from ...tools.backend_api import AdapterBackendStatus, Fragment
22
20
  from ...tools.log_settings import LoggerAlias
21
+ from ..stop_condition import StopConditionType
23
22
  from .descriptors import Descriptor
24
23
  from .stop_condition_backend import (
25
24
  ContinuationBackend,
@@ -27,8 +26,6 @@ from .stop_condition_backend import (
27
26
  TotalBackend,
28
27
  )
29
28
 
30
- from ..stop_condition import Continuation, StopConditionType
31
-
32
29
 
33
30
  class HasFileno(Protocol):
34
31
  def fileno(self) -> int:
@@ -82,12 +79,13 @@ class AdapterDisconnected(AdapterSignal):
82
79
  # def __repr__(self) -> str:
83
80
  # return self.__str__()
84
81
 
82
+
85
83
  @dataclass
86
84
  class AdapterResponseTimeout(AdapterSignal):
87
- identifier : int
85
+ identifier: int
88
86
 
89
87
  def __str__(self) -> str:
90
- return f"Response timeout"
88
+ return "Response timeout"
91
89
 
92
90
  def __repr__(self) -> str:
93
91
  return self.__str__()
@@ -99,9 +97,9 @@ class AdapterReadPayload(AdapterSignal):
99
97
  stop_timestamp: float
100
98
  stop_condition_type: StopConditionType
101
99
  previous_read_buffer_used: bool
102
- response_timestamp : float | None
100
+ response_timestamp: float | None
103
101
  # Only used by client and set by frontend
104
- response_delay : float | None = None
102
+ response_delay: float | None = None
105
103
 
106
104
  def data(self) -> bytes:
107
105
  return b"".join([f.data for f in self.fragments])
@@ -118,9 +116,10 @@ class AdapterReadPayload(AdapterSignal):
118
116
  @dataclass
119
117
  class ResponseRequest:
120
118
  timestamp: float
121
- identifier : int
119
+ identifier: int
120
+
122
121
 
123
- def nmin(a : float | None, b : float | None) -> float | None:
122
+ def nmin(a: float | None, b: float | None) -> float | None:
124
123
  if a is None and b is None:
125
124
  return None
126
125
  elif a is None:
@@ -130,6 +129,7 @@ def nmin(a : float | None, b : float | None) -> float | None:
130
129
  else:
131
130
  return min(a, b)
132
131
 
132
+
133
133
  class AdapterBackend(ABC):
134
134
  class ThreadCommands(Enum):
135
135
  STOP = b"0"
@@ -168,7 +168,7 @@ class AdapterBackend(ABC):
168
168
  # None : No ask
169
169
  # float : Ask for a response to happen at the specified value at max
170
170
  self._response_request: ResponseRequest | None = None
171
- self._response_request_start : float | None = None
171
+ self._response_request_start: float | None = None
172
172
 
173
173
  self._first_fragment = True
174
174
 
@@ -246,10 +246,10 @@ class AdapterBackend(ABC):
246
246
  @abstractmethod
247
247
  def _socket_read(self) -> Fragment:
248
248
  raise NotImplementedError
249
-
250
- def _fragments_to_string(self, fragments : list[Fragment]) -> str:
249
+
250
+ def _fragments_to_string(self, fragments: list[Fragment]) -> str:
251
251
  if len(fragments) > 0:
252
- return '+'.join(repr(f.data) for f in fragments)
252
+ return "+".join(repr(f.data) for f in fragments)
253
253
  else:
254
254
  return str([])
255
255
 
@@ -260,11 +260,13 @@ class AdapterBackend(ABC):
260
260
  else:
261
261
  fragment_delta_t = float("nan")
262
262
  if fragment.data == b"":
263
- self._logger.debug('Empty data -> close')
264
263
  self.close()
265
264
  yield AdapterDisconnected()
266
265
  else:
267
- self._logger.debug(f"New fragment {fragment_delta_t:+.3f} {fragment}" + (" (first)" if self._first_fragment else ""))
266
+ self._logger.debug(
267
+ f"New fragment {fragment_delta_t:+.3f} {fragment}"
268
+ + (" (first)" if self._first_fragment else "")
269
+ )
268
270
  if self._status == AdapterBackendStatus.CONNECTED:
269
271
  t = time.time()
270
272
 
@@ -273,7 +275,9 @@ class AdapterBackend(ABC):
273
275
 
274
276
  if self._response_request is not None:
275
277
  for stop_condition in self._stop_conditions:
276
- if isinstance(stop_condition, (ContinuationBackend, TotalBackend)):
278
+ if isinstance(
279
+ stop_condition, (ContinuationBackend, TotalBackend)
280
+ ):
277
281
  self._response_request = None
278
282
  break
279
283
 
@@ -288,15 +292,18 @@ class AdapterBackend(ABC):
288
292
  kept = fragment
289
293
 
290
294
  # Run each stop condition one after the other, if a stop is reached, stop evaluating
291
- stop_condition_type : StopConditionType
295
+ stop_condition_type: StopConditionType
292
296
  for stop_condition in self._stop_conditions:
293
- stop, kept, self._previous_buffer, self._next_timeout_timestamp = \
294
- stop_condition.evaluate(kept)
297
+ (
298
+ stop,
299
+ kept,
300
+ self._previous_buffer,
301
+ self._next_timeout_timestamp,
302
+ ) = stop_condition.evaluate(kept)
295
303
  if stop:
296
304
  stop_condition_type = stop_condition.type()
297
305
  break
298
306
 
299
-
300
307
  # if kept.data != b'':
301
308
  # self.fragments.append(kept)
302
309
 
@@ -304,14 +311,22 @@ class AdapterBackend(ABC):
304
311
 
305
312
  if stop:
306
313
  self._first_fragment = True
307
- self._logger.debug(f"Payload {self._fragments_to_string(self.fragments)} ({stop_condition_type.value})")
308
- if self._response_request_start is None or len(self.fragments) == 0:
314
+ self._logger.debug(
315
+ f"Payload {self._fragments_to_string(self.fragments)} ({stop_condition_type.value})"
316
+ )
317
+ if (
318
+ self._response_request_start is None
319
+ or len(self.fragments) == 0
320
+ ):
309
321
  response_delay = None
310
322
  else:
311
323
  if self.fragments[0].timestamp is None:
312
324
  response_delay = None
313
325
  else:
314
- response_delay = self.fragments[0].timestamp - self._response_request_start
326
+ response_delay = (
327
+ self.fragments[0].timestamp
328
+ - self._response_request_start
329
+ )
315
330
  self._response_request_start = None
316
331
  yield AdapterReadPayload(
317
332
  fragments=self.fragments,
@@ -319,9 +334,9 @@ class AdapterBackend(ABC):
319
334
  stop_condition_type=stop_condition_type,
320
335
  previous_read_buffer_used=False,
321
336
  response_timestamp=self.fragments[0].timestamp,
322
- response_delay=response_delay
337
+ response_delay=response_delay,
323
338
  )
324
- self._next_timeout_timestamp = None # Experiment !
339
+ self._next_timeout_timestamp = None # Experiment !
325
340
  self.fragments.clear()
326
341
 
327
342
  if len(self._previous_buffer.data) > 0 and stop:
@@ -342,8 +357,9 @@ class AdapterBackend(ABC):
342
357
  """
343
358
  self._response_request_start = time.time()
344
359
  self._logger.debug(f"Setup read [{identifier}] in {response_time:.3f} s")
345
- self._response_request = ResponseRequest(self._response_request_start + response_time, identifier)
346
-
360
+ self._response_request = ResponseRequest(
361
+ self._response_request_start + response_time, identifier
362
+ )
347
363
 
348
364
  @abstractmethod
349
365
  def is_opened(self) -> bool:
@@ -367,7 +383,9 @@ class AdapterBackend(ABC):
367
383
  response_delay = None
368
384
  else:
369
385
  if self.fragments[0].timestamp is not None:
370
- response_delay = self.fragments[0].timestamp - self._response_request_start
386
+ response_delay = (
387
+ self.fragments[0].timestamp - self._response_request_start
388
+ )
371
389
  else:
372
390
  response_delay = None
373
391
  self._response_request_start = None
@@ -377,8 +395,10 @@ class AdapterBackend(ABC):
377
395
  stop_condition_type=StopConditionType.TIMEOUT,
378
396
  previous_read_buffer_used=False,
379
397
  fragments=self.fragments,
380
- response_timestamp=self.fragments[0].timestamp if len(self.fragments) > 0 else None,
381
- response_delay=response_delay
398
+ response_timestamp=(
399
+ self.fragments[0].timestamp if len(self.fragments) > 0 else None
400
+ ),
401
+ response_delay=response_delay,
382
402
  )
383
403
  # Reset response request
384
404
  if self._response_request is not None:
@@ -389,8 +409,7 @@ class AdapterBackend(ABC):
389
409
  return output
390
410
 
391
411
  elif (
392
- self._next_timeout_origin
393
- == self.AdapterTimeoutEventOrigin.RESPONSE_REQUEST
412
+ self._next_timeout_origin == self.AdapterTimeoutEventOrigin.RESPONSE_REQUEST
394
413
  ):
395
414
  if self._response_request is not None:
396
415
  signal = AdapterResponseTimeout(self._response_request.identifier)
@@ -403,8 +422,6 @@ class AdapterBackend(ABC):
403
422
  min_timestamp = None
404
423
  self._next_timeout_origin = None
405
424
 
406
- t = time.time()
407
-
408
425
  if self._next_timeout_timestamp is not None:
409
426
  min_timestamp = self._next_timeout_timestamp
410
427
  self._next_timeout_origin = self.AdapterTimeoutEventOrigin.TIMEOUT