np-services 0.1.59__py3-none-any.whl → 0.1.73__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.
- np_services/__init__.py +8 -8
- np_services/open_ephys.py +377 -378
- np_services/protocols.py +185 -185
- np_services/proxies.py +1489 -1488
- np_services/resources/mvr_connector.py +260 -260
- np_services/resources/zro.py +325 -325
- np_services/scripts/pretest.py +170 -73
- np_services/stim_computer_theme_changer.py +41 -41
- np_services/utils.py +167 -167
- {np_services-0.1.59.dist-info → np_services-0.1.73.dist-info}/METADATA +7 -8
- np_services-0.1.73.dist-info/RECORD +15 -0
- {np_services-0.1.59.dist-info → np_services-0.1.73.dist-info}/WHEEL +2 -1
- {np_services-0.1.59.dist-info → np_services-0.1.73.dist-info}/entry_points.txt +1 -1
- np_services-0.1.73.dist-info/top_level.txt +1 -0
- np_services/.mypy_cache/.gitignore +0 -2
- np_services/.mypy_cache/3.9/@plugins_snapshot.json +0 -1
- np_services/.mypy_cache/3.9/__future__.data.json +0 -1
- np_services/.mypy_cache/3.9/__future__.meta.json +0 -1
- np_services/.mypy_cache/3.9/_ast.data.json +0 -1
- np_services/.mypy_cache/3.9/_ast.meta.json +0 -1
- np_services/.mypy_cache/3.9/_codecs.data.json +0 -1
- np_services/.mypy_cache/3.9/_codecs.meta.json +0 -1
- np_services/.mypy_cache/3.9/_collections_abc.data.json +0 -1
- np_services/.mypy_cache/3.9/_collections_abc.meta.json +0 -1
- np_services/.mypy_cache/3.9/_ctypes.data.json +0 -1
- np_services/.mypy_cache/3.9/_ctypes.meta.json +0 -1
- np_services/.mypy_cache/3.9/_decimal.data.json +0 -1
- np_services/.mypy_cache/3.9/_decimal.meta.json +0 -1
- np_services/.mypy_cache/3.9/_random.data.json +0 -1
- np_services/.mypy_cache/3.9/_random.meta.json +0 -1
- np_services/.mypy_cache/3.9/_socket.data.json +0 -1
- np_services/.mypy_cache/3.9/_socket.meta.json +0 -1
- np_services/.mypy_cache/3.9/_thread.data.json +0 -1
- np_services/.mypy_cache/3.9/_thread.meta.json +0 -1
- np_services/.mypy_cache/3.9/_typeshed/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/_typeshed/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/_warnings.data.json +0 -1
- np_services/.mypy_cache/3.9/_warnings.meta.json +0 -1
- np_services/.mypy_cache/3.9/_weakref.data.json +0 -1
- np_services/.mypy_cache/3.9/_weakref.meta.json +0 -1
- np_services/.mypy_cache/3.9/_weakrefset.data.json +0 -1
- np_services/.mypy_cache/3.9/_weakrefset.meta.json +0 -1
- np_services/.mypy_cache/3.9/_winapi.data.json +0 -1
- np_services/.mypy_cache/3.9/_winapi.meta.json +0 -1
- np_services/.mypy_cache/3.9/abc.data.json +0 -1
- np_services/.mypy_cache/3.9/abc.meta.json +0 -1
- np_services/.mypy_cache/3.9/array.data.json +0 -1
- np_services/.mypy_cache/3.9/array.meta.json +0 -1
- np_services/.mypy_cache/3.9/atexit.data.json +0 -1
- np_services/.mypy_cache/3.9/atexit.meta.json +0 -1
- np_services/.mypy_cache/3.9/builtins.data.json +0 -1
- np_services/.mypy_cache/3.9/builtins.meta.json +0 -1
- np_services/.mypy_cache/3.9/codecs.data.json +0 -1
- np_services/.mypy_cache/3.9/codecs.meta.json +0 -1
- np_services/.mypy_cache/3.9/collections/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/collections/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/collections/abc.data.json +0 -1
- np_services/.mypy_cache/3.9/collections/abc.meta.json +0 -1
- np_services/.mypy_cache/3.9/contextlib.data.json +0 -1
- np_services/.mypy_cache/3.9/contextlib.meta.json +0 -1
- np_services/.mypy_cache/3.9/ctypes/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/ctypes/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/datetime.data.json +0 -1
- np_services/.mypy_cache/3.9/datetime.meta.json +0 -1
- np_services/.mypy_cache/3.9/decimal.data.json +0 -1
- np_services/.mypy_cache/3.9/decimal.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/email/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/charset.data.json +0 -1
- np_services/.mypy_cache/3.9/email/charset.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/contentmanager.data.json +0 -1
- np_services/.mypy_cache/3.9/email/contentmanager.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/errors.data.json +0 -1
- np_services/.mypy_cache/3.9/email/errors.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/header.data.json +0 -1
- np_services/.mypy_cache/3.9/email/header.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/message.data.json +0 -1
- np_services/.mypy_cache/3.9/email/message.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/policy.data.json +0 -1
- np_services/.mypy_cache/3.9/email/policy.meta.json +0 -1
- np_services/.mypy_cache/3.9/enum.data.json +0 -1
- np_services/.mypy_cache/3.9/enum.meta.json +0 -1
- np_services/.mypy_cache/3.9/errno.data.json +0 -1
- np_services/.mypy_cache/3.9/errno.meta.json +0 -1
- np_services/.mypy_cache/3.9/fractions.data.json +0 -1
- np_services/.mypy_cache/3.9/fractions.meta.json +0 -1
- np_services/.mypy_cache/3.9/genericpath.data.json +0 -1
- np_services/.mypy_cache/3.9/genericpath.meta.json +0 -1
- np_services/.mypy_cache/3.9/importlib/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/importlib/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/importlib/abc.data.json +0 -1
- np_services/.mypy_cache/3.9/importlib/abc.meta.json +0 -1
- np_services/.mypy_cache/3.9/importlib/machinery.data.json +0 -1
- np_services/.mypy_cache/3.9/importlib/machinery.meta.json +0 -1
- np_services/.mypy_cache/3.9/importlib/metadata/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/importlib/metadata/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/io.data.json +0 -1
- np_services/.mypy_cache/3.9/io.meta.json +0 -1
- np_services/.mypy_cache/3.9/json/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/json/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/json/decoder.data.json +0 -1
- np_services/.mypy_cache/3.9/json/decoder.meta.json +0 -1
- np_services/.mypy_cache/3.9/json/encoder.data.json +0 -1
- np_services/.mypy_cache/3.9/json/encoder.meta.json +0 -1
- np_services/.mypy_cache/3.9/logging/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/logging/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/math.data.json +0 -1
- np_services/.mypy_cache/3.9/math.meta.json +0 -1
- np_services/.mypy_cache/3.9/mmap.data.json +0 -1
- np_services/.mypy_cache/3.9/mmap.meta.json +0 -1
- np_services/.mypy_cache/3.9/np_services/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/np_services/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/np_services/config.data.json +0 -1
- np_services/.mypy_cache/3.9/np_services/config.meta.json +0 -1
- np_services/.mypy_cache/3.9/np_services/protocols.data.json +0 -1
- np_services/.mypy_cache/3.9/np_services/protocols.meta.json +0 -1
- np_services/.mypy_cache/3.9/np_services/zro.data.json +0 -1
- np_services/.mypy_cache/3.9/np_services/zro.meta.json +0 -1
- np_services/.mypy_cache/3.9/ntpath.data.json +0 -1
- np_services/.mypy_cache/3.9/ntpath.meta.json +0 -1
- np_services/.mypy_cache/3.9/numbers.data.json +0 -1
- np_services/.mypy_cache/3.9/numbers.meta.json +0 -1
- np_services/.mypy_cache/3.9/os/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/os/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/os/path.data.json +0 -1
- np_services/.mypy_cache/3.9/os/path.meta.json +0 -1
- np_services/.mypy_cache/3.9/pathlib.data.json +0 -1
- np_services/.mypy_cache/3.9/pathlib.meta.json +0 -1
- np_services/.mypy_cache/3.9/pickle.data.json +0 -1
- np_services/.mypy_cache/3.9/pickle.meta.json +0 -1
- np_services/.mypy_cache/3.9/platform.data.json +0 -1
- np_services/.mypy_cache/3.9/platform.meta.json +0 -1
- np_services/.mypy_cache/3.9/posixpath.data.json +0 -1
- np_services/.mypy_cache/3.9/posixpath.meta.json +0 -1
- np_services/.mypy_cache/3.9/random.data.json +0 -1
- np_services/.mypy_cache/3.9/random.meta.json +0 -1
- np_services/.mypy_cache/3.9/re.data.json +0 -1
- np_services/.mypy_cache/3.9/re.meta.json +0 -1
- np_services/.mypy_cache/3.9/shutil.data.json +0 -1
- np_services/.mypy_cache/3.9/shutil.meta.json +0 -1
- np_services/.mypy_cache/3.9/socket.data.json +0 -1
- np_services/.mypy_cache/3.9/socket.meta.json +0 -1
- np_services/.mypy_cache/3.9/sre_compile.data.json +0 -1
- np_services/.mypy_cache/3.9/sre_compile.meta.json +0 -1
- np_services/.mypy_cache/3.9/sre_constants.data.json +0 -1
- np_services/.mypy_cache/3.9/sre_constants.meta.json +0 -1
- np_services/.mypy_cache/3.9/sre_parse.data.json +0 -1
- np_services/.mypy_cache/3.9/sre_parse.meta.json +0 -1
- np_services/.mypy_cache/3.9/string.data.json +0 -1
- np_services/.mypy_cache/3.9/string.meta.json +0 -1
- np_services/.mypy_cache/3.9/subprocess.data.json +0 -1
- np_services/.mypy_cache/3.9/subprocess.meta.json +0 -1
- np_services/.mypy_cache/3.9/sys.data.json +0 -1
- np_services/.mypy_cache/3.9/sys.meta.json +0 -1
- np_services/.mypy_cache/3.9/threading.data.json +0 -1
- np_services/.mypy_cache/3.9/threading.meta.json +0 -1
- np_services/.mypy_cache/3.9/time.data.json +0 -1
- np_services/.mypy_cache/3.9/time.meta.json +0 -1
- np_services/.mypy_cache/3.9/types.data.json +0 -1
- np_services/.mypy_cache/3.9/types.meta.json +0 -1
- np_services/.mypy_cache/3.9/typing.data.json +0 -1
- np_services/.mypy_cache/3.9/typing.meta.json +0 -1
- np_services/.mypy_cache/3.9/typing_extensions.data.json +0 -1
- np_services/.mypy_cache/3.9/typing_extensions.meta.json +0 -1
- np_services/.mypy_cache/3.9/warnings.data.json +0 -1
- np_services/.mypy_cache/3.9/warnings.meta.json +0 -1
- np_services/.mypy_cache/3.9/weakref.data.json +0 -1
- np_services/.mypy_cache/3.9/weakref.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/_typing.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/_typing.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/backend/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/backend/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/backend/select.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/backend/select.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/constants.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/constants.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/error.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/error.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/attrsettr.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/attrsettr.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/context.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/context.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/frame.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/frame.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/poll.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/poll.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/socket.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/socket.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/tracker.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/tracker.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/version.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/version.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/interop.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/interop.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/jsonapi.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/jsonapi.meta.json +0 -1
- np_services/.mypy_cache/CACHEDIR.TAG +0 -3
- np_services/resources/black_desktop.ps1 +0 -66
- np_services/resources/grey_desktop.ps1 +0 -66
- np_services/resources/reset_desktop.ps1 +0 -66
- np_services-0.1.59.dist-info/RECORD +0 -206
np_services/scripts/pretest.py
CHANGED
|
@@ -1,50 +1,93 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import abc
|
|
1
4
|
import argparse
|
|
5
|
+
import copy
|
|
2
6
|
import contextlib
|
|
7
|
+
import dataclasses
|
|
3
8
|
import functools
|
|
9
|
+
import json
|
|
4
10
|
import os
|
|
5
11
|
import pathlib
|
|
12
|
+
import sys
|
|
6
13
|
import tempfile
|
|
7
14
|
import time
|
|
8
15
|
import logging
|
|
9
|
-
from typing import Iterable, Literal
|
|
16
|
+
from typing import Iterable, Literal, Type
|
|
10
17
|
|
|
11
18
|
import upath
|
|
12
19
|
|
|
13
20
|
|
|
14
|
-
os.environ["USE_TEST_RIG"] = "0"
|
|
15
|
-
os.environ["AIBS_RIG_ID"] = "NP.3"
|
|
16
|
-
|
|
17
21
|
import np_session
|
|
18
22
|
import np_services
|
|
19
23
|
import np_config
|
|
20
24
|
import npc_sync
|
|
21
|
-
import npc_ephys
|
|
22
25
|
import npc_mvr
|
|
23
26
|
import npc_stim
|
|
24
27
|
|
|
25
28
|
logger = logging.getLogger()
|
|
26
29
|
|
|
27
|
-
DEFAULT_SERVICES = (np_services.MouseDirector, )
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
DEFAULT_SERVICES: tuple[np_services.Testable, ...] = (np_services.MouseDirector, )
|
|
31
|
+
DEFAULT_RECORDERS: tuple[np_services.Startable, ...] = (np_services.Sync, np_services.VideoMVR, )
|
|
32
|
+
|
|
33
|
+
@dataclasses.dataclass
|
|
34
|
+
class PretestConfig:
|
|
35
|
+
check_sync_barcodes: bool = False
|
|
36
|
+
check_ephys_barcodes: bool = False # this is error prone with short recordings, so is separated from checking sync alone
|
|
37
|
+
check_licks: bool = False
|
|
38
|
+
check_opto: bool = False
|
|
39
|
+
check_audio: bool = False
|
|
40
|
+
check_running: bool = False
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def check_barcodes(self) -> bool:
|
|
44
|
+
return self.check_sync_barcodes or self.check_ephys_barcodes
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class PretestSession(abc.ABC):
|
|
48
|
+
|
|
49
|
+
def __init__(self, pretest_config: PretestConfig) -> None:
|
|
50
|
+
self.pretest_config = pretest_config
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def services(self) -> tuple[np_services.Testable | np_services.Startable, ...]:
|
|
54
|
+
return DEFAULT_SERVICES + self.recorders + (self.stim, )
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def recorders(self) -> tuple[np_services.Startable, ...]:
|
|
58
|
+
if self.pretest_config.check_ephys_barcodes or self.pretest_config.check_sync_barcodes:
|
|
59
|
+
return DEFAULT_RECORDERS + (np_services.OpenEphys, )
|
|
60
|
+
return DEFAULT_RECORDERS
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
@abc.abstractmethod
|
|
64
|
+
def stim(self) -> Type[np_services.Camstim]: ...
|
|
30
65
|
|
|
31
|
-
|
|
66
|
+
@abc.abstractmethod
|
|
67
|
+
def configure_services(self) -> None: ...
|
|
68
|
+
|
|
69
|
+
@abc.abstractmethod
|
|
70
|
+
def run_pretest_stim(self) -> None: ...
|
|
71
|
+
|
|
72
|
+
class DynamicRoutingPretest(PretestSession):
|
|
32
73
|
"""Modified version of class in np_workflows."""
|
|
74
|
+
|
|
33
75
|
use_github: bool = True
|
|
76
|
+
task_name: str = "" # unused in pretest
|
|
34
77
|
|
|
78
|
+
@property
|
|
79
|
+
def stim(self) -> Type[np_services.ScriptCamstim]:
|
|
80
|
+
return np_services.ScriptCamstim
|
|
81
|
+
|
|
35
82
|
@property
|
|
36
83
|
def rig(self) -> np_config.Rig:
|
|
37
84
|
return np_config.Rig()
|
|
38
|
-
|
|
39
|
-
@property
|
|
40
|
-
def config(self) -> dict:
|
|
41
|
-
return self.rig.config
|
|
42
85
|
|
|
43
86
|
@property
|
|
44
87
|
def commit_hash(self) -> str:
|
|
45
88
|
if hasattr(self, '_commit_hash'):
|
|
46
89
|
return self._commit_hash
|
|
47
|
-
self._commit_hash = self.config['dynamicrouting_task_script']['commit_hash']
|
|
90
|
+
self._commit_hash = self.rig.config['dynamicrouting_task_script']['commit_hash']
|
|
48
91
|
return self.commit_hash
|
|
49
92
|
|
|
50
93
|
@commit_hash.setter
|
|
@@ -55,7 +98,7 @@ class DynamicRoutingPretest:
|
|
|
55
98
|
def github_url(self) -> str:
|
|
56
99
|
if hasattr(self, '_github_url'):
|
|
57
100
|
return self._github_url
|
|
58
|
-
self._github_url = self.config['dynamicrouting_task_script']['url']
|
|
101
|
+
self._github_url = self.rig.config['dynamicrouting_task_script']['url']
|
|
59
102
|
return self.github_url
|
|
60
103
|
|
|
61
104
|
@github_url.setter
|
|
@@ -70,21 +113,6 @@ class DynamicRoutingPretest:
|
|
|
70
113
|
def base_path(self) -> pathlib.Path:
|
|
71
114
|
return pathlib.Path('//allen/programs/mindscope/workgroups/dynamicrouting/DynamicRoutingTask/')
|
|
72
115
|
|
|
73
|
-
@property
|
|
74
|
-
def task_name(self) -> str:
|
|
75
|
-
"""For sending to runTask.py and controlling implementation details of the task."""
|
|
76
|
-
if hasattr(self, '_task_name'):
|
|
77
|
-
return self._task_name
|
|
78
|
-
return ""
|
|
79
|
-
|
|
80
|
-
@task_name.setter
|
|
81
|
-
def task_name(self, task_name: str) -> None:
|
|
82
|
-
self._task_name = task_name
|
|
83
|
-
if task_name not in self.preset_task_names:
|
|
84
|
-
print(f"{task_name = !r} doesn't correspond to a preset value, but the attribute is updated anyway!")
|
|
85
|
-
else:
|
|
86
|
-
print(f"Updated {self.__class__.__name__}.{task_name = !r}")
|
|
87
|
-
|
|
88
116
|
@property
|
|
89
117
|
def mouse(self) -> np_session.Mouse:
|
|
90
118
|
return np_session.Mouse(366122)
|
|
@@ -135,9 +163,11 @@ class DynamicRoutingPretest:
|
|
|
135
163
|
|
|
136
164
|
rig = str(self.rig).replace('.', '')
|
|
137
165
|
locs_root = self.base_path / 'OptoGui' / f'{dirname}'
|
|
138
|
-
|
|
166
|
+
# use any available locs file - as long as the light switches on the
|
|
167
|
+
# values don't matter
|
|
168
|
+
available_locs = sorted(tuple(locs_root.glob(f"{file_prefix}*")), reverse=True)
|
|
139
169
|
if not available_locs:
|
|
140
|
-
raise FileNotFoundError(f"No optotagging locs found
|
|
170
|
+
raise FileNotFoundError(f"No optotagging locs found - have you run OptoGui?")
|
|
141
171
|
return available_locs[0]
|
|
142
172
|
|
|
143
173
|
|
|
@@ -197,16 +227,16 @@ class DynamicRoutingPretest:
|
|
|
197
227
|
|
|
198
228
|
def run_script(self, stim: Literal['sound_test', 'mapping', 'task', 'opto', 'optotagging', 'spontaneous', 'spontaneous_rewards']) -> None:
|
|
199
229
|
|
|
200
|
-
params = getattr(self, f'{stim.replace(" ", "_")}_params')
|
|
230
|
+
params = copy.deepcopy(getattr(self, f'{stim.replace(" ", "_")}_params'))
|
|
201
231
|
|
|
202
232
|
# add mouse and user info for MPE
|
|
203
233
|
params['mouse_id'] = str(self.mouse.id)
|
|
204
234
|
params['user_id'] = 'ben.hardcastle'
|
|
205
235
|
|
|
206
|
-
|
|
207
|
-
|
|
236
|
+
if self.task_script_base.as_posix() not in params['taskScript']:
|
|
237
|
+
params['taskScript'] = (self.task_script_base / params['taskScript']).as_posix()
|
|
208
238
|
|
|
209
|
-
params['maxTrials'] = 30
|
|
239
|
+
params['maxTrials'] = 30
|
|
210
240
|
|
|
211
241
|
if self.use_github:
|
|
212
242
|
|
|
@@ -217,23 +247,53 @@ class DynamicRoutingPretest:
|
|
|
217
247
|
}
|
|
218
248
|
params['task_script_commit_hash'] = self.commit_hash
|
|
219
249
|
|
|
220
|
-
|
|
250
|
+
self.stim.script = self.camstim_script.read_text()
|
|
221
251
|
else:
|
|
222
|
-
|
|
252
|
+
self.stim.script = self.camstim_script.as_posix()
|
|
223
253
|
|
|
224
|
-
|
|
254
|
+
self.stim.params = params
|
|
225
255
|
|
|
226
256
|
|
|
227
|
-
|
|
257
|
+
self.stim.start()
|
|
228
258
|
with contextlib.suppress(np_services.resources.zro.ZroError):
|
|
229
|
-
while not
|
|
259
|
+
while not self.stim.is_ready_to_start():
|
|
230
260
|
time.sleep(1)
|
|
231
261
|
|
|
232
262
|
|
|
233
263
|
with contextlib.suppress(np_services.resources.zro.ZroError):
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
def
|
|
264
|
+
self.stim.finalize()
|
|
265
|
+
|
|
266
|
+
def run_pretest_stim(self) -> None:
|
|
267
|
+
if self.pretest_config.check_audio:
|
|
268
|
+
print("Starting audio test - check for sound...", end="", flush=True)
|
|
269
|
+
self.run_script('sound_test')
|
|
270
|
+
print(" done")
|
|
271
|
+
print("Starting stim - check for opto, spin wheel and tap lick spout...", end="", flush=True)
|
|
272
|
+
self.run_script('optotagging') # vis stim with opto (for checking vsyncs, running, )
|
|
273
|
+
print(" done")
|
|
274
|
+
|
|
275
|
+
def configure_services(self) -> None:
|
|
276
|
+
self.stim.script = '//allen/programs/mindscope/workgroups/dynamicrouting/DynamicRoutingTask/runTask.py'
|
|
277
|
+
self.stim.data_root = pathlib.Path('//allen/programs/mindscope/workgroups/dynamicrouting/DynamicRoutingTask/Data/366122')
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class LegacyNP0Pretest(PretestSession):
|
|
281
|
+
def __init__(self, pretest_config: PretestConfig) -> None:
|
|
282
|
+
self.pretest_config = pretest_config
|
|
283
|
+
|
|
284
|
+
@property
|
|
285
|
+
def stim(self) -> Type[np_services.SessionCamstim]:
|
|
286
|
+
return np_services.SessionCamstim
|
|
287
|
+
|
|
288
|
+
def run_pretest_stim(self) -> None:
|
|
289
|
+
self.stim.start()
|
|
290
|
+
|
|
291
|
+
def configure_services(self) -> None:
|
|
292
|
+
self.stim.lims_user_id = "ben.hardcastle"
|
|
293
|
+
self.stim.labtracks_mouse_id = 598796
|
|
294
|
+
self.stim.override_params = json.loads(pathlib.Path("//allen/programs/mindscope/workgroups/dynamicrouting/ben/np0_pretest/params.json").read_bytes())
|
|
295
|
+
|
|
296
|
+
def configure_services(session: PretestSession) -> None:
|
|
237
297
|
"""For each service, apply every key in self.config['service'] as an attribute."""
|
|
238
298
|
|
|
239
299
|
def apply_config(service) -> None:
|
|
@@ -244,73 +304,110 @@ def configure_services(services: Iterable[np_services.Testable]) -> None:
|
|
|
244
304
|
f"{service.__name__} | Configuring {service.__name__}.{key} = {getattr(service, key)}"
|
|
245
305
|
)
|
|
246
306
|
|
|
247
|
-
for service in services:
|
|
307
|
+
for service in session.services:
|
|
248
308
|
for base in service.__class__.__bases__:
|
|
249
309
|
apply_config(base)
|
|
250
310
|
apply_config(service)
|
|
251
|
-
|
|
252
|
-
np_services.ScriptCamstim.script = '//allen/programs/mindscope/workgroups/dynamicrouting/DynamicRoutingTask/runTask.py'
|
|
253
|
-
np_services.ScriptCamstim.data_root = pathlib.Path('//allen/programs/mindscope/workgroups/dynamicrouting/DynamicRoutingTask/Data/366122')
|
|
254
|
-
|
|
311
|
+
|
|
255
312
|
np_services.MouseDirector.user = 'ben.hardcastle'
|
|
256
313
|
np_services.MouseDirector.mouse = 366122
|
|
314
|
+
|
|
315
|
+
session.configure_services()
|
|
257
316
|
|
|
258
|
-
|
|
317
|
+
if session.pretest_config.check_barcodes:
|
|
318
|
+
np_services.OpenEphys.folder = '_test_'
|
|
259
319
|
|
|
260
320
|
|
|
261
321
|
@functools.cache
|
|
262
322
|
def get_temp_dir() -> pathlib.Path:
|
|
263
323
|
return pathlib.Path(tempfile.mkdtemp())
|
|
264
324
|
|
|
265
|
-
def
|
|
266
|
-
|
|
267
|
-
stim: np_services.Startable = DEFAULT_STIM,
|
|
268
|
-
other: Iterable[np_services.Testable] = DEFAULT_SERVICES,
|
|
269
|
-
check_licks: bool = False,
|
|
270
|
-
check_opto: bool = False,
|
|
271
|
-
check_audio: bool = False,
|
|
325
|
+
def run_pretest(
|
|
326
|
+
config: PretestConfig = PretestConfig(),
|
|
272
327
|
) -> None:
|
|
273
328
|
print("Starting pretest")
|
|
274
|
-
|
|
275
|
-
|
|
329
|
+
session: PretestSession
|
|
330
|
+
if np_config.Rig().idx == 0:
|
|
331
|
+
session = LegacyNP0Pretest(config)
|
|
332
|
+
else:
|
|
333
|
+
session = DynamicRoutingPretest(config)
|
|
334
|
+
configure_services(session)
|
|
335
|
+
|
|
336
|
+
for service in session.services:
|
|
276
337
|
if isinstance(service, np_services.Initializable):
|
|
277
338
|
service.initialize()
|
|
278
339
|
|
|
279
|
-
stoppables = tuple(_ for _ in recorders if isinstance(_, np_services.Stoppable))
|
|
340
|
+
stoppables = tuple(_ for _ in session.recorders if isinstance(_, np_services.Stoppable))
|
|
280
341
|
with np_services.stop_on_error(*stoppables):
|
|
281
342
|
for service in stoppables:
|
|
282
343
|
if isinstance(service, np_services.Startable):
|
|
283
344
|
service.start()
|
|
284
345
|
t0 = time.time()
|
|
285
|
-
|
|
346
|
+
session.run_pretest_stim()
|
|
286
347
|
t1 = time.time()
|
|
287
|
-
|
|
348
|
+
if not config.check_barcodes:
|
|
349
|
+
min_wait_time = 0
|
|
350
|
+
elif config.check_sync_barcodes and not config.check_ephys_barcodes:
|
|
351
|
+
min_wait_time = 35 # long enough to capture 1 sets of barcodes on sync
|
|
352
|
+
else:
|
|
353
|
+
min_wait_time = 70 # long enough to capture 2 sets of barcodes on sync/openephys (cannot scale time with 1 set)
|
|
354
|
+
time.sleep(max(0, min_wait_time - (t1 - t0)))
|
|
288
355
|
for service in reversed(stoppables):
|
|
289
356
|
if isinstance(service, np_services.Stoppable):
|
|
290
357
|
service.stop()
|
|
291
358
|
|
|
292
|
-
for service in
|
|
359
|
+
for service in session.services:
|
|
293
360
|
if isinstance(service, np_services.Finalizable):
|
|
294
361
|
service.finalize()
|
|
295
362
|
|
|
296
|
-
np_services.VideoMVR.sync_path = np_services.OpenEphys.sync_path = stim.sync_path = np_services.Sync.data_files[0]
|
|
363
|
+
np_services.VideoMVR.sync_path = np_services.OpenEphys.sync_path = session.stim.sync_path = np_services.Sync.data_files[0]
|
|
297
364
|
|
|
298
|
-
|
|
365
|
+
# validate
|
|
366
|
+
for service in session.services:
|
|
299
367
|
if isinstance(service, np_services.Validatable):
|
|
300
|
-
service.
|
|
301
|
-
|
|
368
|
+
if service is not np_services.OpenEphys:
|
|
369
|
+
service.validate()
|
|
370
|
+
elif config.check_ephys_barcodes:
|
|
371
|
+
# try validating ephys without sync (currently error prone with short pretest-like recordings)
|
|
372
|
+
import npc_ephys
|
|
373
|
+
npc_ephys.validate_ephys(
|
|
374
|
+
root_paths=service.data_files,
|
|
375
|
+
sync_path_or_dataset=False,
|
|
376
|
+
ignore_small_folders=False,
|
|
377
|
+
)
|
|
378
|
+
else:
|
|
379
|
+
# barcodes on sync will be validated, open ephys will be assumed to work correctly
|
|
380
|
+
continue
|
|
381
|
+
assert np_services.Sync.data_files is not None, "No sync file found"
|
|
382
|
+
assert session.stim.data_files is not None, "No stim file found"
|
|
383
|
+
|
|
384
|
+
if any((config.check_licks, config.check_opto, config.check_audio)):
|
|
302
385
|
npc_sync.SyncDataset(np_services.Sync.data_files[0]).validate(
|
|
303
|
-
licks=check_licks, opto=check_opto, audio=check_audio,
|
|
386
|
+
licks=config.check_licks, opto=config.check_opto, audio=config.check_audio,
|
|
304
387
|
)
|
|
388
|
+
if config.check_running:
|
|
389
|
+
speed, timestamps = npc_stim.get_running_speed_from_stim_files(*session.stim.data_files, sync=np_services.Sync.data_files[0])
|
|
390
|
+
if not speed.size or not timestamps.size:
|
|
391
|
+
raise AssertionError("No running data found")
|
|
305
392
|
|
|
306
|
-
def parse_args() ->
|
|
393
|
+
def parse_args() -> PretestConfig:
|
|
307
394
|
parser = argparse.ArgumentParser(description="Run pretest")
|
|
395
|
+
parser.add_argument("--check_ephys_barcodes", action="store_true", help="Check barcodes from Arduino are being received on open ephys and time-alignment is possible (currently error prone with short pretest-like recordings)", default=False)
|
|
396
|
+
parser.add_argument("--check_sync_barcodes", action="store_true", help="Check barcodes from Arduino are being received on sync", default=False)
|
|
308
397
|
parser.add_argument("--check_licks", action="store_true", help="Check lick sensor line on sync", default=False)
|
|
309
398
|
parser.add_argument("--check_opto", action="store_true", help="Check opto-running line on sync", default=False)
|
|
310
399
|
parser.add_argument("--check_audio", action="store_true", help="Check audio-running line on sync", default=False)
|
|
311
|
-
|
|
400
|
+
parser.add_argument("--check_running", action="store_true", help="Check running-wheel encoder data in stim files", default=False)
|
|
401
|
+
return PretestConfig(**vars(parser.parse_args()))
|
|
402
|
+
|
|
403
|
+
def main() -> None:
|
|
404
|
+
logging.basicConfig(
|
|
405
|
+
level="INFO",
|
|
406
|
+
format="%(name)s | %(levelname)s | %(message)s",
|
|
407
|
+
datefmt="%H:%M:%S",
|
|
408
|
+
stream=sys.stdout,
|
|
409
|
+
)
|
|
410
|
+
run_pretest(parse_args())
|
|
312
411
|
|
|
313
412
|
if __name__ == '__main__':
|
|
314
|
-
main(
|
|
315
|
-
**parse_args()
|
|
316
|
-
)
|
|
413
|
+
main()
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import pathlib
|
|
2
|
-
from typing import ClassVar
|
|
3
|
-
|
|
4
|
-
import fabric
|
|
5
|
-
import np_config
|
|
6
|
-
|
|
7
|
-
from np_services.proxies import ScriptCamstim
|
|
8
|
-
|
|
9
|
-
class DesktopThemeChanger(ScriptCamstim):
|
|
10
|
-
"""Base class for setting the background wallpaper on a remote machine,
|
|
11
|
-
then hiding all desktop icons, hiding the taskbar, minimizing all windows"""
|
|
12
|
-
local_file: ClassVar[str | pathlib.Path]
|
|
13
|
-
remote_file: ClassVar[str | pathlib.Path]
|
|
14
|
-
|
|
15
|
-
extra_args: ClassVar[list[str]] = []
|
|
16
|
-
ssh: ClassVar[fabric.Connection]
|
|
17
|
-
user: ClassVar[str] = 'svc_neuropix'
|
|
18
|
-
password: ClassVar[str] = np_config.fetch('logins')['svc_neuropix']['password']
|
|
19
|
-
|
|
20
|
-
# @classmethod
|
|
21
|
-
# def initialize(cls):
|
|
22
|
-
# super().initialize()
|
|
23
|
-
# cls.get_ssh().put(cls.local_file, cls.remote_file)
|
|
24
|
-
|
|
25
|
-
@classmethod
|
|
26
|
-
def start(cls):
|
|
27
|
-
cls.get_ssh().run(f'powershell.exe -ExecutionPolicy bypass {cls.remote_file}')
|
|
28
|
-
|
|
29
|
-
class DarkDesktopChanger(DesktopThemeChanger):
|
|
30
|
-
local_file = pathlib.Path(__file__).parent / 'resources' / 'black_wallpaper.ps1'
|
|
31
|
-
# remote_file: ClassVar[str | pathlib.Path] = 'c:/users/svc_neuropix/desktop/black_wallpaper.ps1'
|
|
32
|
-
remote_file: ClassVar[str | pathlib.Path] = R'\\allen\programs\mindscope\workgroups\dynamicrouting\ben\black_wallpaper.ps1'
|
|
33
|
-
|
|
34
|
-
class GreyDesktopChanger(DesktopThemeChanger):
|
|
35
|
-
local_file = pathlib.Path(__file__).parent / 'resources' / 'grey_wallpaper.ps1'
|
|
36
|
-
# remote_file: ClassVar[str | pathlib.Path] = 'c:/users/svc_neuropix/desktop/grey_wallpaper.ps1'
|
|
37
|
-
remote_file: ClassVar[str | pathlib.Path] = R'\\allen\programs\mindscope\workgroups\dynamicrouting\ben\grey_wallpaper.ps1'
|
|
38
|
-
|
|
39
|
-
class DesktopResetter(DesktopThemeChanger):
|
|
40
|
-
local_file = pathlib.Path(__file__).parent / 'resources' / 'reset_wallpaper.ps1'
|
|
41
|
-
# remote_file: ClassVar[str | pathlib.Path] = 'c:/users/svc_neuropix/desktop/reset_wallpaper.ps1'
|
|
1
|
+
import pathlib
|
|
2
|
+
from typing import ClassVar
|
|
3
|
+
|
|
4
|
+
import fabric
|
|
5
|
+
import np_config
|
|
6
|
+
|
|
7
|
+
from np_services.proxies import ScriptCamstim
|
|
8
|
+
|
|
9
|
+
class DesktopThemeChanger(ScriptCamstim):
|
|
10
|
+
"""Base class for setting the background wallpaper on a remote machine,
|
|
11
|
+
then hiding all desktop icons, hiding the taskbar, minimizing all windows"""
|
|
12
|
+
local_file: ClassVar[str | pathlib.Path]
|
|
13
|
+
remote_file: ClassVar[str | pathlib.Path]
|
|
14
|
+
|
|
15
|
+
extra_args: ClassVar[list[str]] = []
|
|
16
|
+
ssh: ClassVar[fabric.Connection]
|
|
17
|
+
user: ClassVar[str] = 'svc_neuropix'
|
|
18
|
+
password: ClassVar[str] = np_config.fetch('logins')['svc_neuropix']['password']
|
|
19
|
+
|
|
20
|
+
# @classmethod
|
|
21
|
+
# def initialize(cls):
|
|
22
|
+
# super().initialize()
|
|
23
|
+
# cls.get_ssh().put(cls.local_file, cls.remote_file)
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def start(cls):
|
|
27
|
+
cls.get_ssh().run(f'powershell.exe -ExecutionPolicy bypass {cls.remote_file}')
|
|
28
|
+
|
|
29
|
+
class DarkDesktopChanger(DesktopThemeChanger):
|
|
30
|
+
local_file = pathlib.Path(__file__).parent / 'resources' / 'black_wallpaper.ps1'
|
|
31
|
+
# remote_file: ClassVar[str | pathlib.Path] = 'c:/users/svc_neuropix/desktop/black_wallpaper.ps1'
|
|
32
|
+
remote_file: ClassVar[str | pathlib.Path] = R'\\allen\programs\mindscope\workgroups\dynamicrouting\ben\black_wallpaper.ps1'
|
|
33
|
+
|
|
34
|
+
class GreyDesktopChanger(DesktopThemeChanger):
|
|
35
|
+
local_file = pathlib.Path(__file__).parent / 'resources' / 'grey_wallpaper.ps1'
|
|
36
|
+
# remote_file: ClassVar[str | pathlib.Path] = 'c:/users/svc_neuropix/desktop/grey_wallpaper.ps1'
|
|
37
|
+
remote_file: ClassVar[str | pathlib.Path] = R'\\allen\programs\mindscope\workgroups\dynamicrouting\ben\grey_wallpaper.ps1'
|
|
38
|
+
|
|
39
|
+
class DesktopResetter(DesktopThemeChanger):
|
|
40
|
+
local_file = pathlib.Path(__file__).parent / 'resources' / 'reset_wallpaper.ps1'
|
|
41
|
+
# remote_file: ClassVar[str | pathlib.Path] = 'c:/users/svc_neuropix/desktop/reset_wallpaper.ps1'
|
|
42
42
|
remote_file: ClassVar[str | pathlib.Path] = R'\\allen\programs\mindscope\workgroups\dynamicrouting\ben\reset_wallpaper.ps1'
|