sl-shared-assets 3.0.0rc2__py3-none-any.whl → 3.0.0rc4__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.

Potentially problematic release.


This version of sl-shared-assets might be problematic. Click here for more details.

@@ -28,6 +28,7 @@ from .data_classes import (
28
28
  ZaberPositions,
29
29
  ExperimentState,
30
30
  MesoscopeCameras,
31
+ TrialCueSequence,
31
32
  ProcessingTracker,
32
33
  MesoscopePositions,
33
34
  ProjectConfiguration,
@@ -81,6 +82,7 @@ __all__ = [
81
82
  "MesoscopeAdditionalFirmware",
82
83
  "get_system_configuration_data",
83
84
  "set_system_configuration_file",
85
+ "TrialCueSequence",
84
86
  # Tools package
85
87
  "resolve_p53_marker",
86
88
  "transfer_directory",
@@ -24,6 +24,7 @@ from .data_classes import (
24
24
  ZaberPositions as ZaberPositions,
25
25
  ExperimentState as ExperimentState,
26
26
  MesoscopeCameras as MesoscopeCameras,
27
+ TrialCueSequence as TrialCueSequence,
27
28
  ProcessingTracker as ProcessingTracker,
28
29
  MesoscopePositions as MesoscopePositions,
29
30
  ProjectConfiguration as ProjectConfiguration,
@@ -71,6 +72,7 @@ __all__ = [
71
72
  "MesoscopeAdditionalFirmware",
72
73
  "get_system_configuration_data",
73
74
  "set_system_configuration_file",
75
+ "TrialCueSequence",
74
76
  "resolve_p53_marker",
75
77
  "transfer_directory",
76
78
  "calculate_directory_checksum",
@@ -24,6 +24,7 @@ from .configuration_data import (
24
24
  MesoscopePaths,
25
25
  ExperimentState,
26
26
  MesoscopeCameras,
27
+ TrialCueSequence,
27
28
  MesoscopeMicroControllers,
28
29
  MesoscopeAdditionalFirmware,
29
30
  MesoscopeSystemConfiguration,
@@ -60,4 +61,5 @@ __all__ = [
60
61
  "MesoscopeMicroControllers",
61
62
  "MesoscopeAdditionalFirmware",
62
63
  "ProcessingTracker",
64
+ "TrialCueSequence",
63
65
  ]
@@ -26,6 +26,7 @@ from .configuration_data import (
26
26
  MesoscopePaths as MesoscopePaths,
27
27
  ExperimentState as ExperimentState,
28
28
  MesoscopeCameras as MesoscopeCameras,
29
+ TrialCueSequence as TrialCueSequence,
29
30
  MesoscopeMicroControllers as MesoscopeMicroControllers,
30
31
  MesoscopeAdditionalFirmware as MesoscopeAdditionalFirmware,
31
32
  MesoscopeSystemConfiguration as MesoscopeSystemConfiguration,
@@ -62,4 +63,5 @@ __all__ = [
62
63
  "MesoscopeMicroControllers",
63
64
  "MesoscopeAdditionalFirmware",
64
65
  "ProcessingTracker",
66
+ "TrialCueSequence",
65
67
  ]
@@ -39,6 +39,20 @@ class ExperimentState:
39
39
  system currently support two system state codes: REST (1) and RUN (2)."""
40
40
  state_duration_s: float
41
41
  """The time, in seconds, to maintain the current combination of the experiment and system states."""
42
+ initial_guided_trials: int
43
+ """Specifies the number of trials (laps) at the onset of the experiment state, for which lick guidance will be
44
+ automatically enabled. Specifically, if the experiment state supports running linearized Virtual Reality track, the
45
+ system will enable lick guidance for this many trials at the beginning of the experiment state and automatically
46
+ disable it for the following trials."""
47
+ failed_trial_threshold: int
48
+ """Specifies the number of failed (non-rewarded) non-guided trials (laps), after which the system will re-enable
49
+ guidance for the 'recovery_guided_trials' number of following trials. For this to take effect, the trials must be
50
+ failed this many times in a row."""
51
+ recovery_guided_trials: int
52
+ """Specifies the number of trials (laps) for which the system will re-enable lick guidance, when the animal
53
+ repeatedly fails 'failed_trial_threshold' number of trials. This field works similar to the 'initial_guided_trials'
54
+ field, but is triggered by repeated performance failures, rather than experiment state onset. After the animal
55
+ runs this many guided trials, the system will automatically disable guidance for the following trials."""
42
56
 
43
57
 
44
58
  @dataclass()
@@ -54,6 +68,10 @@ class TrialCueSequence:
54
68
 
55
69
  cue_sequence: tuple[int, ...]
56
70
  """Specifies the sequence of wall cues experienced by the animal while running this trial."""
71
+ trial_length_unity_unit: float
72
+ """The length of the trial cue sequence, in Unity units."""
73
+ trial_length_cm: float
74
+ """The length of the trial cue sequence in centimeters."""
57
75
 
58
76
 
59
77
  # noinspection PyArgumentList
@@ -82,15 +100,40 @@ class MesoscopeExperimentConfiguration(YamlConfig):
82
100
  to travel to fully traverse the wall cue region from start to end."""
83
101
  experiment_states: dict[str, ExperimentState] = field(
84
102
  default_factory=lambda: {
85
- "baseline": ExperimentState(experiment_state_code=1, system_state_code=1, state_duration_s=30),
86
- "experiment": ExperimentState(experiment_state_code=2, system_state_code=2, state_duration_s=120),
87
- "cooldown": ExperimentState(experiment_state_code=3, system_state_code=1, state_duration_s=15),
103
+ "baseline": ExperimentState(
104
+ experiment_state_code=1,
105
+ system_state_code=1,
106
+ state_duration_s=30,
107
+ initial_guided_trials=0,
108
+ failed_trial_threshold=0,
109
+ recovery_guided_trials=0,
110
+ ),
111
+ "experiment": ExperimentState(
112
+ experiment_state_code=2,
113
+ system_state_code=2,
114
+ state_duration_s=120,
115
+ initial_guided_trials=3,
116
+ failed_trial_threshold=6,
117
+ recovery_guided_trials=3,
118
+ ),
119
+ "cooldown": ExperimentState(
120
+ experiment_state_code=3,
121
+ system_state_code=1,
122
+ state_duration_s=15,
123
+ initial_guided_trials=1000000,
124
+ failed_trial_threshold=0,
125
+ recovery_guided_trials=0,
126
+ ),
88
127
  }
89
128
  )
90
129
  """A dictionary that uses human-readable state-names as keys and ExperimentState instances as values. Each
91
130
  ExperimentState instance represents a phase of the experiment."""
92
131
  trial_structures: dict[str, TrialCueSequence] = field(
93
- default_factory=lambda: {"circular_4cue": TrialCueSequence(cue_sequence=(0, 1, 0, 2, 0, 3, 0, 4))}
132
+ default_factory=lambda: {
133
+ "circular 4 cue": TrialCueSequence(
134
+ cue_sequence=(0, 1, 0, 2, 0, 3, 0, 4), trial_length_unity_unit=24.0, trial_length_cm=240.0
135
+ )
136
+ }
94
137
  )
95
138
  """A dictionary that maps human-readable trial structure names as keys and TrialCueSequence instances as values.
96
139
  Each TrialCueSequence instance represents a specific VR wall cue sequence used by a given trial structure."""
@@ -23,6 +23,9 @@ class ExperimentState:
23
23
  experiment_state_code: int
24
24
  system_state_code: int
25
25
  state_duration_s: float
26
+ initial_guided_trials: int
27
+ failed_trial_threshold: int
28
+ recovery_guided_trials: int
26
29
 
27
30
  @dataclass()
28
31
  class TrialCueSequence:
@@ -36,6 +39,8 @@ class TrialCueSequence:
36
39
  """
37
40
 
38
41
  cue_sequence: tuple[int, ...]
42
+ trial_length_unity_unit: float
43
+ trial_length_cm: float
39
44
 
40
45
  @dataclass()
41
46
  class MesoscopeExperimentConfiguration(YamlConfig):
@@ -4,6 +4,7 @@ the running job status. All lab processing and analysis pipelines use this inter
4
4
  resources.
5
5
  """
6
6
 
7
+ import stat
7
8
  from random import randint
8
9
  from pathlib import Path
9
10
  import tempfile
@@ -486,6 +487,71 @@ class Server:
486
487
  finally:
487
488
  sftp.close()
488
489
 
490
+ def pull_directory(self, local_directory_path: Path, remote_directory_path: Path) -> None:
491
+ """Recursively downloads the entire target directory from the remote server to the local machine.
492
+
493
+ Args:
494
+ local_directory_path: The path to the local directory where the remote directory will be copied.
495
+ remote_directory_path: The path to the directory on the remote server to be downloaded.
496
+ """
497
+ sftp = self._client.open_sftp()
498
+
499
+ try:
500
+ # Creates the local directory if it doesn't exist
501
+ local_directory_path.mkdir(parents=True, exist_ok=True)
502
+
503
+ # Gets the list of items in the remote directory
504
+ remote_items = sftp.listdir_attr(str(remote_directory_path))
505
+
506
+ for item in remote_items:
507
+ remote_item_path = remote_directory_path.joinpath(item.filename)
508
+ local_item_path = local_directory_path.joinpath(item.filename)
509
+
510
+ # Checks if item is a directory
511
+ if stat.S_ISDIR(item.st_mode): # type: ignore
512
+ # Recursively pulls the subdirectory
513
+ self.pull_directory(local_item_path, remote_item_path)
514
+ else:
515
+ # Pulls the individual file using existing method
516
+ sftp.get(localpath=str(local_item_path), remotepath=str(remote_item_path))
517
+
518
+ finally:
519
+ sftp.close()
520
+
521
+ def push_directory(self, local_directory_path: Path, remote_directory_path: Path) -> None:
522
+ """Recursively uploads the entire target directory from the local machine to the remote server.
523
+
524
+ Args:
525
+ local_directory_path: The path to the local directory to be uploaded.
526
+ remote_directory_path: The path on the remote server where the directory will be copied.
527
+ """
528
+ if not local_directory_path.exists() or not local_directory_path.is_dir():
529
+ message = (
530
+ f"Unable to upload the target local directory {local_directory_path} to the server, as it does not "
531
+ f"exist."
532
+ )
533
+ console.error(message=message, error=FileNotFoundError)
534
+
535
+ sftp = self._client.open_sftp()
536
+
537
+ try:
538
+ # Creates the remote directory using existing method
539
+ self.create_directory(remote_directory_path, parents=True)
540
+
541
+ # Iterates through all items in the local directory
542
+ for local_item_path in local_directory_path.iterdir():
543
+ remote_item_path = remote_directory_path.joinpath(local_item_path.name)
544
+
545
+ if local_item_path.is_dir():
546
+ # Recursively pushes subdirectory
547
+ self.push_directory(local_item_path, remote_item_path)
548
+ else:
549
+ # Pushes the individual file using existing method
550
+ sftp.put(localpath=str(local_item_path), remotepath=str(remote_item_path))
551
+
552
+ finally:
553
+ sftp.close()
554
+
489
555
  def remove(self, remote_path: Path, is_dir: bool) -> None:
490
556
  """Removes the specified file or directory from the remote server.
491
557
 
@@ -216,6 +216,20 @@ class Server:
216
216
  local_file_path: The path to the file that needs to be copied to the remote server.
217
217
  remote_file_path: The path to the file on the remote server (where to copy the file).
218
218
  """
219
+ def pull_directory(self, local_directory_path: Path, remote_directory_path: Path) -> None:
220
+ """Recursively downloads the entire target directory from the remote server to the local machine.
221
+
222
+ Args:
223
+ local_directory_path: The path to the local directory where the remote directory will be copied.
224
+ remote_directory_path: The path to the directory on the remote server to be downloaded.
225
+ """
226
+ def push_directory(self, local_directory_path: Path, remote_directory_path: Path) -> None:
227
+ """Recursively uploads the entire target directory from the local machine to the remote server.
228
+
229
+ Args:
230
+ local_directory_path: The path to the local directory to be uploaded.
231
+ remote_directory_path: The path on the remote server where the directory will be copied.
232
+ """
219
233
  def remove(self, remote_path: Path, is_dir: bool) -> None:
220
234
  """Removes the specified file or directory from the remote server.
221
235
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sl-shared-assets
3
- Version: 3.0.0rc2
3
+ Version: 3.0.0rc4
4
4
  Summary: Provides data acquisition and processing assets shared between Sun (NeuroAI) lab libraries.
5
5
  Project-URL: Homepage, https://github.com/Sun-Lab-NBB/sl-shared-assets
6
6
  Project-URL: Documentation, https://sl-shared-assets-api-docs.netlify.app/
@@ -1,12 +1,12 @@
1
- sl_shared_assets/__init__.py,sha256=meu22eFCi7n8KeUPxY_dtLbzlWA4Dxvj8yk7m60UFcI,2243
2
- sl_shared_assets/__init__.pyi,sha256=jUguKA473IsMR8sYqOOiA0_UORJXNGhcYB2nPGd0NtE,2465
1
+ sl_shared_assets/__init__.py,sha256=0v_te6XWwWEsxfq5RWfLecsNoTx1XVJj0D5OWu1OJtk,2289
2
+ sl_shared_assets/__init__.pyi,sha256=wE_YjwirUFaRql_RVCdbNbvR3tDlyuyq0JF2nQLUO1U,2531
3
3
  sl_shared_assets/cli.py,sha256=R_h_Dlla48mG1LpFDDE9flZ_NyDC9UguRUAYZL6gA9s,18383
4
4
  sl_shared_assets/cli.pyi,sha256=8ZJK56_jh2QlF3XCN6c7fI6Z022XtehB0eCrQDJbAsU,5515
5
5
  sl_shared_assets/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- sl_shared_assets/data_classes/__init__.py,sha256=ixn972b-3URCinVLRPjMfDXpO2w24_NkEUUjdqByFrA,1890
7
- sl_shared_assets/data_classes/__init__.pyi,sha256=bDBLkyhlosB4t09GxHBNKH0kaVBhHSY_j-i3MD2iKVo,2088
8
- sl_shared_assets/data_classes/configuration_data.py,sha256=h6o7Uaz2HZjV-9-wc5iz5xfkhVpPWPrncU8VU7_AeB8,30587
9
- sl_shared_assets/data_classes/configuration_data.pyi,sha256=fb12sdDuYJtfEurzbg6WcCU0NIm1mudsgsGdUVFTajQ,10305
6
+ sl_shared_assets/data_classes/__init__.py,sha256=1NusIC_gUoQDFuHtvnpPj4RJQ2pCzZhjfVzgFThG8Ws,1936
7
+ sl_shared_assets/data_classes/__init__.pyi,sha256=gdCYkXzyoZRURR5e5C0kd_frFURHEu_UI_d0QJ0RRwA,2154
8
+ sl_shared_assets/data_classes/configuration_data.py,sha256=a8MDzSJ0T3P3MGz0JyfpJ4bmlIuzXTYUVb-EG4UhyWQ,32683
9
+ sl_shared_assets/data_classes/configuration_data.pyi,sha256=anjl32Z-OgVgy96T7s7y1XN5HM_FfnztOvUFWTUjQfw,10462
10
10
  sl_shared_assets/data_classes/runtime_data.py,sha256=V98VSUHBFiqRngHAYtH6r6X_zDht65wi9TpdbbYAhS8,16656
11
11
  sl_shared_assets/data_classes/runtime_data.pyi,sha256=zATWUIP0whD0iRpxkvt78cLL_Ajr-d_9C6goHdTLnSw,6927
12
12
  sl_shared_assets/data_classes/session_data.py,sha256=0dNv_49WJeUf5IYgbGMWnMwX3aAYPIv7u8OJM5itIJA,50673
@@ -17,8 +17,8 @@ sl_shared_assets/server/__init__.py,sha256=w7y73RXXjBrWQsjU5g1QNCv_gsXDYnHos3NpO
17
17
  sl_shared_assets/server/__init__.pyi,sha256=Zc12G90fZdgEMwaVZbFzrRVV1wH_LEj3sxaV3lhk1Cw,316
18
18
  sl_shared_assets/server/job.py,sha256=DnEVIswZXm9queBgy6MlpIrCosXvQ_tweOeko7LN9yc,19431
19
19
  sl_shared_assets/server/job.pyi,sha256=uYfOuKgPL1hSHQvy5nmXzFkVjS316F3IZTdT-PmluZU,11663
20
- sl_shared_assets/server/server.py,sha256=fR7SvJDpurYBUTKkt_cImAD0x64thXPTKHmDb6YPYaU,29925
21
- sl_shared_assets/server/server.pyi,sha256=P3E_jSMlSnQ8O0UwA4fO6p4RSyu8maDEGlIJ_ptGpG4,14267
20
+ sl_shared_assets/server/server.py,sha256=MGk1v49aEFeIChMDsiR7CXjVkWwDpD9kA1TK0fwuTXw,32926
21
+ sl_shared_assets/server/server.pyi,sha256=5Yxq4txhjtd9w-6U9fPehzMeIZL5GcprVCHd9mPP6FI,15113
22
22
  sl_shared_assets/tools/__init__.py,sha256=NktXk62E_HHOrO_93z_MVmSd6-Oir3mE4xE9Yr8Qa7U,682
23
23
  sl_shared_assets/tools/__init__.pyi,sha256=0UXorfCXXmHQOP5z7hODpsqEX0DAkOta5VZqN6FSS-w,623
24
24
  sl_shared_assets/tools/ascension_tools.py,sha256=kIqYGX9F8lRao_LaVOacIiT8J9SypTvarb9mgaI9ZPs,15387
@@ -29,8 +29,8 @@ sl_shared_assets/tools/project_management_tools.py,sha256=Z_U0R26w9Le1O-u66gyF5C
29
29
  sl_shared_assets/tools/project_management_tools.pyi,sha256=4kok98nOZ4KnT-Sg-ZCZYg-WIM5qZqiyK8g1XiiDjHM,10375
30
30
  sl_shared_assets/tools/transfer_tools.py,sha256=J26kwOp_NpPSY0-xu5FTw9udte-rm_mW1FJyaTNoqQI,6606
31
31
  sl_shared_assets/tools/transfer_tools.pyi,sha256=FoH7eYZe7guGHfPr0MK5ggO62uXKwD2aJ7h1Bu7PaEE,3294
32
- sl_shared_assets-3.0.0rc2.dist-info/METADATA,sha256=mCoBnEMzF796sZr6H6yqwY0N-T46sSWNoJXg29x0FZ4,49309
33
- sl_shared_assets-3.0.0rc2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
- sl_shared_assets-3.0.0rc2.dist-info/entry_points.txt,sha256=UmO1rl7ly9N7HWPwWyP9E0b5KBUStpBo4TRoqNtizDY,430
35
- sl_shared_assets-3.0.0rc2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
36
- sl_shared_assets-3.0.0rc2.dist-info/RECORD,,
32
+ sl_shared_assets-3.0.0rc4.dist-info/METADATA,sha256=35CAPKPkE-DLPvdQ5WuGnsn77wggdxEZDRQGV1e45Ls,49309
33
+ sl_shared_assets-3.0.0rc4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
+ sl_shared_assets-3.0.0rc4.dist-info/entry_points.txt,sha256=UmO1rl7ly9N7HWPwWyP9E0b5KBUStpBo4TRoqNtizDY,430
35
+ sl_shared_assets-3.0.0rc4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
36
+ sl_shared_assets-3.0.0rc4.dist-info/RECORD,,