ephys-link 1.3.0b2__tar.gz → 1.3.3__tar.gz
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-1.3.0b2 → ephys_link-1.3.3}/PKG-INFO +12 -11
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/README.md +6 -4
- ephys_link-1.3.3/ephys_link.spec +70 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/pyproject.toml +10 -16
- ephys_link-1.3.3/scripts/proxy_dev.py +24 -0
- ephys_link-1.3.3/src/ephys_link/__about__.py +1 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/__main__.py +17 -2
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/gui.py +60 -6
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platform_handler.py +3 -3
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platform_manipulator.py +1 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platforms/sensapex_handler.py +1 -1
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platforms/sensapex_manipulator.py +7 -1
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platforms/ump3_handler.py +14 -14
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platforms/ump3_manipulator.py +3 -1
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/server.py +147 -75
- ephys_link-1.3.0b2/ephys_link.spec +0 -39
- ephys_link-1.3.0b2/src/ephys_link/__about__.py +0 -1
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/.gitignore +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/LICENSE +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/assets/icon.ico +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/scripts/__init__.py +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/scripts/move_tester.py +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/__init__.py +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/common.py +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/emergency_stop.py +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platforms/__init__.py +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platforms/new_scale_handler.py +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platforms/new_scale_manipulator.py +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platforms/new_scale_pathfinder_handler.py +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/resources/CP210xManufacturing.dll +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/resources/NstMotorCtrl.dll +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/resources/SiUSBXp.dll +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/resources/libum.dll +0 -0
- {ephys_link-1.3.0b2 → ephys_link-1.3.3}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: ephys-link
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.3
|
|
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
|
|
@@ -25,15 +25,14 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
25
25
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
26
26
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
27
27
|
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
28
|
-
Requires-Python: <3.13,>=3.
|
|
29
|
-
Requires-Dist: aiohttp==3.9.
|
|
30
|
-
Requires-Dist: platformdirs==4.2.
|
|
28
|
+
Requires-Python: <3.13,>=3.10
|
|
29
|
+
Requires-Dist: aiohttp==3.9.5
|
|
30
|
+
Requires-Dist: platformdirs==4.2.2
|
|
31
31
|
Requires-Dist: pyserial==3.5
|
|
32
|
-
Requires-Dist: python-socketio==5.11.2
|
|
32
|
+
Requires-Dist: python-socketio[asyncio-client]==5.11.2
|
|
33
33
|
Requires-Dist: pythonnet==3.0.3
|
|
34
|
-
Requires-Dist: requests==2.31.0
|
|
35
34
|
Requires-Dist: sensapex==1.400.0
|
|
36
|
-
Requires-Dist: vbl-aquarium==0.0.
|
|
35
|
+
Requires-Dist: vbl-aquarium==0.0.15
|
|
37
36
|
Description-Content-Type: text/markdown
|
|
38
37
|
|
|
39
38
|
# Electrophysiology Manipulator Link
|
|
@@ -124,16 +123,14 @@ Import the modules you need and launch the server.
|
|
|
124
123
|
from ephys_link.server import Server
|
|
125
124
|
|
|
126
125
|
server = Server()
|
|
127
|
-
server.launch("sensapex", 8081)
|
|
126
|
+
server.launch("sensapex", args.proxy_address, 8081)
|
|
128
127
|
```
|
|
129
128
|
|
|
130
129
|
## Install for Development
|
|
131
130
|
|
|
132
131
|
1. Clone the repository.
|
|
133
132
|
2. Install [Hatch](https://hatch.pypa.io/latest/install/)
|
|
134
|
-
3.
|
|
135
|
-
via [Visual Studio Build Tools Installer](https://visualstudio.microsoft.com/visual-cpp-build-tools/).
|
|
136
|
-
4. In a terminal, navigate to the repository's root directory and run
|
|
133
|
+
3. In a terminal, navigate to the repository's root directory and run
|
|
137
134
|
|
|
138
135
|
```bash
|
|
139
136
|
hatch shell
|
|
@@ -141,6 +138,10 @@ server.launch("sensapex", 8081)
|
|
|
141
138
|
|
|
142
139
|
This will create a virtual environment, install Python 12 (if not found), and install the package in editable mode.
|
|
143
140
|
|
|
141
|
+
If you encounter any dependency issues (particularly with `aiohttp`), try installing the latest Microsoft Visual C++
|
|
142
|
+
(MSVC v143+ x86/64) and the Windows SDK (10/11)
|
|
143
|
+
via [Visual Studio Build Tools Installer](https://visualstudio.microsoft.com/visual-cpp-build-tools/).
|
|
144
|
+
|
|
144
145
|
# Documentation and More Information
|
|
145
146
|
|
|
146
147
|
Complete documentation including API usage and development installation can be
|
|
@@ -86,16 +86,14 @@ Import the modules you need and launch the server.
|
|
|
86
86
|
from ephys_link.server import Server
|
|
87
87
|
|
|
88
88
|
server = Server()
|
|
89
|
-
server.launch("sensapex", 8081)
|
|
89
|
+
server.launch("sensapex", args.proxy_address, 8081)
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
## Install for Development
|
|
93
93
|
|
|
94
94
|
1. Clone the repository.
|
|
95
95
|
2. Install [Hatch](https://hatch.pypa.io/latest/install/)
|
|
96
|
-
3.
|
|
97
|
-
via [Visual Studio Build Tools Installer](https://visualstudio.microsoft.com/visual-cpp-build-tools/).
|
|
98
|
-
4. In a terminal, navigate to the repository's root directory and run
|
|
96
|
+
3. In a terminal, navigate to the repository's root directory and run
|
|
99
97
|
|
|
100
98
|
```bash
|
|
101
99
|
hatch shell
|
|
@@ -103,6 +101,10 @@ server.launch("sensapex", 8081)
|
|
|
103
101
|
|
|
104
102
|
This will create a virtual environment, install Python 12 (if not found), and install the package in editable mode.
|
|
105
103
|
|
|
104
|
+
If you encounter any dependency issues (particularly with `aiohttp`), try installing the latest Microsoft Visual C++
|
|
105
|
+
(MSVC v143+ x86/64) and the Windows SDK (10/11)
|
|
106
|
+
via [Visual Studio Build Tools Installer](https://visualstudio.microsoft.com/visual-cpp-build-tools/).
|
|
107
|
+
|
|
106
108
|
# Documentation and More Information
|
|
107
109
|
|
|
108
110
|
Complete documentation including API usage and development installation can be
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# -*- mode: python ; coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from ephys_link.__about__ import __version__ as version
|
|
4
|
+
|
|
5
|
+
from argparse import ArgumentParser
|
|
6
|
+
|
|
7
|
+
parser = ArgumentParser()
|
|
8
|
+
parser.add_argument("-d", "--dir", action="store_true", help="Outputs a directory")
|
|
9
|
+
options = parser.parse_args()
|
|
10
|
+
|
|
11
|
+
FILE_NAME = f"EphysLink-v{version}"
|
|
12
|
+
|
|
13
|
+
a = Analysis(
|
|
14
|
+
['src\\ephys_link\\__main__.py'],
|
|
15
|
+
pathex=[],
|
|
16
|
+
binaries=[('src\\ephys_link\\resources', 'ephys_link\\resources')],
|
|
17
|
+
datas=[],
|
|
18
|
+
hiddenimports=['engineio.async_drivers.aiohttp'],
|
|
19
|
+
hookspath=[],
|
|
20
|
+
hooksconfig={},
|
|
21
|
+
runtime_hooks=[],
|
|
22
|
+
excludes=[],
|
|
23
|
+
noarchive=False,
|
|
24
|
+
optimize=1,
|
|
25
|
+
)
|
|
26
|
+
pyz = PYZ(a.pure)
|
|
27
|
+
|
|
28
|
+
if options.dir:
|
|
29
|
+
exe = EXE(
|
|
30
|
+
pyz,
|
|
31
|
+
a.scripts,
|
|
32
|
+
[],
|
|
33
|
+
exlude_binaries=True,
|
|
34
|
+
name=FILE_NAME,
|
|
35
|
+
debug=False,
|
|
36
|
+
bootloader_ignore_signals=False,
|
|
37
|
+
strip=False,
|
|
38
|
+
upx=True,
|
|
39
|
+
upx_exclude=[],
|
|
40
|
+
console=True,
|
|
41
|
+
disable_windowed_traceback=False,
|
|
42
|
+
argv_emulation=False,
|
|
43
|
+
target_arch=None,
|
|
44
|
+
codesign_identity=None,
|
|
45
|
+
entitlements_file=None,
|
|
46
|
+
icon='assets\\icon.ico',
|
|
47
|
+
)
|
|
48
|
+
coll = COLLECT(exe, a.binaries, a.datas, strip=False, upx=True, upx_exclude=[], name=FILE_NAME)
|
|
49
|
+
else:
|
|
50
|
+
exe = EXE(
|
|
51
|
+
pyz,
|
|
52
|
+
a.scripts,
|
|
53
|
+
a.binaries,
|
|
54
|
+
a.datas,
|
|
55
|
+
[],
|
|
56
|
+
name=FILE_NAME,
|
|
57
|
+
debug=False,
|
|
58
|
+
bootloader_ignore_signals=False,
|
|
59
|
+
strip=False,
|
|
60
|
+
upx=True,
|
|
61
|
+
upx_exclude=[],
|
|
62
|
+
runtime_tmpdir=None,
|
|
63
|
+
console=True,
|
|
64
|
+
disable_windowed_traceback=False,
|
|
65
|
+
argv_emulation=False,
|
|
66
|
+
target_arch=None,
|
|
67
|
+
codesign_identity=None,
|
|
68
|
+
entitlements_file=None,
|
|
69
|
+
icon='assets\\icon.ico',
|
|
70
|
+
)
|
|
@@ -7,7 +7,7 @@ name = "ephys-link"
|
|
|
7
7
|
dynamic = ["version"]
|
|
8
8
|
description = "A Python Socket.IO server that allows any Socket.IO-compliant application to communicate with manipulators used in electrophysiology experiments."
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.10, <3.13"
|
|
11
11
|
license = "GPL-3.0-only"
|
|
12
12
|
keywords = ["socket-io", "manipulator", "electrophysiology", "ephys", "sensapex", "neuroscience", "neurotech", "virtualbrainlab", "new-scale"]
|
|
13
13
|
authors = [{ name = "Kenneth Yang", email = "kjy5@uw.edu" }]
|
|
@@ -30,14 +30,13 @@ classifiers = [
|
|
|
30
30
|
"Topic :: Scientific/Engineering :: Medical Science Apps.",
|
|
31
31
|
]
|
|
32
32
|
dependencies = [
|
|
33
|
-
"aiohttp==3.9.
|
|
34
|
-
"platformdirs==4.2.
|
|
33
|
+
"aiohttp==3.9.5",
|
|
34
|
+
"platformdirs==4.2.2",
|
|
35
35
|
"pyserial==3.5",
|
|
36
|
-
"python-socketio==5.11.2",
|
|
36
|
+
"python-socketio[asyncio_client]==5.11.2",
|
|
37
37
|
"pythonnet==3.0.3",
|
|
38
|
-
"requests==2.31.0",
|
|
39
38
|
"sensapex==1.400.0",
|
|
40
|
-
"vbl-aquarium==0.0.
|
|
39
|
+
"vbl-aquarium==0.0.15"
|
|
41
40
|
]
|
|
42
41
|
|
|
43
42
|
[project.urls]
|
|
@@ -60,8 +59,8 @@ exclude = ["/.github", "/.idea"]
|
|
|
60
59
|
python = "3.12"
|
|
61
60
|
dependencies = [
|
|
62
61
|
"coverage[toml]>=6.5",
|
|
62
|
+
"mypy>=1.0.0",
|
|
63
63
|
"pytest",
|
|
64
|
-
"python-socketio[client]==5.11.2",
|
|
65
64
|
]
|
|
66
65
|
[tool.hatch.envs.default.scripts]
|
|
67
66
|
test = "pytest {args:tests}"
|
|
@@ -74,24 +73,19 @@ cov = [
|
|
|
74
73
|
"test-cov",
|
|
75
74
|
"cov-report",
|
|
76
75
|
]
|
|
76
|
+
types = "mypy --strict --install-types --non-interactive {args:src/ephys_link tests}"
|
|
77
77
|
|
|
78
78
|
#[[tool.hatch.envs.all.matrix]]
|
|
79
79
|
#python = ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
|
80
80
|
|
|
81
|
-
[tool.hatch.envs.types]
|
|
82
|
-
dependencies = [
|
|
83
|
-
"mypy>=1.0.0",
|
|
84
|
-
]
|
|
85
|
-
[tool.hatch.envs.types.scripts]
|
|
86
|
-
check = "mypy --install-types --non-interactive {args:src/ephys_link tests}"
|
|
87
|
-
|
|
88
81
|
[tool.hatch.envs.exe]
|
|
89
82
|
python = "3.12"
|
|
90
83
|
dependencies = [
|
|
91
|
-
"pyinstaller
|
|
84
|
+
"pyinstaller",
|
|
92
85
|
]
|
|
93
86
|
[tool.hatch.envs.exe.scripts]
|
|
94
|
-
build = "pyinstaller.exe ephys_link.spec -y"
|
|
87
|
+
build = "pyinstaller.exe ephys_link.spec -y -- -d && pyinstaller.exe ephys_link.spec -y"
|
|
88
|
+
build_onefile = "pyinstaller.exe ephys_link.spec -y"
|
|
95
89
|
build_clean = "pyinstaller.exe ephys_link.spec -y --clean"
|
|
96
90
|
|
|
97
91
|
[tool.coverage.run]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from asyncio import run
|
|
4
|
+
|
|
5
|
+
from socketio import AsyncClient
|
|
6
|
+
|
|
7
|
+
pinpoint_id = "4158ebf3"
|
|
8
|
+
is_requester = True
|
|
9
|
+
|
|
10
|
+
sio = AsyncClient()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async def main():
|
|
14
|
+
await sio.connect("http://localhost:3000")
|
|
15
|
+
# await sio.emit("get_manipulators", lambda m: print(m))
|
|
16
|
+
await sio.wait()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@sio.event
|
|
20
|
+
async def get_pinpoint_id() -> tuple[str, bool]:
|
|
21
|
+
return pinpoint_id, is_requester
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
run(main())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.3.3"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from argparse import ArgumentParser
|
|
2
|
+
from asyncio import run
|
|
2
3
|
from sys import argv
|
|
3
4
|
|
|
4
5
|
from ephys_link import common as com
|
|
@@ -26,13 +27,22 @@ parser.add_argument(
|
|
|
26
27
|
help='Manipulator type (i.e. "sensapex", "new_scale", or "new_scale_pathfinder"). Default: "sensapex".',
|
|
27
28
|
)
|
|
28
29
|
parser.add_argument("-d", "--debug", dest="debug", action="store_true", help="Enable debug mode.")
|
|
30
|
+
parser.add_argument("-x", "--use-proxy", dest="use_proxy", action="store_true", help="Enable proxy mode.")
|
|
31
|
+
parser.add_argument(
|
|
32
|
+
"-a",
|
|
33
|
+
"--proxy-address",
|
|
34
|
+
type=str,
|
|
35
|
+
default="proxy2.virtualbrainlab.org",
|
|
36
|
+
dest="proxy_address",
|
|
37
|
+
help="Proxy IP address.",
|
|
38
|
+
)
|
|
29
39
|
parser.add_argument(
|
|
30
40
|
"-p",
|
|
31
41
|
"--port",
|
|
32
42
|
type=int,
|
|
33
43
|
default=8081,
|
|
34
44
|
dest="port",
|
|
35
|
-
help="
|
|
45
|
+
help="TCP/IP port to use. Default: 8081 (avoids conflict with other HTTP servers).",
|
|
36
46
|
)
|
|
37
47
|
parser.add_argument(
|
|
38
48
|
"--pathfinder_port",
|
|
@@ -83,7 +93,12 @@ def main() -> None:
|
|
|
83
93
|
e_stop.watch()
|
|
84
94
|
|
|
85
95
|
# Launch with parsed arguments on main thread.
|
|
86
|
-
|
|
96
|
+
if args.use_proxy:
|
|
97
|
+
run(
|
|
98
|
+
server.launch_for_proxy(args.proxy_address, args.port, args.type, args.pathfinder_port, args.ignore_updates)
|
|
99
|
+
)
|
|
100
|
+
else:
|
|
101
|
+
server.launch(args.type, args.port, args.pathfinder_port, args.ignore_updates)
|
|
87
102
|
|
|
88
103
|
|
|
89
104
|
if __name__ == "__main__":
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from asyncio import run
|
|
1
2
|
from json import dumps, load
|
|
2
3
|
from os import makedirs
|
|
3
4
|
from os.path import exists
|
|
@@ -24,15 +25,27 @@ class GUI:
|
|
|
24
25
|
self._root = Tk()
|
|
25
26
|
|
|
26
27
|
# Create default settings dictionary
|
|
27
|
-
settings = {
|
|
28
|
+
settings = {
|
|
29
|
+
"ignore_updates": False,
|
|
30
|
+
"type": "sensapex",
|
|
31
|
+
"debug": False,
|
|
32
|
+
"proxy": False,
|
|
33
|
+
"proxy_address": "proxy2.virtualbrainlab.org",
|
|
34
|
+
"port": 8081,
|
|
35
|
+
"pathfinder_port": 8080,
|
|
36
|
+
"serial": "no-e-stop",
|
|
37
|
+
}
|
|
28
38
|
|
|
29
39
|
# Read settings.
|
|
30
40
|
if exists(f"{SETTINGS_DIR}\\{SETTINGS_FILENAME}"):
|
|
31
41
|
with open(f"{SETTINGS_DIR}\\{SETTINGS_FILENAME}") as settings_file:
|
|
32
42
|
settings = load(settings_file)
|
|
33
43
|
|
|
44
|
+
self._ignore_updates = BooleanVar(value=settings["ignore_updates"])
|
|
34
45
|
self._type = StringVar(value=settings["type"])
|
|
35
46
|
self._debug = BooleanVar(value=settings["debug"])
|
|
47
|
+
self._proxy = BooleanVar(value=settings["proxy"])
|
|
48
|
+
self._proxy_address = StringVar(value=settings["proxy_address"])
|
|
36
49
|
self._port = IntVar(value=settings["port"])
|
|
37
50
|
self._pathfinder_port = IntVar(value=settings["pathfinder_port"])
|
|
38
51
|
self._serial = StringVar(value=settings["serial"])
|
|
@@ -61,15 +74,41 @@ class GUI:
|
|
|
61
74
|
server_serving_settings = ttk.LabelFrame(mainframe, text="Serving Settings", padding=3)
|
|
62
75
|
server_serving_settings.grid(column=0, row=0, sticky="news")
|
|
63
76
|
|
|
64
|
-
# IP.
|
|
65
|
-
ttk.Label(server_serving_settings, text="IP:", anchor=E, justify=RIGHT).grid(column=0, row=0, sticky="we")
|
|
77
|
+
# Local IP.
|
|
78
|
+
ttk.Label(server_serving_settings, text="Local IP:", anchor=E, justify=RIGHT).grid(column=0, row=0, sticky="we")
|
|
66
79
|
ttk.Label(server_serving_settings, text=gethostbyname(gethostname())).grid(column=1, row=0, sticky="we")
|
|
67
80
|
|
|
81
|
+
# Proxy.
|
|
82
|
+
ttk.Label(server_serving_settings, text="Use Proxy:", anchor=E, justify=RIGHT).grid(
|
|
83
|
+
column=0, row=1, sticky="we"
|
|
84
|
+
)
|
|
85
|
+
ttk.Checkbutton(
|
|
86
|
+
server_serving_settings,
|
|
87
|
+
variable=self._proxy,
|
|
88
|
+
).grid(column=1, row=1, sticky="we")
|
|
89
|
+
|
|
90
|
+
# Proxy address.
|
|
91
|
+
ttk.Label(server_serving_settings, text="Proxy Address:", anchor=E, justify=RIGHT).grid(
|
|
92
|
+
column=0, row=2, sticky="we"
|
|
93
|
+
)
|
|
94
|
+
ttk.Entry(server_serving_settings, textvariable=self._proxy_address, justify=CENTER).grid(
|
|
95
|
+
column=1, row=2, sticky="we"
|
|
96
|
+
)
|
|
97
|
+
|
|
68
98
|
# Port.
|
|
69
|
-
ttk.Label(server_serving_settings, text="Port:", anchor=E, justify=RIGHT).grid(column=0, row=
|
|
99
|
+
ttk.Label(server_serving_settings, text="Port:", anchor=E, justify=RIGHT).grid(column=0, row=3, sticky="we")
|
|
70
100
|
ttk.Entry(server_serving_settings, textvariable=self._port, width=5, justify=CENTER).grid(
|
|
71
|
-
column=1, row=
|
|
101
|
+
column=1, row=3, sticky="we"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Ignore updates.
|
|
105
|
+
ttk.Label(server_serving_settings, text="Ignore Updates:", anchor=E, justify=RIGHT).grid(
|
|
106
|
+
column=0, row=4, sticky="we"
|
|
72
107
|
)
|
|
108
|
+
ttk.Checkbutton(
|
|
109
|
+
server_serving_settings,
|
|
110
|
+
variable=self._ignore_updates,
|
|
111
|
+
).grid(column=1, row=4, sticky="we")
|
|
73
112
|
|
|
74
113
|
# ---
|
|
75
114
|
|
|
@@ -141,8 +180,11 @@ class GUI:
|
|
|
141
180
|
|
|
142
181
|
# Save settings.
|
|
143
182
|
settings = {
|
|
183
|
+
"ignore_updates": self._ignore_updates.get(),
|
|
144
184
|
"type": self._type.get(),
|
|
145
185
|
"debug": self._debug.get(),
|
|
186
|
+
"proxy": self._proxy.get(),
|
|
187
|
+
"proxy_address": self._proxy_address.get(),
|
|
146
188
|
"port": self._port.get(),
|
|
147
189
|
"pathfinder_port": self._pathfinder_port.get(),
|
|
148
190
|
"serial": self._serial.get(),
|
|
@@ -160,4 +202,16 @@ class GUI:
|
|
|
160
202
|
e_stop = EmergencyStop(server, self._serial.get())
|
|
161
203
|
e_stop.watch()
|
|
162
204
|
|
|
163
|
-
|
|
205
|
+
# Launch with parsed arguments on main thread.
|
|
206
|
+
if self._proxy.get():
|
|
207
|
+
run(
|
|
208
|
+
server.launch_for_proxy(
|
|
209
|
+
self._proxy_address.get(),
|
|
210
|
+
self._port.get(),
|
|
211
|
+
self._type.get(),
|
|
212
|
+
self._pathfinder_port.get(),
|
|
213
|
+
self._ignore_updates.get(),
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
else:
|
|
217
|
+
server.launch(self._type.get(), self._port.get(), self._pathfinder_port.get(), self._ignore_updates.get())
|
|
@@ -34,7 +34,7 @@ from vbl_aquarium.models.unity import Vector4
|
|
|
34
34
|
from ephys_link import common as com
|
|
35
35
|
|
|
36
36
|
if TYPE_CHECKING:
|
|
37
|
-
import
|
|
37
|
+
from socketio import AsyncClient, AsyncServer
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
class PlatformHandler(ABC):
|
|
@@ -309,7 +309,7 @@ class PlatformHandler(ABC):
|
|
|
309
309
|
print(f"{e}\n")
|
|
310
310
|
return BooleanStateResponse(error="Error setting inside brain")
|
|
311
311
|
|
|
312
|
-
async def calibrate(self, manipulator_id: str, sio:
|
|
312
|
+
async def calibrate(self, manipulator_id: str, sio: AsyncClient | AsyncServer) -> str:
|
|
313
313
|
"""Calibrate manipulator
|
|
314
314
|
|
|
315
315
|
:param manipulator_id: ID of manipulator to calibrate
|
|
@@ -423,7 +423,7 @@ class PlatformHandler(ABC):
|
|
|
423
423
|
raise NotImplementedError
|
|
424
424
|
|
|
425
425
|
@abstractmethod
|
|
426
|
-
async def _calibrate(self, manipulator_id: str, sio:
|
|
426
|
+
async def _calibrate(self, manipulator_id: str, sio: AsyncClient | AsyncServer) -> str:
|
|
427
427
|
"""Calibrate manipulator
|
|
428
428
|
|
|
429
429
|
:param manipulator_id: ID of manipulator to calibrate
|
|
@@ -95,7 +95,7 @@ class SensapexHandler(PlatformHandler):
|
|
|
95
95
|
cur_pos = self.manipulators[manipulator_id].get_pos()["position"]
|
|
96
96
|
|
|
97
97
|
# Check difference between current and target position
|
|
98
|
-
for prev, cur in zip([10000, 10000, 10000, 10000], cur_pos):
|
|
98
|
+
for prev, cur in zip([10000, 10000, 10000, 10000], cur_pos, strict=False):
|
|
99
99
|
if abs(prev - cur) > 1:
|
|
100
100
|
still_working = True
|
|
101
101
|
break
|
|
@@ -59,7 +59,13 @@ class SensapexManipulator(PlatformManipulator):
|
|
|
59
59
|
# com.dprint(f"[SUCCESS]\t Got position of manipulator {self._id}\n")
|
|
60
60
|
return PositionalResponse(
|
|
61
61
|
position=Vector4(
|
|
62
|
-
**dict(
|
|
62
|
+
**dict(
|
|
63
|
+
zip(
|
|
64
|
+
Vector4.model_fields.keys(),
|
|
65
|
+
[axis / MM_TO_UM for axis in self._device.get_pos(1)],
|
|
66
|
+
strict=False,
|
|
67
|
+
)
|
|
68
|
+
)
|
|
63
69
|
)
|
|
64
70
|
)
|
|
65
71
|
except Exception as e:
|
|
@@ -28,30 +28,30 @@ class UMP3Handler(SensapexHandler):
|
|
|
28
28
|
|
|
29
29
|
self.manipulators[manipulator_id] = UMP3Manipulator(self.ump.get_device(int(manipulator_id)))
|
|
30
30
|
|
|
31
|
-
def _platform_space_to_unified_space(self, platform_position:
|
|
31
|
+
def _platform_space_to_unified_space(self, platform_position: Vector4) -> Vector4:
|
|
32
32
|
# unified <- platform
|
|
33
33
|
# +x <- +y
|
|
34
34
|
# +y <- -x
|
|
35
35
|
# +z <- -z
|
|
36
36
|
# +d <- +d/x
|
|
37
37
|
|
|
38
|
-
return
|
|
39
|
-
platform_position
|
|
40
|
-
self.dimensions
|
|
41
|
-
self.dimensions
|
|
42
|
-
platform_position
|
|
43
|
-
|
|
38
|
+
return Vector4(
|
|
39
|
+
x=platform_position.y,
|
|
40
|
+
y=self.dimensions.x - platform_position.x,
|
|
41
|
+
z=self.dimensions.z - platform_position.z,
|
|
42
|
+
w=platform_position.w,
|
|
43
|
+
)
|
|
44
44
|
|
|
45
|
-
def _unified_space_to_platform_space(self, unified_position:
|
|
45
|
+
def _unified_space_to_platform_space(self, unified_position: Vector4) -> Vector4:
|
|
46
46
|
# platform <- unified
|
|
47
47
|
# +x <- -y
|
|
48
48
|
# +y <- +x
|
|
49
49
|
# +z <- -z
|
|
50
50
|
# +d/x <- +d
|
|
51
51
|
|
|
52
|
-
return
|
|
53
|
-
self.dimensions
|
|
54
|
-
unified_position
|
|
55
|
-
self.dimensions
|
|
56
|
-
unified_position
|
|
57
|
-
|
|
52
|
+
return Vector4(
|
|
53
|
+
x=self.dimensions.y - unified_position.y,
|
|
54
|
+
y=unified_position.x,
|
|
55
|
+
z=self.dimensions.z - unified_position.z,
|
|
56
|
+
w=unified_position.w,
|
|
57
|
+
)
|
|
@@ -55,7 +55,9 @@ class UMP3Manipulator(SensapexManipulator):
|
|
|
55
55
|
position.append(position[0])
|
|
56
56
|
|
|
57
57
|
# com.dprint(f"[SUCCESS]\t Got position of manipulator {self._id}\n")
|
|
58
|
-
return PositionalResponse(
|
|
58
|
+
return PositionalResponse(
|
|
59
|
+
position=Vector4(**dict(zip(Vector4.model_fields.keys(), position, strict=False)))
|
|
60
|
+
)
|
|
59
61
|
except Exception as e:
|
|
60
62
|
print(f"[ERROR]\t\t Getting position of manipulator {self._id}")
|
|
61
63
|
print(f"{e}\n")
|
|
@@ -11,18 +11,20 @@ every event, the server does the following:
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
+
from asyncio import get_event_loop
|
|
14
15
|
from json import loads
|
|
15
16
|
from signal import SIGINT, SIGTERM, signal
|
|
16
|
-
from sys import exit
|
|
17
17
|
from typing import TYPE_CHECKING, Any
|
|
18
|
+
from uuid import uuid4
|
|
18
19
|
|
|
19
|
-
from aiohttp import
|
|
20
|
+
from aiohttp import ClientConnectionError, ClientSession
|
|
21
|
+
from aiohttp.web import Application, run_app
|
|
20
22
|
from aiohttp.web_runner import GracefulExit
|
|
21
|
-
from packaging import
|
|
23
|
+
from packaging.version import parse
|
|
22
24
|
from pydantic import ValidationError
|
|
23
|
-
|
|
24
|
-
from
|
|
25
|
-
from socketio import AsyncServer
|
|
25
|
+
|
|
26
|
+
# from socketio import AsyncServer
|
|
27
|
+
from socketio import AsyncClient, AsyncServer
|
|
26
28
|
from vbl_aquarium.models.ephys_link import (
|
|
27
29
|
BooleanStateResponse,
|
|
28
30
|
CanWriteRequest,
|
|
@@ -32,6 +34,7 @@ from vbl_aquarium.models.ephys_link import (
|
|
|
32
34
|
InsideBrainRequest,
|
|
33
35
|
PositionalResponse,
|
|
34
36
|
)
|
|
37
|
+
from vbl_aquarium.models.proxy import PinpointIdResponse
|
|
35
38
|
|
|
36
39
|
from ephys_link.__about__ import __version__
|
|
37
40
|
from ephys_link.common import (
|
|
@@ -48,46 +51,31 @@ if TYPE_CHECKING:
|
|
|
48
51
|
|
|
49
52
|
|
|
50
53
|
class Server:
|
|
51
|
-
def __init__(self):
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
def __init__(self) -> None:
|
|
55
|
+
"""Declare and setup server object. Launching is done is a separate function."""
|
|
56
|
+
|
|
57
|
+
# Server object.
|
|
58
|
+
self.sio: AsyncClient | AsyncServer | None = None
|
|
59
|
+
|
|
60
|
+
# Web application object.
|
|
61
|
+
self.app: Application | None = None
|
|
55
62
|
|
|
63
|
+
# Proxy server ID.
|
|
64
|
+
self.pinpoint_id: str = ""
|
|
65
|
+
|
|
66
|
+
# Manipulator platform handler.
|
|
67
|
+
self.platform: PlatformHandler | None = None
|
|
56
68
|
# Is there a client connected?
|
|
57
69
|
self.is_connected = False
|
|
58
70
|
|
|
59
71
|
# Is the server running?
|
|
60
72
|
self.is_running = False
|
|
61
73
|
|
|
62
|
-
# Current platform handler (defaults to Sensapex).
|
|
63
|
-
self.platform: PlatformHandler = SensapexHandler()
|
|
64
|
-
|
|
65
74
|
# Register server exit handlers.
|
|
66
75
|
signal(SIGTERM, self.close_server)
|
|
67
76
|
signal(SIGINT, self.close_server)
|
|
68
77
|
|
|
69
|
-
|
|
70
|
-
self.sio.attach(self.app)
|
|
71
|
-
|
|
72
|
-
# Declare events and assign handlers.
|
|
73
|
-
self.sio.on("connect", self.connect)
|
|
74
|
-
self.sio.on("disconnect", self.disconnect)
|
|
75
|
-
self.sio.on("get_version", self.get_version)
|
|
76
|
-
self.sio.on("get_manipulators", self.get_manipulators)
|
|
77
|
-
self.sio.on("register_manipulator", self.register_manipulator)
|
|
78
|
-
self.sio.on("unregister_manipulator", self.unregister_manipulator)
|
|
79
|
-
self.sio.on("get_pos", self.get_pos)
|
|
80
|
-
self.sio.on("get_angles", self.get_angles)
|
|
81
|
-
self.sio.on("get_shank_count", self.get_shank_count)
|
|
82
|
-
self.sio.on("goto_pos", self.goto_pos)
|
|
83
|
-
self.sio.on("drive_to_depth", self.drive_to_depth)
|
|
84
|
-
self.sio.on("set_inside_brain", self.set_inside_brain)
|
|
85
|
-
self.sio.on("calibrate", self.calibrate)
|
|
86
|
-
self.sio.on("bypass_calibration", self.bypass_calibration)
|
|
87
|
-
self.sio.on("set_can_write", self.set_can_write)
|
|
88
|
-
self.sio.on("stop", self.stop)
|
|
89
|
-
self.sio.on("*", self.catch_all)
|
|
90
|
-
|
|
78
|
+
# Server events.
|
|
91
79
|
async def connect(self, sid, _, __) -> bool:
|
|
92
80
|
"""Acknowledge connection to the server.
|
|
93
81
|
|
|
@@ -122,7 +110,15 @@ class Server:
|
|
|
122
110
|
self.platform.reset()
|
|
123
111
|
self.is_connected = False
|
|
124
112
|
|
|
125
|
-
# Events
|
|
113
|
+
# Ephys Link Events
|
|
114
|
+
|
|
115
|
+
async def get_pinpoint_id(self) -> str:
|
|
116
|
+
"""Get the pinpoint ID.
|
|
117
|
+
|
|
118
|
+
:return: Pinpoint ID and whether the client is a requester.
|
|
119
|
+
:rtype: tuple[str, bool]
|
|
120
|
+
"""
|
|
121
|
+
return PinpointIdResponse(pinpoint_id=self.pinpoint_id, is_requester=False).to_string()
|
|
126
122
|
|
|
127
123
|
@staticmethod
|
|
128
124
|
async def get_version(_) -> str:
|
|
@@ -133,6 +129,8 @@ class Server:
|
|
|
133
129
|
:return: Version number as defined in :mod:`ephys_link.__about__`.
|
|
134
130
|
:rtype: str
|
|
135
131
|
"""
|
|
132
|
+
dprint("[EVENT]\t\t Get version")
|
|
133
|
+
|
|
136
134
|
return __version__
|
|
137
135
|
|
|
138
136
|
async def get_manipulators(self, _) -> str:
|
|
@@ -361,38 +359,21 @@ class Server:
|
|
|
361
359
|
print(f"[UNKNOWN EVENT]:\t {data}")
|
|
362
360
|
return "UNKNOWN_EVENT"
|
|
363
361
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
platform_type: str,
|
|
367
|
-
server_port: int,
|
|
368
|
-
pathfinder_port: int | None = None,
|
|
369
|
-
ignore_updates: bool = False, # noqa: FBT002
|
|
370
|
-
) -> None:
|
|
371
|
-
"""Launch the server.
|
|
372
|
-
|
|
373
|
-
:param platform_type: Parsed argument for platform type.
|
|
374
|
-
:type platform_type: str
|
|
375
|
-
:param server_port: HTTP port to serve the server.
|
|
376
|
-
:type server_port: int
|
|
377
|
-
:param pathfinder_port: Port New Scale Pathfinder's server is on.
|
|
378
|
-
:type pathfinder_port: int
|
|
379
|
-
:param ignore_updates: Flag to ignore checking for updates.
|
|
380
|
-
:type ignore_updates: bool
|
|
381
|
-
:return: None
|
|
382
|
-
"""
|
|
383
|
-
|
|
362
|
+
# Server functions
|
|
363
|
+
async def launch_setup(self, platform_type: str, pathfinder_port: int, ignore_updates) -> None:
|
|
384
364
|
# Import correct manipulator handler
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
365
|
+
match platform_type:
|
|
366
|
+
case "sensapex":
|
|
367
|
+
self.platform = SensapexHandler()
|
|
368
|
+
case "ump3":
|
|
369
|
+
self.platform = UMP3Handler()
|
|
370
|
+
case "new_scale":
|
|
371
|
+
self.platform = NewScaleHandler()
|
|
372
|
+
case "new_scale_pathfinder":
|
|
373
|
+
self.platform = NewScalePathfinderHandler(pathfinder_port)
|
|
374
|
+
case _:
|
|
375
|
+
error = f"[ERROR]\t\t Invalid manipulator type: {platform_type}"
|
|
376
|
+
raise ValueError(error)
|
|
396
377
|
|
|
397
378
|
# Preamble.
|
|
398
379
|
print(ASCII)
|
|
@@ -401,19 +382,24 @@ class Server:
|
|
|
401
382
|
# Check for newer version.
|
|
402
383
|
if not ignore_updates:
|
|
403
384
|
try:
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
385
|
+
async with (
|
|
386
|
+
ClientSession() as session,
|
|
387
|
+
session.get("https://api.github.com/repos/VirtualBrainLab/ephys-link/tags") as response,
|
|
388
|
+
):
|
|
389
|
+
latest_version = (await response.json())[0]["name"]
|
|
390
|
+
if parse(latest_version) > parse(__version__):
|
|
391
|
+
print(f"New version available: {latest_version}")
|
|
392
|
+
print("Download at: https://github.com/VirtualBrainLab/ephys-link/releases/latest")
|
|
393
|
+
|
|
394
|
+
await session.close()
|
|
395
|
+
except ClientConnectionError:
|
|
410
396
|
pass
|
|
411
397
|
|
|
412
398
|
# Explain window.
|
|
413
399
|
print()
|
|
414
400
|
print("This is the Ephys Link server window.")
|
|
415
401
|
print("You may safely leave it running in the background.")
|
|
416
|
-
print("To stop
|
|
402
|
+
print("To stop it, close this window or press CTRL + Pause/Break.")
|
|
417
403
|
print()
|
|
418
404
|
|
|
419
405
|
# List available manipulators
|
|
@@ -421,9 +407,95 @@ class Server:
|
|
|
421
407
|
print(self.platform.get_manipulators().manipulators)
|
|
422
408
|
print()
|
|
423
409
|
|
|
410
|
+
async def launch_for_proxy(
|
|
411
|
+
self, proxy_address: str, port: int, platform_type: str, pathfinder_port: int | None, ignore_updates: bool
|
|
412
|
+
) -> None:
|
|
413
|
+
"""Launch the server in proxy mode.
|
|
414
|
+
|
|
415
|
+
:param proxy_address: Proxy IP address.
|
|
416
|
+
:type proxy_address: str
|
|
417
|
+
:param port: Port to serve the server.
|
|
418
|
+
:type port: int
|
|
419
|
+
:param platform_type: Parsed argument for platform type.
|
|
420
|
+
:type platform_type: str
|
|
421
|
+
:param pathfinder_port: Port New Scale Pathfinder's server is on.
|
|
422
|
+
:type pathfinder_port: int
|
|
423
|
+
:param ignore_updates: Flag to ignore checking for updates.
|
|
424
|
+
:type ignore_updates: bool
|
|
425
|
+
:return: None
|
|
426
|
+
"""
|
|
427
|
+
|
|
428
|
+
# Launch setup
|
|
429
|
+
await self.launch_setup(platform_type, pathfinder_port, ignore_updates)
|
|
430
|
+
|
|
431
|
+
# Create AsyncClient.
|
|
432
|
+
self.sio = AsyncClient()
|
|
433
|
+
self.pinpoint_id = str(uuid4())[:8]
|
|
434
|
+
|
|
435
|
+
# Bind events.
|
|
436
|
+
self.bind_events()
|
|
437
|
+
|
|
438
|
+
# Connect and mark that server is running.
|
|
439
|
+
await self.sio.connect(f"http://{proxy_address}:{port}")
|
|
440
|
+
self.is_running = True
|
|
441
|
+
print(f"Pinpoint ID: {self.pinpoint_id}")
|
|
442
|
+
await self.sio.wait()
|
|
443
|
+
|
|
444
|
+
def launch(
|
|
445
|
+
self,
|
|
446
|
+
platform_type: str,
|
|
447
|
+
port: int,
|
|
448
|
+
pathfinder_port: int | None,
|
|
449
|
+
ignore_updates: bool,
|
|
450
|
+
) -> None:
|
|
451
|
+
"""Launch the server.
|
|
452
|
+
|
|
453
|
+
:param platform_type: Parsed argument for platform type.
|
|
454
|
+
:type platform_type: str
|
|
455
|
+
:param port: HTTP port to serve the server.
|
|
456
|
+
:type port: int
|
|
457
|
+
:param pathfinder_port: Port New Scale Pathfinder's server is on.
|
|
458
|
+
:type pathfinder_port: int
|
|
459
|
+
:param ignore_updates: Flag to ignore checking for updates.
|
|
460
|
+
:type ignore_updates: bool
|
|
461
|
+
:return: None
|
|
462
|
+
"""
|
|
463
|
+
|
|
464
|
+
# Launch setup (synchronously)
|
|
465
|
+
get_event_loop().run_until_complete(self.launch_setup(platform_type, pathfinder_port, ignore_updates))
|
|
466
|
+
|
|
467
|
+
# Create AsyncServer
|
|
468
|
+
self.sio = AsyncServer()
|
|
469
|
+
self.app = Application()
|
|
470
|
+
self.sio.attach(self.app)
|
|
471
|
+
|
|
472
|
+
# Bind events
|
|
473
|
+
self.sio.on("connect", self.connect)
|
|
474
|
+
self.sio.on("disconnect", self.disconnect)
|
|
475
|
+
self.bind_events()
|
|
476
|
+
|
|
424
477
|
# Mark that server is running
|
|
425
478
|
self.is_running = True
|
|
426
|
-
|
|
479
|
+
run_app(self.app, port=port)
|
|
480
|
+
|
|
481
|
+
def bind_events(self) -> None:
|
|
482
|
+
"""Bind Ephys Link events to the server."""
|
|
483
|
+
self.sio.on("get_pinpoint_id", self.get_pinpoint_id)
|
|
484
|
+
self.sio.on("get_version", self.get_version)
|
|
485
|
+
self.sio.on("get_manipulators", self.get_manipulators)
|
|
486
|
+
self.sio.on("register_manipulator", self.register_manipulator)
|
|
487
|
+
self.sio.on("unregister_manipulator", self.unregister_manipulator)
|
|
488
|
+
self.sio.on("get_pos", self.get_pos)
|
|
489
|
+
self.sio.on("get_angles", self.get_angles)
|
|
490
|
+
self.sio.on("get_shank_count", self.get_shank_count)
|
|
491
|
+
self.sio.on("goto_pos", self.goto_pos)
|
|
492
|
+
self.sio.on("drive_to_depth", self.drive_to_depth)
|
|
493
|
+
self.sio.on("set_inside_brain", self.set_inside_brain)
|
|
494
|
+
self.sio.on("calibrate", self.calibrate)
|
|
495
|
+
self.sio.on("bypass_calibration", self.bypass_calibration)
|
|
496
|
+
self.sio.on("set_can_write", self.set_can_write)
|
|
497
|
+
self.sio.on("stop", self.stop)
|
|
498
|
+
self.sio.on("*", self.catch_all)
|
|
427
499
|
|
|
428
500
|
def close_server(self, _, __) -> None:
|
|
429
501
|
"""Close the server."""
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# -*- mode: python ; coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
from ephys_link.__about__ import __version__ as version
|
|
4
|
-
|
|
5
|
-
a = Analysis(
|
|
6
|
-
['src\\ephys_link\\__main__.py'],
|
|
7
|
-
pathex=[],
|
|
8
|
-
binaries=[('src\\ephys_link\\resources', 'ephys_link\\resources')],
|
|
9
|
-
datas=[],
|
|
10
|
-
hiddenimports=['engineio.async_drivers.aiohttp'],
|
|
11
|
-
hookspath=[],
|
|
12
|
-
hooksconfig={},
|
|
13
|
-
runtime_hooks=[],
|
|
14
|
-
excludes=[],
|
|
15
|
-
noarchive=False,
|
|
16
|
-
)
|
|
17
|
-
pyz = PYZ(a.pure)
|
|
18
|
-
|
|
19
|
-
exe = EXE(
|
|
20
|
-
pyz,
|
|
21
|
-
a.scripts,
|
|
22
|
-
a.binaries,
|
|
23
|
-
a.datas,
|
|
24
|
-
[],
|
|
25
|
-
name=f"EphysLink-v{version}",
|
|
26
|
-
debug=False,
|
|
27
|
-
bootloader_ignore_signals=False,
|
|
28
|
-
strip=False,
|
|
29
|
-
upx=True,
|
|
30
|
-
upx_exclude=[],
|
|
31
|
-
runtime_tmpdir=None,
|
|
32
|
-
console=True,
|
|
33
|
-
disable_windowed_traceback=False,
|
|
34
|
-
argv_emulation=False,
|
|
35
|
-
target_arch=None,
|
|
36
|
-
codesign_identity=None,
|
|
37
|
-
entitlements_file=None,
|
|
38
|
-
icon='assets\\icon.ico',
|
|
39
|
-
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.3.0b2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ephys_link-1.3.0b2 → ephys_link-1.3.3}/src/ephys_link/platforms/new_scale_pathfinder_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|