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 +1 -1
- ephys_link/back_end/platform_handler.py +3 -3
- ephys_link/back_end/server.py +6 -4
- ephys_link/bindings/ump_4_bindings.py +0 -2
- ephys_link/util/common.py +2 -3
- ephys_link/util/console.py +75 -54
- {ephys_link-2.0.0b1.dist-info → ephys_link-2.0.0b2.dist-info}/METADATA +2 -1
- {ephys_link-2.0.0b1.dist-info → ephys_link-2.0.0b2.dist-info}/RECORD +11 -11
- {ephys_link-2.0.0b1.dist-info → ephys_link-2.0.0b2.dist-info}/WHEEL +0 -0
- {ephys_link-2.0.0b1.dist-info → ephys_link-2.0.0b2.dist-info}/entry_points.txt +0 -0
- {ephys_link-2.0.0b1.dist-info → ephys_link-2.0.0b2.dist-info}/licenses/LICENSE +0 -0
ephys_link/__about__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2.0.
|
|
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.
|
|
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)
|
ephys_link/back_end/server.py
CHANGED
|
@@ -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.
|
|
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(
|
|
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
|
-
|
|
51
|
-
|
|
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
|
ephys_link/util/console.py
CHANGED
|
@@ -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
|
|
9
|
+
from logging import DEBUG, ERROR, INFO, basicConfig, getLogger
|
|
10
10
|
|
|
11
|
-
from
|
|
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 =
|
|
23
|
+
self._last_message = (0, "", "")
|
|
24
|
+
self._repeat_counter = 0
|
|
29
25
|
|
|
30
|
-
#
|
|
31
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
"""Print an error message to the console.
|
|
35
|
+
# Install Rich traceback.
|
|
36
|
+
install()
|
|
36
37
|
|
|
37
|
-
|
|
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
|
-
|
|
46
|
+
self._repeatable_log(DEBUG, f"[b green]{label}", f"[green]{msg}")
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
74
|
-
|
|
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
|
-
|
|
88
|
-
def
|
|
89
|
-
"""
|
|
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
|
|
94
|
-
:type
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
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.
|
|
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=
|
|
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=
|
|
6
|
-
ephys_link/back_end/server.py,sha256=
|
|
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
|
|
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=
|
|
20
|
-
ephys_link/util/console.py,sha256=
|
|
21
|
-
ephys_link-2.0.
|
|
22
|
-
ephys_link-2.0.
|
|
23
|
-
ephys_link-2.0.
|
|
24
|
-
ephys_link-2.0.
|
|
25
|
-
ephys_link-2.0.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|