ephys-link 2.0.0b1__py3-none-any.whl → 2.0.0b2__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.
ephys_link/__about__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.0.0b1"
1
+ __version__ = "2.0.0b2"
@@ -71,7 +71,7 @@ class PlatformHandler:
71
71
  return FakeBindings()
72
72
  case _:
73
73
  error_message = f'Platform type "{platform_type}" not recognized.'
74
- self._console.labeled_error_print("PLATFORM", error_message)
74
+ self._console.critical_print(error_message)
75
75
  raise ValueError(error_message)
76
76
 
77
77
  # Ephys Link metadata.
@@ -185,7 +185,7 @@ class PlatformHandler:
185
185
  # Disallow setting manipulator position while inside the brain.
186
186
  if request.manipulator_id in self._inside_brain:
187
187
  error_message = 'Can not move manipulator while inside the brain. Set the depth ("set_depth") instead.'
188
- self._console.error_print(error_message)
188
+ self._console.error_print("Set Position", error_message)
189
189
  return PositionalResponse(error=error_message)
190
190
 
191
191
  # Move to the new position.
@@ -209,7 +209,7 @@ class PlatformHandler:
209
209
  f" position on axis {list(Vector4.model_fields.keys())[index]}."
210
210
  f"Requested: {request.position}, got: {final_unified_position}."
211
211
  )
212
- self._console.error_print(error_message)
212
+ self._console.error_print("Set Position", error_message)
213
213
  return PositionalResponse(error=error_message)
214
214
  except Exception as e:
215
215
  self._console.exception_error_print("Set Position", e)
@@ -75,7 +75,7 @@ class Server:
75
75
  # Helper functions.
76
76
  def _malformed_request_response(self, request: str, data: tuple[tuple[Any], ...]) -> str:
77
77
  """Return a response for a malformed request."""
78
- self._console.labeled_error_print("MALFORMED REQUEST", f"{request}: {data}")
78
+ self._console.error_print("MALFORMED REQUEST", f"{request}: {data}")
79
79
  return dumps({"error": "Malformed request."})
80
80
 
81
81
  async def _run_if_data_available(
@@ -127,7 +127,9 @@ class Server:
127
127
  self._console.info_print("CONNECTION GRANTED", sid)
128
128
  return True
129
129
 
130
- self._console.error_print(f"CONNECTION REFUSED to {sid}. Client {self._client_sid} already connected.")
130
+ self._console.error_print(
131
+ "CONNECTION REFUSED", f"Cannot connect {sid} as {self._client_sid} is already connected."
132
+ )
131
133
  return False
132
134
 
133
135
  async def disconnect(self, sid: str) -> None:
@@ -142,7 +144,7 @@ class Server:
142
144
  if self._client_sid == sid:
143
145
  self._client_sid = ""
144
146
  else:
145
- self._console.error_print(f"Client {sid} disconnected without being connected.")
147
+ self._console.error_print("DISCONNECTION", f"Client {sid} disconnected without being connected.")
146
148
 
147
149
  # noinspection PyTypeChecker
148
150
  async def platform_event_handler(self, event: str, *args: tuple[Any]) -> str:
@@ -196,5 +198,5 @@ class Server:
196
198
  case "stop_all":
197
199
  return await self._platform_handler.stop_all()
198
200
  case _:
199
- self._console.error_print(f"Unknown event: {event}.")
201
+ self._console.error_print("EVENT", f"Unknown event: {event}.")
200
202
  return dumps({"error": "Unknown event."})
@@ -10,7 +10,6 @@ from vbl_aquarium.models.unity import Vector3, Vector4
10
10
 
11
11
  from ephys_link.util.base_bindings import BaseBindings
12
12
  from ephys_link.util.common import RESOURCES_PATH, array_to_vector4, mm_to_um, mmps_to_umps, um_to_mm, vector4_to_array
13
- from ephys_link.util.console import Console
14
13
 
15
14
 
16
15
  class Ump4Bindings(BaseBindings):
@@ -24,7 +23,6 @@ class Ump4Bindings(BaseBindings):
24
23
  self._ump = UMP.get_ump()
25
24
  if self._ump is None:
26
25
  error_message = "Unable to connect to uMp"
27
- Console.error_print(error_message)
28
26
  raise ValueError(error_message)
29
27
 
30
28
  async def get_manipulators(self) -> list[str]:
ephys_link/util/common.py CHANGED
@@ -9,7 +9,6 @@ from requests import get
9
9
  from vbl_aquarium.models.unity import Vector4
10
10
 
11
11
  from ephys_link.__about__ import __version__
12
- from ephys_link.util.console import Console
13
12
 
14
13
  # Ephys Link ASCII.
15
14
  ASCII = r"""
@@ -47,8 +46,8 @@ def check_for_updates() -> None:
47
46
  response = get("https://api.github.com/repos/VirtualBrainLab/ephys-link/tags", timeout=10)
48
47
  latest_version = response.json()[0]["name"]
49
48
  if parse(latest_version) > parse(__version__):
50
- Console.info_print("Update available", latest_version)
51
- Console.info_print("", "Download at: https://github.com/VirtualBrainLab/ephys-link/releases/latest")
49
+ print(f"Update available: {latest_version} !")
50
+ print("Download at: https://github.com/VirtualBrainLab/ephys-link/releases/latest")
52
51
 
53
52
 
54
53
  # Unit conversions
@@ -6,12 +6,10 @@ Configure the console to print error and debug messages.
6
6
  Usage: Create a Console object and call the appropriate method to print messages.
7
7
  """
8
8
 
9
- from traceback import print_exc
9
+ from logging import DEBUG, ERROR, INFO, basicConfig, getLogger
10
10
 
11
- from colorama import Back, Fore, Style, init
12
-
13
- # Constants.
14
- TAB_BLOCK = "\t\t"
11
+ from rich.logging import RichHandler
12
+ from rich.traceback import install
15
13
 
16
14
 
17
15
  class Console:
@@ -21,34 +19,59 @@ class Console:
21
19
  :param enable_debug: Enable debug mode.
22
20
  :type enable_debug: bool
23
21
  """
24
- self._enable_debug = enable_debug
25
-
26
22
  # Repeat message fields.
27
- self._last_message = ""
28
- self._repeat_counter = 1
23
+ self._last_message = (0, "", "")
24
+ self._repeat_counter = 0
29
25
 
30
- # Initialize colorama.
31
- init(autoreset=True)
26
+ # Config logger.
27
+ basicConfig(
28
+ level=DEBUG if enable_debug else INFO,
29
+ format="%(message)s",
30
+ datefmt="[%I:%M:%S %p]",
31
+ handlers=[RichHandler(rich_tracebacks=True)],
32
+ )
33
+ self._log = getLogger("rich")
32
34
 
33
- @staticmethod
34
- def error_print(msg: str) -> None:
35
- """Print an error message to the console.
35
+ # Install Rich traceback.
36
+ install()
36
37
 
37
- :param msg: Error message to print.
38
+ def debug_print(self, label: str, msg: str) -> None:
39
+ """Print a debug message to the console.
40
+
41
+ :param label: Label for the debug message.
42
+ :type label: str
43
+ :param msg: Debug message to print.
38
44
  :type msg: str
39
45
  """
40
- print(f"\n{Back.RED}{Style.BRIGHT} ERROR {Style.RESET_ALL}{TAB_BLOCK}{Fore.RED}{msg}")
46
+ self._repeatable_log(DEBUG, f"[b green]{label}", f"[green]{msg}")
41
47
 
42
- @staticmethod
43
- def labeled_error_print(label: str, msg: str) -> None:
44
- """Print an error message with a label to the console.
48
+ def info_print(self, label: str, msg: str) -> None:
49
+ """Print info to console.
50
+
51
+ :param label: Label for the message.
52
+ :type label: str
53
+ :param msg: Message to print.
54
+ :type msg: str
55
+ """
56
+ self._repeatable_log(INFO, f"[b blue]{label}", msg)
57
+
58
+ def error_print(self, label: str, msg: str) -> None:
59
+ """Print an error message to the console.
45
60
 
46
61
  :param label: Label for the error message.
47
62
  :type label: str
48
63
  :param msg: Error message to print.
49
64
  :type msg: str
50
65
  """
51
- print(f"\n{Back.RED}{Style.BRIGHT} ERROR {label} {Style.RESET_ALL}{TAB_BLOCK}{Fore.RED}{msg}")
66
+ self._repeatable_log(ERROR, f"[b red]{label}", f"[red]{msg}")
67
+
68
+ def critical_print(self, msg: str) -> None:
69
+ """Print a critical message to the console.
70
+
71
+ :param msg: Critical message to print.
72
+ :type msg: str
73
+ """
74
+ self._log.critical(f"[b i red]{msg}", extra={"markup": True})
52
75
 
53
76
  @staticmethod
54
77
  def pretty_exception(exception: Exception) -> str:
@@ -61,8 +84,7 @@ class Console:
61
84
  """
62
85
  return f"{type(exception).__name__}: {exception}"
63
86
 
64
- @staticmethod
65
- def exception_error_print(label: str, exception: Exception) -> None:
87
+ def exception_error_print(self, label: str, exception: Exception) -> None:
66
88
  """Print an error message with exception details to the console.
67
89
 
68
90
  :param label: Label for the error message.
@@ -70,43 +92,42 @@ class Console:
70
92
  :param exception: Exception to print.
71
93
  :type exception: Exception
72
94
  """
73
- Console.labeled_error_print(label, Console.pretty_exception(exception))
74
- print_exc()
75
-
76
- def debug_print(self, label: str, msg: str) -> None:
77
- """Print a debug message to the console.
78
-
79
- :param label: Label for the debug message.
80
- :type label: str
81
- :param msg: Debug message to print.
82
- :type msg: str
83
- """
84
- if self._enable_debug:
85
- self._repeat_print(f"{Back.BLUE}{Style.BRIGHT} DEBUG {label} {Style.RESET_ALL}{TAB_BLOCK}{Fore.BLUE}{msg}")
95
+ self._log.exception(
96
+ f"[b magenta]{label}:[/] [magenta]{Console.pretty_exception(exception)}", extra={"markup": True}
97
+ )
86
98
 
87
- @staticmethod
88
- def info_print(label: str, msg: str) -> None:
89
- """Print info to console.
99
+ # Helper methods.
100
+ def _repeatable_log(self, log_type: int, label: str, message: str) -> None:
101
+ """Add a row to the output table.
90
102
 
103
+ :param log_type: Type of log.
104
+ :type log_type: int
91
105
  :param label: Label for the message.
92
106
  :type label: str
93
- :param msg: Message to print.
94
- :type msg: str
107
+ :param message: Message.
108
+ :type message: str
95
109
  """
96
- print(f"\n{Back.GREEN}{Style.BRIGHT} {label} {Style.RESET_ALL}{TAB_BLOCK}{Fore.GREEN}{msg}")
97
-
98
- # Helper methods.
99
- def _repeat_print(self, msg: str) -> None:
100
- """Print a message to the console with repeat counter.
101
110
 
102
- :param msg: Message to print.
103
- :type msg: str
104
- """
105
- if msg == self._last_message:
111
+ # Compute if this is a repeated message.
112
+ message_set = (log_type, label, message)
113
+ if message_set == self._last_message:
114
+ # Handle repeat.
106
115
  self._repeat_counter += 1
107
- else:
108
- self._repeat_counter = 1
109
- self._last_message = msg
110
- print()
111
116
 
112
- print(f"\r{msg}{f" (x{self._repeat_counter})" if self._repeat_counter > 1 else ""}", end="")
117
+ # Add an ellipsis row for first repeat.
118
+ if self._repeat_counter == 1:
119
+ self._log.log(log_type, "...")
120
+ else:
121
+ # Handle novel message.
122
+ if self._repeat_counter > 0:
123
+ # Complete previous repeat.
124
+ self._log.log(
125
+ self._last_message[0],
126
+ f"{self._last_message[1]}:[/] {self._last_message[2]}[/] x {self._repeat_counter}",
127
+ extra={"markup": True},
128
+ )
129
+ self._repeat_counter = 0
130
+
131
+ # Log new message.
132
+ self._log.log(log_type, f"{label}:[/] {message}", extra={"markup": True})
133
+ self._last_message = message_set
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ephys-link
3
- Version: 2.0.0b1
3
+ Version: 2.0.0b2
4
4
  Summary: A Python Socket.IO server that allows any Socket.IO-compliant application to communicate with manipulators used in electrophysiology experiments.
5
5
  Project-URL: Documentation, https://virtualbrainlab.org/ephys_link/installation_and_use.html
6
6
  Project-URL: Issues, https://github.com/VirtualBrainLab/ephys-link/issues
@@ -33,6 +33,7 @@ Requires-Dist: pyserial==3.5
33
33
  Requires-Dist: python-socketio[asyncio-client]==5.11.3
34
34
  Requires-Dist: pythonnet==3.0.3
35
35
  Requires-Dist: requests==2.32.3
36
+ Requires-Dist: rich==13.7.1
36
37
  Requires-Dist: sensapex==1.400.1
37
38
  Requires-Dist: vbl-aquarium==0.0.19
38
39
  Description-Content-Type: text/markdown
@@ -1,12 +1,12 @@
1
- ephys_link/__about__.py,sha256=QUUi7DnZ0lfA8ZZUdMrPNiqXewCSfYtIqTvB6q6NnGQ,25
1
+ ephys_link/__about__.py,sha256=hCxVb1QEtE7vuKzDSJMrBKv-IroPOVT1d4aqMkNa-5c,25
2
2
  ephys_link/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  ephys_link/__main__.py,sha256=pu7QLmS_30qWpgzeibMVD5FsVhICiK0wi7QkzX6F0qU,1373
4
4
  ephys_link/back_end/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- ephys_link/back_end/platform_handler.py,sha256=5GfyLz8rX8VYypuT9JJokV12mnyUksriFOzRgp6H4W8,12939
6
- ephys_link/back_end/server.py,sha256=WP5NLJnIKtkVImdRgtZKxWEghd17FjsmpuczYpoFs3Q,7965
5
+ ephys_link/back_end/platform_handler.py,sha256=KKJd2qEV4eYsxaAviR9I2PyesdmILmJTjlk3mFGogUs,12954
6
+ ephys_link/back_end/server.py,sha256=TMg0jgTt5Dqw7T7rHvs4ZcswrSKgD2IHAJc1kEUUfsw,8020
7
7
  ephys_link/bindings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  ephys_link/bindings/fake_bindings.py,sha256=_ZpXx4whztbO5jNGNqwoJFdqhIIbZ0VMx4mHkMge1r0,1726
9
- ephys_link/bindings/ump_4_bindings.py,sha256=1V_bQzq7xVX1qGxbK11nxX7X3L3cfh9RTdhbVJwBKg8,4651
9
+ ephys_link/bindings/ump_4_bindings.py,sha256=-qyDL8JAw7R1H_HZgPgyZDfiu3RDEaE0Uzhb8rNbXtg,4558
10
10
  ephys_link/front_end/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  ephys_link/front_end/cli.py,sha256=KJBSWqdz4T5z0Zor1tJSHTJKZeMcHAJf5gXXu38wQPU,3105
12
12
  ephys_link/front_end/gui.py,sha256=_gE6zFhFnzHPSyYd9MBvfK5xmDZHsUXcETDHzH66QzU,7518
@@ -16,10 +16,10 @@ ephys_link/resources/SiUSBXp.dll,sha256=187zlclZNNezCkU1o1CbICRAmKWJxbh8ahP6L6wo
16
16
  ephys_link/resources/libum.dll,sha256=YaD4dwiSNohx-XxHjx2eQWPOBEVvUIXARvx37e_yqNw,316316
17
17
  ephys_link/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  ephys_link/util/base_bindings.py,sha256=FNqhB7kJf2n9g4wYHEBbQ2wEiZscR5sKCnIEZ6yujgE,4808
19
- ephys_link/util/common.py,sha256=IgmTpXRU2z7jfYV2zB4RGgjV34IaYa2s3TYpzKZkpao,3519
20
- ephys_link/util/console.py,sha256=kD4LLehdA1xLiGwdvjt5KxImDSyDkcoC2CQVOxTv8T4,3560
21
- ephys_link-2.0.0b1.dist-info/METADATA,sha256=j_XqMK_IK955IOE0ikj_JhqschZGCOKpgMiWdGzTrQQ,7975
22
- ephys_link-2.0.0b1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
23
- ephys_link-2.0.0b1.dist-info/entry_points.txt,sha256=o8wV3AdnJ9o47vg9ymKxPNVq9pMdPq8UZHE_iyAJx-k,124
24
- ephys_link-2.0.0b1.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
25
- ephys_link-2.0.0b1.dist-info/RECORD,,
19
+ ephys_link/util/common.py,sha256=FCfqX5DP_hyYy4MycwxhjZ9AVq27DpENIggGVC8LHHg,3449
20
+ ephys_link/util/console.py,sha256=RTlGtIpruw2ommshICinOyxdTEAiovXu9bUJNeGc64I,4444
21
+ ephys_link-2.0.0b2.dist-info/METADATA,sha256=WdN_6MVw6XiGqUx4WKDeYSLA61jDCdxJ1mKG319ol5g,8003
22
+ ephys_link-2.0.0b2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
23
+ ephys_link-2.0.0b2.dist-info/entry_points.txt,sha256=o8wV3AdnJ9o47vg9ymKxPNVq9pMdPq8UZHE_iyAJx-k,124
24
+ ephys_link-2.0.0b2.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
25
+ ephys_link-2.0.0b2.dist-info/RECORD,,