ephys-link 2.0.0__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.
@@ -1,127 +1,133 @@
1
- """Console class for printing messages to the console.
2
-
3
- Configure the console to print error and debug messages.
4
-
5
- Usage:
6
- Create a Console object and call the appropriate method to print messages.
7
- """
8
-
9
- from logging import DEBUG, ERROR, INFO, basicConfig, getLogger
10
- from typing import final
11
-
12
- from rich.logging import RichHandler
13
- from rich.traceback import install
14
-
15
-
16
- @final
17
- class Console:
18
- def __init__(self, *, enable_debug: bool) -> None:
19
- """Initialize console properties.
20
-
21
- Args:
22
- enable_debug: Enable debug mode.
23
- """
24
- # Repeat message fields.
25
- self._last_message = (0, "", "")
26
- self._repeat_counter = 0
27
-
28
- # Config logger.
29
- basicConfig(
30
- format="%(message)s",
31
- datefmt="[%I:%M:%S %p]",
32
- handlers=[RichHandler(rich_tracebacks=True, markup=True)],
33
- )
34
- self._log = getLogger("rich")
35
- self._log.setLevel(DEBUG if enable_debug else INFO)
36
-
37
- # Install Rich traceback.
38
- _ = install()
39
-
40
- def debug_print(self, label: str, msg: str) -> None:
41
- """Print a debug message to the console.
42
-
43
- Args:
44
- label: Label for the debug message.
45
- msg: Debug message to print.
46
- """
47
- self._repeatable_log(DEBUG, f"[b green]{label}", f"[green]{msg}")
48
-
49
- def info_print(self, label: str, msg: str) -> None:
50
- """Print info to console.
51
-
52
- Args:
53
- label: Label for the message.
54
- msg: Message to print.
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.
60
-
61
- Args:
62
- label: Label for the error message.
63
- msg: Error message to print.
64
- """
65
- self._repeatable_log(ERROR, f"[b red]{label}", f"[red]{msg}")
66
-
67
- def critical_print(self, msg: str) -> None:
68
- """Print a critical message to the console.
69
-
70
- Args:
71
- msg: Critical message to print.
72
- """
73
- self._log.critical(f"[b i red]{msg}")
74
-
75
- @staticmethod
76
- def pretty_exception(exception: Exception) -> str:
77
- """Pretty print an exception.
78
-
79
- Args:
80
- exception: Exception to pretty print.
81
-
82
- Returns:
83
- Pretty printed exception.
84
- """
85
- return f"{type(exception).__name__}: {exception}"
86
-
87
- def exception_error_print(self, label: str, exception: Exception) -> None:
88
- """Print an error message with exception details to the console.
89
-
90
- Args:
91
- label: Label for the error message.
92
- exception: Exception to print.
93
- """
94
- self._log.exception(f"[b magenta]{label}:[/] [magenta]{Console.pretty_exception(exception)}")
95
-
96
- # Helper methods.
97
- def _repeatable_log(self, log_type: int, label: str, message: str) -> None:
98
- """Add a row to the output table.
99
-
100
- Args:
101
- log_type: Type of log.
102
- label: Label for the message.
103
- message: Message.
104
- """
105
-
106
- # Compute if this is a repeated message.
107
- message_set = (log_type, label, message)
108
- if message_set == self._last_message:
109
- # Handle repeat.
110
- self._repeat_counter += 1
111
-
112
- # Add an ellipsis row for first repeat.
113
- if self._repeat_counter == 1:
114
- self._log.log(log_type, "...")
115
- else:
116
- # Handle novel message.
117
- if self._repeat_counter > 0:
118
- # Complete previous repeat.
119
- self._log.log(
120
- self._last_message[0],
121
- f"{self._last_message[1]}:[/] {self._last_message[2]}[/] x {self._repeat_counter}",
122
- )
123
- self._repeat_counter = 0
124
-
125
- # Log new message.
126
- self._log.log(log_type, f"{label}:[/] {message}")
127
- self._last_message = message_set
1
+ # ruff: noqa: T201
2
+ """Console class for printing messages to the console.
3
+
4
+ Configure the console to print error and debug messages.
5
+
6
+ Usage: Create a Console object and call the appropriate method to print messages.
7
+ """
8
+
9
+ from logging import DEBUG, ERROR, INFO, basicConfig, getLogger
10
+
11
+ from rich.logging import RichHandler
12
+ from rich.traceback import install
13
+
14
+
15
+ class Console:
16
+ def __init__(self, *, enable_debug: bool) -> None:
17
+ """Initialize console properties.
18
+
19
+ :param enable_debug: Enable debug mode.
20
+ :type enable_debug: bool
21
+ """
22
+ # Repeat message fields.
23
+ self._last_message = (0, "", "")
24
+ self._repeat_counter = 0
25
+
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")
34
+
35
+ # Install Rich traceback.
36
+ install()
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.
44
+ :type msg: str
45
+ """
46
+ self._repeatable_log(DEBUG, f"[b green]{label}", f"[green]{msg}")
47
+
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.
60
+
61
+ :param label: Label for the error message.
62
+ :type label: str
63
+ :param msg: Error message to print.
64
+ :type msg: str
65
+ """
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})
75
+
76
+ @staticmethod
77
+ def pretty_exception(exception: Exception) -> str:
78
+ """Pretty print an exception.
79
+
80
+ :param exception: Exception to pretty print.
81
+ :type exception: Exception
82
+ :return: Pretty printed exception.
83
+ :rtype: str
84
+ """
85
+ return f"{type(exception).__name__}: {exception}"
86
+
87
+ def exception_error_print(self, label: str, exception: Exception) -> None:
88
+ """Print an error message with exception details to the console.
89
+
90
+ :param label: Label for the error message.
91
+ :type label: str
92
+ :param exception: Exception to print.
93
+ :type exception: Exception
94
+ """
95
+ self._log.exception(
96
+ f"[b magenta]{label}:[/] [magenta]{Console.pretty_exception(exception)}", extra={"markup": True}
97
+ )
98
+
99
+ # Helper methods.
100
+ def _repeatable_log(self, log_type: int, label: str, message: str) -> None:
101
+ """Add a row to the output table.
102
+
103
+ :param log_type: Type of log.
104
+ :type log_type: int
105
+ :param label: Label for the message.
106
+ :type label: str
107
+ :param message: Message.
108
+ :type message: str
109
+ """
110
+
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.
115
+ self._repeat_counter += 1
116
+
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
@@ -0,0 +1,167 @@
1
+ Metadata-Version: 2.3
2
+ Name: ephys-link
3
+ Version: 2.0.0b2
4
+ Summary: A Python Socket.IO server that allows any Socket.IO-compliant application to communicate with manipulators used in electrophysiology experiments.
5
+ Project-URL: Documentation, https://virtualbrainlab.org/ephys_link/installation_and_use.html
6
+ Project-URL: Issues, https://github.com/VirtualBrainLab/ephys-link/issues
7
+ Project-URL: Source, https://github.com/VirtualBrainLab/ephys-link
8
+ Author-email: Kenneth Yang <kjy5@uw.edu>
9
+ Maintainer-email: Kenneth Yang <kjy5@uw.edu>
10
+ License-Expression: GPL-3.0-only
11
+ License-File: LICENSE
12
+ Keywords: electrophysiology,ephys,manipulator,neuroscience,neurotech,new-scale,sensapex,socket-io,virtualbrainlab
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Intended Audience :: Healthcare Industry
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
17
+ Classifier: Operating System :: Microsoft :: Windows
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: Implementation :: CPython
26
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
27
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
28
+ Requires-Python: <3.13,>=3.10
29
+ Requires-Dist: aiohttp==3.9.5
30
+ Requires-Dist: colorama==0.4.6
31
+ Requires-Dist: platformdirs==4.2.2
32
+ Requires-Dist: pyserial==3.5
33
+ Requires-Dist: python-socketio[asyncio-client]==5.11.3
34
+ Requires-Dist: pythonnet==3.0.3
35
+ Requires-Dist: requests==2.32.3
36
+ Requires-Dist: rich==13.7.1
37
+ Requires-Dist: sensapex==1.400.1
38
+ Requires-Dist: vbl-aquarium==0.0.19
39
+ Description-Content-Type: text/markdown
40
+
41
+ # Electrophysiology Manipulator Link
42
+
43
+ [![PyPI version](https://badge.fury.io/py/ephys-link.svg)](https://badge.fury.io/py/ephys-link)
44
+ [![CodeQL](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/codeql-analysis.yml)
45
+ [![Dependency Review](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/dependency-review.yml)
46
+ [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
47
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
48
+
49
+ <!-- [![Build](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/build.yml/badge.svg)](https://github.com/VirtualBrainLab/ephys-link/actions/workflows/build.yml) -->
50
+
51
+ <img width="100%" src="https://github.com/VirtualBrainLab/ephys-link/assets/82800265/0c7c60b1-0926-4697-a461-221554f82de1" alt="Manipulator and probe in pinpoint moving in sync">
52
+
53
+ The [Electrophysiology Manipulator Link](https://github.com/VirtualBrainLab/ephys-link)
54
+ (or Ephys Link for short) is a Python [Socket.IO](https://socket.io/docs/v4/#what-socketio-is) server that allows any
55
+ Socket.IO-compliant application (such
56
+ as [Pinpoint](https://github.com/VirtualBrainLab/Pinpoint))
57
+ to communicate with manipulators used in electrophysiology experiments.
58
+
59
+ **Supported Manipulators:**
60
+
61
+ | Manufacturer | Model |
62
+ |--------------|-------------------------------------------------------------------------|
63
+ | Sensapex | <ul> <li>uMp-4</li> <li>uMp-3</li> </ul> |
64
+ | New Scale | <ul> <li>Pathfinder MPM Control v2.8+</li> <li>M3-USB-3:1-EP</li> </ul> |
65
+
66
+ Ephys Link is an open and extensible platform. It is designed to easily support integration with other manipulators.
67
+
68
+ For more information regarding the server's implementation and how the code is organized, see
69
+ the [package's development documentation](https://virtualbrainlab.org/ephys_link/development.html).
70
+
71
+ For detailed descriptions of the server's API, see
72
+ the [API reference](https://virtualbrainlab.org/api_reference_ephys_link.html).
73
+
74
+ # Installation
75
+
76
+ ## Prerequisites
77
+
78
+ 1. An **x86 Windows PC is required** to run the server.
79
+ 2. For Sensapex devices, the controller unit must be connected via an ethernet
80
+ cable and powered. A USB-to-ethernet adapter is acceptable. For New Scale manipulators,
81
+ the controller unit must be connected via USB and be powered by a 6V power
82
+ supply.
83
+ 3. To use the emergency stop feature, ensure an Arduino with
84
+ the [StopSignal](https://github.com/VirtualBrainLab/StopSignal) sketch is
85
+ connected to the computer. Follow the instructions on that repo for how to
86
+ set up the Arduino.
87
+
88
+ **NOTE:** Ephys Link is an HTTP server without cross-origin support. The server
89
+ is currently designed to interface with local/desktop instances of Pinpoint. It
90
+ will not work with the web browser versions of Pinpoint at this time.
91
+
92
+ ## Launch from Pinpoint (Recommended)
93
+
94
+ Pinpoint comes bundled with the correct version of Ephys Link. If you are using Pinpoint on the same computer your
95
+ manipulators are connected to, you can launch the server from within Pinpoint. Follow the instructions in
96
+ the [Pinpoint documentation](https://virtualbrainlab.org/pinpoint/tutorials/tutorial_ephys_link.html#configure-and-launch-ephys-link).
97
+
98
+ ## Install as Standalone Executable
99
+
100
+ 1. Download the latest executable from
101
+ the [releases page](https://github.com/VirtualBrainLab/ephys-link/releases/latest).
102
+ 2. Double-click the executable file to launch the configuration window.
103
+ 1. Take note of the IP address and port. **Copy this information into Pinpoint to connect**.
104
+ 3. Select the desired configuration and click "Launch Server".
105
+
106
+ The configuration window will close and the server will launch. Your configurations will be saved for future use.
107
+
108
+ To connect to the server from Pinpoint, provide the IP address and port. For example, if the server is running on the
109
+ same computer that Pinpoint is, use
110
+
111
+ - Server: `localhost`
112
+ - Port: `8081`
113
+
114
+ If the server is running on a different (local) computer, use the IP address of that computer as shown in the startup
115
+ window instead of `localhost`.
116
+
117
+ ## Install as a Python package
118
+
119
+ ```bash
120
+ pip install ephys-link
121
+ ```
122
+
123
+ Import the modules you need and launch the server.
124
+
125
+ ```python
126
+ from ephys_link.server import Server
127
+
128
+ server = Server()
129
+ server.launch("sensapex", args.proxy_address, 8081)
130
+ ```
131
+
132
+ ## Install for Development
133
+
134
+ 1. Clone the repository.
135
+ 2. Install [Hatch](https://hatch.pypa.io/latest/install/)
136
+ 3. In a terminal, navigate to the repository's root directory and run
137
+
138
+ ```bash
139
+ hatch shell
140
+ ```
141
+
142
+ This will create a virtual environment, install Python 12 (if not found), and install the package in editable mode.
143
+
144
+ If you encounter any dependency issues (particularly with `aiohttp`), try installing the latest Microsoft Visual C++
145
+ (MSVC v143+ x86/64) and the Windows SDK (10/11)
146
+ via [Visual Studio Build Tools Installer](https://visualstudio.microsoft.com/visual-cpp-build-tools/).
147
+
148
+ # Documentation and More Information
149
+
150
+ Complete documentation including API usage and development installation can be
151
+ found on the [Virtual Brain Lab Documentation page][docs] for Ephys Link.
152
+
153
+ # Citing
154
+
155
+ If this project is used as part of a research project you should cite
156
+ the [Pinpoint repository][Pinpoint]. Please email
157
+ Dan ([dbirman@uw.edu](mailto:dbirman@uw.edu)) if you have questions.
158
+
159
+ Please reach out to Kenneth ([kjy5@uw.edu](mailto:kjy5@uw.edu)) for questions
160
+ about the Electrophysiology Manipulator Link server. Bugs may be reported
161
+ through the issues tab.
162
+
163
+ [Pinpoint]: https://github.com/VirtualBrainLab/Pinpoint
164
+
165
+ [StopSignal]: https://github.com/VirtualBrainLab/StopSignal
166
+
167
+ [docs]: https://virtualbrainlab.org/ephys_link/installation_and_use.html
@@ -0,0 +1,25 @@
1
+ ephys_link/__about__.py,sha256=hCxVb1QEtE7vuKzDSJMrBKv-IroPOVT1d4aqMkNa-5c,25
2
+ ephys_link/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ ephys_link/__main__.py,sha256=pu7QLmS_30qWpgzeibMVD5FsVhICiK0wi7QkzX6F0qU,1373
4
+ ephys_link/back_end/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ ephys_link/back_end/platform_handler.py,sha256=KKJd2qEV4eYsxaAviR9I2PyesdmILmJTjlk3mFGogUs,12954
6
+ ephys_link/back_end/server.py,sha256=TMg0jgTt5Dqw7T7rHvs4ZcswrSKgD2IHAJc1kEUUfsw,8020
7
+ ephys_link/bindings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ ephys_link/bindings/fake_bindings.py,sha256=_ZpXx4whztbO5jNGNqwoJFdqhIIbZ0VMx4mHkMge1r0,1726
9
+ ephys_link/bindings/ump_4_bindings.py,sha256=-qyDL8JAw7R1H_HZgPgyZDfiu3RDEaE0Uzhb8rNbXtg,4558
10
+ ephys_link/front_end/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ ephys_link/front_end/cli.py,sha256=KJBSWqdz4T5z0Zor1tJSHTJKZeMcHAJf5gXXu38wQPU,3105
12
+ ephys_link/front_end/gui.py,sha256=_gE6zFhFnzHPSyYd9MBvfK5xmDZHsUXcETDHzH66QzU,7518
13
+ ephys_link/resources/CP210xManufacturing.dll,sha256=aM9k_XABjkq0TOMiIw8HeteB40zqEkUDNO8wo91EdYI,810232
14
+ ephys_link/resources/NstMotorCtrl.dll,sha256=Xtpr3vBcxhcsOUGvgVEwYtGPvKEqDctIUGCK36GfU2Q,155136
15
+ ephys_link/resources/SiUSBXp.dll,sha256=187zlclZNNezCkU1o1CbICRAmKWJxbh8ahP6L6wo-_Y,469752
16
+ ephys_link/resources/libum.dll,sha256=YaD4dwiSNohx-XxHjx2eQWPOBEVvUIXARvx37e_yqNw,316316
17
+ ephys_link/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ ephys_link/util/base_bindings.py,sha256=FNqhB7kJf2n9g4wYHEBbQ2wEiZscR5sKCnIEZ6yujgE,4808
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,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.25.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any