syndesi 0.4.2__py3-none-any.whl → 0.5.0__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 (57) hide show
  1. syndesi/__init__.py +22 -2
  2. syndesi/adapters/adapter.py +332 -489
  3. syndesi/adapters/adapter_worker.py +820 -0
  4. syndesi/adapters/auto.py +58 -25
  5. syndesi/adapters/descriptors.py +38 -0
  6. syndesi/adapters/ip.py +203 -71
  7. syndesi/adapters/serialport.py +154 -25
  8. syndesi/adapters/stop_conditions.py +354 -0
  9. syndesi/adapters/timeout.py +58 -21
  10. syndesi/adapters/visa.py +236 -11
  11. syndesi/cli/console.py +51 -16
  12. syndesi/cli/shell.py +95 -47
  13. syndesi/cli/terminal_tools.py +8 -8
  14. syndesi/component.py +315 -0
  15. syndesi/protocols/delimited.py +92 -107
  16. syndesi/protocols/modbus.py +2368 -868
  17. syndesi/protocols/protocol.py +186 -33
  18. syndesi/protocols/raw.py +45 -62
  19. syndesi/protocols/scpi.py +65 -102
  20. syndesi/remote/remote.py +188 -0
  21. syndesi/scripts/syndesi.py +12 -2
  22. syndesi/tools/errors.py +49 -31
  23. syndesi/tools/log_settings.py +21 -8
  24. syndesi/tools/{log.py → logmanager.py} +24 -13
  25. syndesi/tools/types.py +9 -7
  26. syndesi/version.py +5 -1
  27. {syndesi-0.4.2.dist-info → syndesi-0.5.0.dist-info}/METADATA +1 -1
  28. syndesi-0.5.0.dist-info/RECORD +41 -0
  29. syndesi/adapters/backend/__init__.py +0 -0
  30. syndesi/adapters/backend/adapter_backend.py +0 -438
  31. syndesi/adapters/backend/adapter_manager.py +0 -48
  32. syndesi/adapters/backend/adapter_session.py +0 -346
  33. syndesi/adapters/backend/backend.py +0 -438
  34. syndesi/adapters/backend/backend_status.py +0 -0
  35. syndesi/adapters/backend/backend_tools.py +0 -66
  36. syndesi/adapters/backend/descriptors.py +0 -153
  37. syndesi/adapters/backend/ip_backend.py +0 -149
  38. syndesi/adapters/backend/serialport_backend.py +0 -241
  39. syndesi/adapters/backend/stop_condition_backend.py +0 -219
  40. syndesi/adapters/backend/timed_queue.py +0 -39
  41. syndesi/adapters/backend/timeout.py +0 -252
  42. syndesi/adapters/backend/visa_backend.py +0 -197
  43. syndesi/adapters/ip_server.py +0 -102
  44. syndesi/adapters/stop_condition.py +0 -90
  45. syndesi/cli/backend_console.py +0 -96
  46. syndesi/cli/backend_status.py +0 -274
  47. syndesi/cli/backend_wrapper.py +0 -61
  48. syndesi/scripts/syndesi_backend.py +0 -37
  49. syndesi/tools/backend_api.py +0 -175
  50. syndesi/tools/backend_logger.py +0 -64
  51. syndesi/tools/exceptions.py +0 -16
  52. syndesi/tools/internal.py +0 -0
  53. syndesi-0.4.2.dist-info/RECORD +0 -60
  54. {syndesi-0.4.2.dist-info → syndesi-0.5.0.dist-info}/WHEEL +0 -0
  55. {syndesi-0.4.2.dist-info → syndesi-0.5.0.dist-info}/entry_points.txt +0 -0
  56. {syndesi-0.4.2.dist-info → syndesi-0.5.0.dist-info}/licenses/LICENSE +0 -0
  57. {syndesi-0.4.2.dist-info → syndesi-0.5.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,188 @@
1
+ DEFAULT_REMOTE_PORT = 59677
2
+
3
+
4
+ # Backend protocol format
5
+ # (action, arguments)
6
+ # If the command succeeds, it is returned as :
7
+ # (action, other arguments)
8
+ # If the command fails, it is returned as :
9
+ # (error, error_description)
10
+
11
+
12
+ # The backend links the client with an adapter when SELECT_ADAPTER is
13
+ # sent along with an adapter descriptor
14
+
15
+ EXTRA_BUFFER_RESPONSE_TIME = 1
16
+
17
+ # Delay to let the adapter connect
18
+ DEFAULT_ADAPTER_OPEN_TIMEOUT = 0.5
19
+
20
+
21
+ # def add_backend_address_port_arguments(
22
+ # parser: argparse.ArgumentParser, client_side: bool
23
+ # ) -> None:
24
+ # """
25
+ # Add -a/--address and -p/--port to a given ArgumentParser. The description of -a/--address
26
+ # is different based on the value of client_side
27
+ # """
28
+ # if client_side:
29
+ # address_help = "Address of the backend"
30
+ # else:
31
+ # address_help = (
32
+ # "Backend listening address, set it to the host address used by clients"
33
+ # )
34
+
35
+ # parser.add_argument(
36
+ # "-a", "--address", type=str, default=LOCALHOST, help=address_help
37
+ # )
38
+ # parser.add_argument("-p", "--port", type=int, default=BACKEND_PORT)
39
+
40
+
41
+ # class Action(Enum):
42
+ # """
43
+ # Backend actions enum
44
+ # """
45
+
46
+ # # All adapters
47
+ # SELECT_ADAPTER = "select"
48
+ # OPEN = "open" # (descriptor,stop_condition) -> ()
49
+ # CLOSE = "close" # (descriptor,force) -> ()
50
+ # # FORCE_CLOSE = "force_close" # (descriptor,) -> ()
51
+ # WRITE = "write" # (descriptor,data) -> ()
52
+ # READ = "read" # (descriptor,full_output,temp_timeout,temp_stop_condition) -> (data,metrics)
53
+ # SET_STOP_CONDITIONS = "set_stop_condition" # (descriptor,stop_condition)
54
+ # FLUSHREAD = "flushread"
55
+ # START_READ = "start_read" # Start a read (descriptor,response_time)
56
+ # RESPONSE_TIMEOUT = "response_timeout"
57
+
58
+ # # Signal
59
+ # ADAPTER_SIGNAL = "adapter_signal"
60
+
61
+ # # Other
62
+ # SET_ROLE_ADAPTER = (
63
+ # "set_role_adapter" # Define the client as an adapter (exchange of data)
64
+ # )
65
+ # SET_ROLE_MONITORING = "set_role_monitoring" # The client queries for backend info
66
+ # SET_ROLE_LOGGER = "set_role_logger" # The client receives logs
67
+ # SET_LOG_LEVEL = "set_log_level"
68
+ # PING = "ping"
69
+ # STOP = "stop"
70
+
71
+ # # Backend debugger
72
+ # ENUMERATE_ADAPTER_CONNECTIONS = "enumerate_adapter_connections"
73
+ # ENUMERATE_MONITORING_CONNECTIONS = "enumerate_monitoring_connections"
74
+ # BACKEND_STATS = "backend_stats"
75
+
76
+ # # Errors
77
+ # ERROR_GENERIC = "error_generic"
78
+ # ERROR_UNKNOWN_ACTION = "error_unknown_action"
79
+ # ERROR_INVALID_REQUEST = "error_invalid_request"
80
+ # ERROR_ADAPTER_NOT_OPENED = "error_adapter_not_opened"
81
+ # ERROR_INVALID_ROLE = "error_invalid_role"
82
+ # ERROR_ADAPTER_DISCONNECTED = "error_adapter_disconnected"
83
+ # ERROR_BACKEND_DISCONNECTED = "error_backend_disconnected"
84
+ # ERROR_FAILED_TO_OPEN = "error_failed_to_open"
85
+
86
+
87
+ # def is_action_error(action: Action) -> bool:
88
+ # """
89
+ # Return True if the action describes an error
90
+ # """
91
+ # return action.value.startswith("error_")
92
+
93
+
94
+ # class BackendException(Exception):
95
+ # """
96
+ # Generic backend error
97
+ # """
98
+
99
+
100
+ # def frontend_send(conn: Connection, action: Action, *args: Any) -> bool:
101
+ # """
102
+ # Send an action to the frontend
103
+ # """
104
+ # try:
105
+ # conn.send((action.value, *args))
106
+ # except (BrokenPipeError, OSError):
107
+ # return False
108
+ # return True
109
+
110
+
111
+ # def backend_request(
112
+ # conn: Connection,
113
+ # action: Action,
114
+ # *args: Any,
115
+ # timeout: float = EXTRA_BUFFER_RESPONSE_TIME,
116
+ # ) -> BackendResponse:
117
+ # """
118
+ # Send a request to the backend an expect a response with the time specified by timeout
119
+ # """
120
+ # try:
121
+ # conn.send((action.value, *args))
122
+ # except (BrokenPipeError, OSError) as err:
123
+ # raise BackendCommunicationError("Failed to communicate with backend") from err
124
+
125
+ # ready = wait([conn], timeout=timeout)
126
+ # if conn not in ready:
127
+ # raise BackendCommunicationError("Failed to receive backend response in time")
128
+
129
+ # try:
130
+ # raw_response: object = conn.recv()
131
+ # except (EOFError, ConnectionResetError) as err:
132
+ # raise BackendCommunicationError(
133
+ # f"Failed to receive backend response to {action.value}"
134
+ # ) from err
135
+
136
+ # # Check if the response is correctly formatted
137
+ # if not (isinstance(raw_response, tuple) and isinstance(raw_response[0], str)):
138
+ # raise BackendCommunicationError(
139
+ # f"Invalid response received from backend : {raw_response}"
140
+ # )
141
+
142
+ # response_action: Action = Action(raw_response[0])
143
+ # arguments: tuple[Any, ...] = raw_response[1:]
144
+
145
+ # if is_action_error(response_action):
146
+ # if len(arguments) > 0:
147
+ # if isinstance(arguments[0], str):
148
+ # error_message: str = arguments[0]
149
+ # else:
150
+ # error_message = "failed to read error message"
151
+ # else:
152
+ # error_message = "Missing error message"
153
+ # raise BackendError(f"{response_action} : {error_message}")
154
+ # return arguments
155
+
156
+
157
+ # backend_send = frontend_send
158
+
159
+
160
+ # def raise_if_error(response: BackendResponse) -> None:
161
+ # """
162
+ # Raise error if the action is an error, ignore otherwise
163
+ # """
164
+ # action = Action(response[0])
165
+ # if is_action_error(action):
166
+ # if len(response) > 1:
167
+ # description = response[1]
168
+ # else:
169
+ # description = f"{action}"
170
+ # raise BackendException(f"{action.name}/{description}")
171
+
172
+
173
+ # class AdapterBackendStatus(Enum):
174
+ # """
175
+ # Adapter backend status enum
176
+ # """
177
+
178
+ # DISCONNECTED = 0
179
+ # CONNECTED = 1
180
+
181
+
182
+ # class ClientStatus(Enum):
183
+ # """
184
+ # Client status enum
185
+ # """
186
+
187
+ # DISCONNECTED = 0
188
+ # CONNECTED = 1
@@ -1,16 +1,23 @@
1
1
  # File : syndesi.py
2
2
  # Author : Sébastien Deriaz
3
3
  # License : GPL
4
+ """
5
+ Main syndesi CLI script
6
+ """
4
7
 
5
8
  import argparse
6
9
  from enum import Enum
7
10
 
8
11
  from ..cli.shell import AdapterShell, AdapterType
9
- from ..tools.log import log
12
+ from ..tools.logmanager import log
10
13
  from ..version import __version__
11
14
 
12
15
 
13
16
  class SyndesiCommands(Enum):
17
+ """
18
+ Syndesi script commands enum
19
+ """
20
+
14
21
  SERIAL = "serial"
15
22
  IP = "ip"
16
23
  MODBUS = "modbus"
@@ -18,6 +25,9 @@ class SyndesiCommands(Enum):
18
25
 
19
26
 
20
27
  def main() -> None:
28
+ """
29
+ Main syndesi entry point
30
+ """
21
31
  parser = argparse.ArgumentParser(
22
32
  prog="syndesi", description="Syndesi command line tool", epilog=""
23
33
  )
@@ -43,7 +53,7 @@ def main() -> None:
43
53
  elif command == SyndesiCommands.VISA:
44
54
  AdapterShell(AdapterType.VISA, remaining_args).run()
45
55
  else:
46
- raise RuntimeError(f"Command '{command.value}' is not supported yet")
56
+ raise NotImplementedError(f"Command '{command.value}' is not supported yet")
47
57
 
48
58
 
49
59
  if __name__ == "__main__":
syndesi/tools/errors.py CHANGED
@@ -1,9 +1,14 @@
1
1
  # File : errors.py
2
2
  # Author : Sébastien Deriaz
3
3
  # License : GPL
4
+ """
5
+ Syndesi errors
6
+ """
4
7
 
5
8
  from pathlib import Path
6
9
 
10
+ from syndesi.tools.types import NumberLike
11
+
7
12
  PACKAGE_PATH = Path(__file__).resolve().parent.parent
8
13
 
9
14
 
@@ -11,40 +16,53 @@ class SyndesiError(Exception):
11
16
  """Base class for all Syndesi errors"""
12
17
 
13
18
 
14
- class BackendCommunicationError(SyndesiError):
15
- """Error with backend communication"""
19
+ class AdapterError(SyndesiError):
20
+ """Adapter error"""
16
21
 
17
22
 
18
- class BackendError(SyndesiError):
19
- """Error inside the backend"""
23
+ class AdapterConfigurationError(AdapterError):
24
+ """Adapter configuration error"""
20
25
 
21
26
 
22
- class AdapterBackendError(BackendError):
23
- """Error inside an adapter backend"""
27
+ class AdapterOpenError(AdapterError):
28
+ """Adapter failed to open"""
24
29
 
25
30
 
26
- class AdapterError(SyndesiError):
27
- """Error inside an adapter frontend"""
28
-
29
-
30
- def make_error_description(e: Exception) -> str:
31
- tb = e.__traceback__
32
- if tb is None:
33
- error_message = ""
34
- else:
35
- while True:
36
- if tb.tb_next is None:
37
- break
38
- file = Path(tb.tb_next.tb_frame.f_code.co_filename).resolve()
39
- if not file.is_relative_to(PACKAGE_PATH):
40
- break
41
- tb = tb.tb_next
42
-
43
- _type = type(e)
44
- extra_arguments = (str(e),)
45
- frame = tb.tb_frame
46
- line_no = tb.tb_lineno
47
- filename = frame.f_code.co_filename
48
- error_message = f"{_type} : {extra_arguments} {filename}:{line_no}"
49
-
50
- return error_message
31
+ class AdapterWriteError(AdapterError):
32
+ """Adapter failed to write"""
33
+
34
+
35
+ class AdapterDisconnected(AdapterError):
36
+ """Adapter disconnected"""
37
+
38
+
39
+ class WorkerThreadError(AdapterError):
40
+ """Adapters worker thread error"""
41
+
42
+
43
+ class AdapterReadError(AdapterError):
44
+ """Error while performing read operation"""
45
+
46
+
47
+ class ProtocolError(SyndesiError):
48
+ """Protocol error"""
49
+
50
+
51
+ class ProtocolWriteError(SyndesiError):
52
+ """Protocol error when writing"""
53
+
54
+
55
+ class ProtocolReadError(SyndesiError):
56
+ """Protocol error when reading"""
57
+
58
+
59
+ class AdapterTimeoutError(AdapterError):
60
+ """
61
+ Adapter timeout error
62
+ """
63
+
64
+ def __init__(self, timeout: NumberLike) -> None:
65
+ self.timeout = timeout
66
+ super().__init__(
67
+ f"No response received from target within {self.timeout} seconds"
68
+ )
@@ -1,17 +1,30 @@
1
- # File : log.py
1
+ # File : log_settings.py
2
2
  # Author : Sébastien Deriaz
3
3
  # License : GPL
4
- #
5
- # Log utilities
6
- # Set log level, destination, etc...
7
-
4
+ """
5
+ Log utilities
6
+ Set log level, destination, etc...
7
+ """
8
+ import logging
8
9
  from enum import Enum
9
10
 
10
11
 
11
12
  class LoggerAlias(Enum):
13
+ """
14
+ Name of the Syndesi loggers inside the logging module
15
+ """
16
+
12
17
  ADAPTER = "syndesi.adapter"
13
18
  PROTOCOL = "syndesi.protocol"
14
19
  CLI = "syndesi.cli"
15
- BACKEND = "syndesi.backend"
16
- ADAPTER_BACKEND = "syndesi.adapter_backend"
17
- BACKEND_LOGGER = "syndesi.backend_logger"
20
+ REMOTE = "syndesi.remote"
21
+ ADAPTER_WORKER = "syndesi.adapterworker"
22
+
23
+
24
+ LOGGING_COLORS = {
25
+ logging.DEBUG: "grey66",
26
+ logging.INFO: "green",
27
+ logging.WARNING: "yellow",
28
+ logging.ERROR: "red",
29
+ logging.CRITICAL: "bold purple",
30
+ }
@@ -1,15 +1,22 @@
1
1
  # File : logmanager.py
2
2
  # Author : Sébastien Deriaz
3
3
  # License : GPL
4
-
4
+ """
5
+ Log manager implementation
6
+ """
5
7
  import logging
6
8
  import threading
7
9
  from typing import TextIO
8
10
 
9
- from .backend_logger import BackendLogger
10
11
  from .log_settings import LoggerAlias
11
12
 
13
+
12
14
  class LogManager:
15
+ """
16
+ Log manager, responsible for logging configuration, backend logging and
17
+ printing to console and/or to a file
18
+ """
19
+
13
20
  _lock = threading.Lock()
14
21
 
15
22
  DEFAULT_FORMATTER = logging.Formatter(
@@ -23,13 +30,11 @@ class LogManager:
23
30
  self._loggers: list[str] = []
24
31
  self._level = self.DEFAULT_LOG_LEVEL
25
32
  self._stream_handler: logging.StreamHandler[TextIO] | None = None
26
- self._backend_logger: BackendLogger | None = None
27
-
28
- def enable_backend_logging(self) -> None:
29
- self._backend_logger = BackendLogger()
30
- self._backend_logger.start()
31
33
 
32
34
  def set_log_level(self, level: str | int) -> None:
35
+ """
36
+ Set log level
37
+ """
33
38
  if isinstance(level, str):
34
39
  if not hasattr(logging, level.upper()):
35
40
  raise ValueError(f"Invalid log level: {level}")
@@ -43,6 +48,9 @@ class LogManager:
43
48
  self.update_loggers()
44
49
 
45
50
  def set_console_log(self, enabled: bool) -> None:
51
+ """
52
+ Enable or disable console logging
53
+ """
46
54
  if enabled:
47
55
  self._stream_handler = logging.StreamHandler()
48
56
  self._stream_handler.setFormatter(self.DEFAULT_FORMATTER)
@@ -50,6 +58,9 @@ class LogManager:
50
58
  self._stream_handler = None
51
59
 
52
60
  def set_log_file(self, file: str | None) -> None:
61
+ """
62
+ Define a file for loggers output
63
+ """
53
64
  if file is not None:
54
65
  self._file_handler = logging.FileHandler(file)
55
66
  self._file_handler.setFormatter(self.DEFAULT_FORMATTER)
@@ -59,6 +70,9 @@ class LogManager:
59
70
  self._file_handler = None
60
71
 
61
72
  def set_logger_filter(self, loggers: list[str] | str) -> None:
73
+ """
74
+ Select loggers
75
+ """
62
76
  self._all_loggers = False
63
77
  self._loggers = []
64
78
  if isinstance(loggers, list):
@@ -72,6 +86,9 @@ class LogManager:
72
86
  raise ValueError("Invalid argument loggers")
73
87
 
74
88
  def update_loggers(self) -> None:
89
+ """
90
+ Update configuration of each logger
91
+ """
75
92
  # 1) Remove everything
76
93
  for alias in LoggerAlias:
77
94
  logger = logging.getLogger(alias.value)
@@ -86,12 +103,6 @@ class LogManager:
86
103
  logger.addHandler(self._stream_handler)
87
104
  logger.setLevel(self._level)
88
105
 
89
- def backend_logger_conn_description(self) -> str:
90
- if self._backend_logger is None:
91
- return ""
92
- else:
93
- return self._backend_logger.conn_description
94
-
95
106
 
96
107
  log_manager = LogManager()
97
108
 
syndesi/tools/types.py CHANGED
@@ -1,6 +1,9 @@
1
1
  # File : types.py
2
2
  # Author : Sébastien Deriaz
3
3
  # License : GPL
4
+ """
5
+ Type tools
6
+ """
4
7
 
5
8
  from typing import TYPE_CHECKING, Any, TypeGuard
6
9
 
@@ -16,7 +19,8 @@ if TYPE_CHECKING:
16
19
  else:
17
20
  NumberLike = int | float | np.number # runtime will resolve string
18
21
 
19
- def is_number(X: Any) -> TypeGuard[NumberLike]:
22
+
23
+ def is_number(x: Any) -> TypeGuard[NumberLike]:
20
24
  """
21
25
  Check if the given X is an instance of int or float
22
26
 
@@ -29,9 +33,8 @@ def is_number(X: Any) -> TypeGuard[NumberLike]:
29
33
  result : bool
30
34
  """
31
35
  if np is None:
32
- return isinstance(X, int | float)
33
- else:
34
- return isinstance(X, int | float | np.number)
36
+ return isinstance(x, int | float)
37
+ return isinstance(x, int | float | np.number)
35
38
 
36
39
 
37
40
  def assert_number(*args: Any) -> None:
@@ -57,7 +60,6 @@ def to_bytes(data: str | bytes) -> bytes:
57
60
  """
58
61
  if isinstance(data, bytes):
59
62
  return data
60
- elif isinstance(data, str):
63
+ if isinstance(data, str):
61
64
  return data.encode("utf-8")
62
- else:
63
- raise ValueError(f"Invalid data type : {type(data)}")
65
+ raise ValueError(f"Invalid data type : {type(data)}")
syndesi/version.py CHANGED
@@ -1,3 +1,7 @@
1
- __version__ = "0.4.2"
1
+ """
2
+ Syndesi version file
3
+ """
4
+
5
+ __version__ = "0.5.0"
2
6
  NAME = "Syndesi"
3
7
  AUTHOR = "Sébastien Deriaz"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syndesi
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: Syndesi
5
5
  Author-email: Sébastien Deriaz <sebastien.deriaz1@gmail.com>
6
6
  License: GPL
@@ -0,0 +1,41 @@
1
+ syndesi/__init__.py,sha256=Lapn-qSSzcSGPgGVX_TLBM-FJyBzr0JKd3EmgwaYBn8,624
2
+ syndesi/__main__.py,sha256=S9G9k0SHGJJ9qMdF_txtYryiPdEPTI10bgQ-M-rVITs,75
3
+ syndesi/component.py,sha256=zdky9tOtN-Z0qEcGWfJ1d-xRmbqQaOyXfvV7HgS-M2A,8402
4
+ syndesi/version.py,sha256=NdA_xw1pibpr0hHkrQoBM6UBvPRxxSywMz2CF2kMq7I,98
5
+ syndesi/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ syndesi/adapters/adapter.py,sha256=w1zZhg9PPxRUnC2mjh7iWKv9bAYGi7yhmG2BZs3tV1g,15282
7
+ syndesi/adapters/adapter_worker.py,sha256=vll3TWvZ1G4eTs4aJqQwxsFfD1LtIhXX2MRnMAYl4K0,28467
8
+ syndesi/adapters/auto.py,sha256=_hXCGM6TCe_cgLyQ_6CUDo8_lqXNB7nTsxkn25kCC5U,2355
9
+ syndesi/adapters/descriptors.py,sha256=GehtGriResi4IBE1fo2xPA8CK-q64p8acghORKY1I18,1021
10
+ syndesi/adapters/ip.py,sha256=Kd_q0-sONL8vFRbEz3Zvj17IhffEJ6QfLBe1-86SIV4,7849
11
+ syndesi/adapters/serialport.py,sha256=RHLqy11L2t-k6XvPRjRjh6KArcZqPIdukywiYwQTRNk,6105
12
+ syndesi/adapters/stop_conditions.py,sha256=5d1F3YQxGj69oDD9iKKbt2uYOZlSchQdiuLSCy5uME8,10150
13
+ syndesi/adapters/timeout.py,sha256=TZdPWBqAyW7Wes2tarbM1fiJL3Gw5xd5J2YRAtVITZw,3184
14
+ syndesi/adapters/visa.py,sha256=xeKRu4P4c_hhcBF327Raq59SvrD11aiFNI_Q1aFrgBk,8455
15
+ syndesi/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ syndesi/cli/console.py,sha256=pwEOukoRDq-AnJSMfmd8jyKjm_2DT8CoWU2OENWSnMI,8864
17
+ syndesi/cli/shell.py,sha256=0jNE7LT22RRru3BCHEobUSmLDNNeDhk-OGL5eUGkFNs,7969
18
+ syndesi/cli/shell_tools.py,sha256=wqa0d5yELV1my_NhcLw00OXmYP8vKlrlkPqjLF2dCNs,3335
19
+ syndesi/cli/terminal.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ syndesi/cli/terminal_apps.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ syndesi/cli/terminal_tools.py,sha256=HuhJebeF_SWywwMhw3G91poSphTDF_aaaiw_m8Z5HIM,301
22
+ syndesi/protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ syndesi/protocols/delimited.py,sha256=6MJDV1Schll9bFk9OHvID6GVg4Fj2s_NzmmfMnR-qqk,5549
24
+ syndesi/protocols/modbus.py,sha256=8VmjPVeEjgcwXHghdSw5n1MYxd3cVyXu_Wb_9eJR-9I,94938
25
+ syndesi/protocols/protocol.py,sha256=Pv92qL__weswyu60ZTMcjy17Rp-ToHChFJHfPmPcOhw,6490
26
+ syndesi/protocols/raw.py,sha256=_UrfDkXT3LpI2vQut8AhN6zorFD-fcnzctR8nYQEtT0,2022
27
+ syndesi/protocols/scpi.py,sha256=hZRA4sDd--xfQHHNA-3M4yTGe6GJtirmOgW8YoHraCc,2985
28
+ syndesi/remote/remote.py,sha256=7ykrmNjCGxTnwwIC2qzeXSne3C2fgpVRYXFB7AOXlt0,5759
29
+ syndesi/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ syndesi/scripts/syndesi.py,sha256=bEueSyCsWr_HVvPxfXffogVXLm-LetDmLQvESaZZS30,1512
31
+ syndesi/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ syndesi/tools/errors.py,sha256=_BZXlETGGkHS_IgPM7Z7-KJkIAQVtJ8MTdpGpWM6B-Q,1331
33
+ syndesi/tools/log_settings.py,sha256=0iy6mQPnAnuGvwsoZPBhCdA5fCMfgSpMhMbJe1sT9bY,604
34
+ syndesi/tools/logmanager.py,sha256=d-CUgPRK8kNED3vwUKF6wJdLSbeGAf3PJh9XBVqTdOs,4455
35
+ syndesi/tools/types.py,sha256=jSLpR-ymLnhCT2BqRNU_g_qhOGWUn5mZ4FobAhFx05k,1393
36
+ syndesi-0.5.0.dist-info/licenses/LICENSE,sha256=7oldAMqsditrYeX4dzMFHpFZ-6AkyGi3bha2zeaJB0A,34492
37
+ syndesi-0.5.0.dist-info/METADATA,sha256=W4Q_6ClHfYhZvPQ0anw66yfYLqmeCfJ7ZoexqOujXD8,2827
38
+ syndesi-0.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
39
+ syndesi-0.5.0.dist-info/entry_points.txt,sha256=1JbZYMX6PrakEg-6b_M_f58QJ1mGFJKJd7puoPQPyKM,112
40
+ syndesi-0.5.0.dist-info/top_level.txt,sha256=HrY36JU6hFYp_6qv-GuVBBtHYYemn8qhCrqpvXBd1Lg,8
41
+ syndesi-0.5.0.dist-info/RECORD,,
File without changes