sl-shared-assets 3.0.0rc14__py3-none-any.whl → 3.0.1__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.
- sl_shared_assets/cli.py +7 -11
- sl_shared_assets/cli.pyi +5 -9
- sl_shared_assets/data_classes/__init__.py +2 -2
- sl_shared_assets/data_classes/configuration_data.py +11 -8
- sl_shared_assets/data_classes/configuration_data.pyi +8 -7
- sl_shared_assets/data_classes/runtime_data.py +2 -2
- sl_shared_assets/data_classes/runtime_data.pyi +2 -2
- sl_shared_assets/data_classes/session_data.py +43 -29
- sl_shared_assets/data_classes/session_data.pyi +11 -11
- sl_shared_assets/server/__init__.py +1 -1
- sl_shared_assets/server/job.py +10 -10
- sl_shared_assets/server/job.pyi +5 -5
- sl_shared_assets/server/server.py +15 -15
- sl_shared_assets/server/server.pyi +7 -7
- sl_shared_assets/tools/ascension_tools.py +8 -8
- sl_shared_assets/tools/packaging_tools.py +2 -1
- sl_shared_assets/tools/project_management_tools.py +30 -40
- sl_shared_assets/tools/project_management_tools.pyi +6 -10
- sl_shared_assets/tools/transfer_tools.py +1 -1
- sl_shared_assets/tools/transfer_tools.pyi +1 -1
- {sl_shared_assets-3.0.0rc14.dist-info → sl_shared_assets-3.0.1.dist-info}/METADATA +122 -5
- sl_shared_assets-3.0.1.dist-info/RECORD +36 -0
- sl_shared_assets-3.0.0rc14.dist-info/RECORD +0 -36
- {sl_shared_assets-3.0.0rc14.dist-info → sl_shared_assets-3.0.1.dist-info}/WHEEL +0 -0
- {sl_shared_assets-3.0.0rc14.dist-info → sl_shared_assets-3.0.1.dist-info}/entry_points.txt +0 -0
- {sl_shared_assets-3.0.0rc14.dist-info → sl_shared_assets-3.0.1.dist-info}/licenses/LICENSE +0 -0
sl_shared_assets/cli.py
CHANGED
|
@@ -49,11 +49,11 @@ def verify_session_integrity(
|
|
|
49
49
|
"""Checks the integrity of the target session's raw data (contents of the raw_data directory).
|
|
50
50
|
|
|
51
51
|
This command assumes that the data has been checksummed during acquisition and contains an ax_checksum.txt file
|
|
52
|
-
that stores the data checksum generated before transferring the data to long-term storage destination. This
|
|
53
|
-
always verified the integrity of the 'raw_data' directory. It does not work with 'processed_data' or any
|
|
54
|
-
directories. If the session data was corrupted, the command removes the 'telomere.bin' file, marking the
|
|
55
|
-
'incomplete' and automatically excluding it from all further automated processing runtimes.
|
|
56
|
-
is intact, generates a 'verified.bin' marker file inside the session's raw_data folder.
|
|
52
|
+
that stores the data checksum generated before transferring the data to the long-term storage destination. This
|
|
53
|
+
function always verified the integrity of the 'raw_data' directory. It does not work with 'processed_data' or any
|
|
54
|
+
other directories. If the session data was corrupted, the command removes the 'telomere.bin' file, marking the
|
|
55
|
+
session as 'incomplete' and automatically excluding it from all further automated processing runtimes. If the
|
|
56
|
+
session data is intact, it generates a 'verified.bin' marker file inside the session's raw_data folder.
|
|
57
57
|
|
|
58
58
|
The command is also used by Sun lab data acquisition systems to generate the processed data hierarchy for each
|
|
59
59
|
processed session. This use case is fully automated and should not be triggered manually by the user.
|
|
@@ -366,7 +366,7 @@ def start_jupyter_server(
|
|
|
366
366
|
server = Server(credentials_path)
|
|
367
367
|
job: JupyterJob | None = None
|
|
368
368
|
try:
|
|
369
|
-
# If the caller did not provide an explicit notebook directory, defaults to user's working directory
|
|
369
|
+
# If the caller did not provide an explicit notebook directory, defaults to the user's working directory
|
|
370
370
|
if directory is None:
|
|
371
371
|
directory = (server.user_working_root,)
|
|
372
372
|
|
|
@@ -394,7 +394,7 @@ def start_jupyter_server(
|
|
|
394
394
|
if job is not None:
|
|
395
395
|
server.abort_job(job)
|
|
396
396
|
|
|
397
|
-
# Closes server connection if it is still open
|
|
397
|
+
# Closes the server connection if it is still open
|
|
398
398
|
server.close()
|
|
399
399
|
|
|
400
400
|
|
|
@@ -446,10 +446,6 @@ def resolve_dataset_marker(
|
|
|
446
446
|
processing pipelines are not allowed to work with the session data, ensuring that all processed data remains
|
|
447
447
|
unchanged. If the marker does not exist, dataset integration pipelines are not allowed to work with the session
|
|
448
448
|
data, enabling processing pipelines to safely modify the data at any time.
|
|
449
|
-
|
|
450
|
-
This command is automatically called at the end of each processing runtime to automatically transfer processed
|
|
451
|
-
sessions to the dataset integration step by creating the p53.bin marker. In contrast, removing the marker can only
|
|
452
|
-
be done manually.
|
|
453
449
|
"""
|
|
454
450
|
resolve_p53_marker(
|
|
455
451
|
session_path=session_path,
|
sl_shared_assets/cli.pyi
CHANGED
|
@@ -22,11 +22,11 @@ def verify_session_integrity(
|
|
|
22
22
|
"""Checks the integrity of the target session's raw data (contents of the raw_data directory).
|
|
23
23
|
|
|
24
24
|
This command assumes that the data has been checksummed during acquisition and contains an ax_checksum.txt file
|
|
25
|
-
that stores the data checksum generated before transferring the data to long-term storage destination. This
|
|
26
|
-
always verified the integrity of the 'raw_data' directory. It does not work with 'processed_data' or any
|
|
27
|
-
directories. If the session data was corrupted, the command removes the 'telomere.bin' file, marking the
|
|
28
|
-
'incomplete' and automatically excluding it from all further automated processing runtimes.
|
|
29
|
-
is intact, generates a 'verified.bin' marker file inside the session's raw_data folder.
|
|
25
|
+
that stores the data checksum generated before transferring the data to the long-term storage destination. This
|
|
26
|
+
function always verified the integrity of the 'raw_data' directory. It does not work with 'processed_data' or any
|
|
27
|
+
other directories. If the session data was corrupted, the command removes the 'telomere.bin' file, marking the
|
|
28
|
+
session as 'incomplete' and automatically excluding it from all further automated processing runtimes. If the
|
|
29
|
+
session data is intact, it generates a 'verified.bin' marker file inside the session's raw_data folder.
|
|
30
30
|
|
|
31
31
|
The command is also used by Sun lab data acquisition systems to generate the processed data hierarchy for each
|
|
32
32
|
processed session. This use case is fully automated and should not be triggered manually by the user.
|
|
@@ -94,8 +94,4 @@ def resolve_dataset_marker(
|
|
|
94
94
|
processing pipelines are not allowed to work with the session data, ensuring that all processed data remains
|
|
95
95
|
unchanged. If the marker does not exist, dataset integration pipelines are not allowed to work with the session
|
|
96
96
|
data, enabling processing pipelines to safely modify the data at any time.
|
|
97
|
-
|
|
98
|
-
This command is automatically called at the end of each processing runtime to automatically transfer processed
|
|
99
|
-
sessions to the dataset integration step by creating the p53.bin marker. In contrast, removing the marker can only
|
|
100
|
-
be done manually.
|
|
101
97
|
"""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""This package provides the classes used to store data acquired at various stages of the data workflow and to
|
|
2
2
|
configure various pipelines used in the Sun lab. These classes are used across all stages of data acquisition,
|
|
3
|
-
preprocessing, and processing in the lab
|
|
4
|
-
|
|
3
|
+
preprocessing, and processing in the lab. Many classes in this package are designed to be saved to disk as .yaml files
|
|
4
|
+
and restored from the .yaml files as needed."""
|
|
5
5
|
|
|
6
6
|
from .runtime_data import (
|
|
7
7
|
ZaberPositions,
|
|
@@ -24,10 +24,10 @@ class AcquisitionSystems(StrEnum):
|
|
|
24
24
|
class ExperimentState:
|
|
25
25
|
"""Encapsulates the information used to set and maintain the desired experiment and system state.
|
|
26
26
|
|
|
27
|
-
Broadly, each experiment runtime can be conceptualized as a two
|
|
27
|
+
Broadly, each experiment runtime can be conceptualized as a two-state-system. The first is the experiment task,
|
|
28
28
|
which reflects the behavior goal, the rules for achieving the goal, and the reward for achieving the goal. The
|
|
29
29
|
second is the data acquisition system state, which is a snapshot of all hardware module states that make up the
|
|
30
|
-
system that acquires the data and controls the task environment. Overall, experiment state is about
|
|
30
|
+
system that acquires the data and controls the task environment. Overall, the experiment state is about
|
|
31
31
|
'what the animal is doing', while the system state is about 'what the hardware is doing'.
|
|
32
32
|
|
|
33
33
|
Note:
|
|
@@ -96,16 +96,16 @@ class ExperimentTrial:
|
|
|
96
96
|
class MesoscopeExperimentConfiguration(YamlConfig):
|
|
97
97
|
"""Stores the configuration of a single experiment runtime that uses the Mesoscope_VR data acquisition system.
|
|
98
98
|
|
|
99
|
-
Primarily, this includes the sequence of experiment and system states that
|
|
99
|
+
Primarily, this includes the sequence of experiment and system states that define the flow of the experiment
|
|
100
100
|
runtime and the configuration of various trials supported by the experiment runtime. During runtime, the main
|
|
101
101
|
runtime control function traverses the sequence of states stored in this class instance start-to-end in the exact
|
|
102
|
-
order specified by the user. Together with custom Unity projects
|
|
103
|
-
responds to animal interactions with the VR system) this class allows flexibly implementing a wide range of
|
|
102
|
+
order specified by the user. Together with custom Unity projects, which define the task logic (how the system
|
|
103
|
+
responds to animal interactions with the VR system), this class allows flexibly implementing a wide range of
|
|
104
104
|
experiments using the Mesoscope-VR system.
|
|
105
105
|
|
|
106
106
|
Each project should define one or more experiment configurations and save them as .yaml files inside the project
|
|
107
107
|
'configuration' folder. The name for each configuration file is defined by the user and is used to identify and load
|
|
108
|
-
the experiment configuration when 'sl-experiment' CLI command exposed by the sl-experiment library is executed.
|
|
108
|
+
the experiment configuration when the 'sl-experiment' CLI command exposed by the sl-experiment library is executed.
|
|
109
109
|
|
|
110
110
|
Notes:
|
|
111
111
|
This class is designed exclusively for the Mesoscope-VR system. Any other system needs to define a separate
|
|
@@ -126,6 +126,9 @@ class MesoscopeExperimentConfiguration(YamlConfig):
|
|
|
126
126
|
track. This offset statically shifts the entire track (in centimeters) against the set of VR wall cues used during
|
|
127
127
|
runtime. Storing this static offset as part of experiment configuration is crucial for correctly mapping what the
|
|
128
128
|
animal sees during runtime to the real-world distance it travels on the running wheel."""
|
|
129
|
+
unity_scene_name: str = "IvanScene"
|
|
130
|
+
"""The name of the Virtual Reality task (Unity Scene) used during experiment. This is used as an extra security
|
|
131
|
+
measure to ensure that Unity game engine is running the correct scene when starting the experiment runtime."""
|
|
129
132
|
experiment_states: dict[str, ExperimentState] = field(
|
|
130
133
|
default_factory=lambda: {
|
|
131
134
|
"baseline": ExperimentState(
|
|
@@ -415,7 +418,7 @@ class MesoscopeSystemConfiguration(YamlConfig):
|
|
|
415
418
|
self.paths.mesoscope_directory = Path(self.paths.mesoscope_directory)
|
|
416
419
|
self.paths.harvesters_cti_path = Path(self.paths.harvesters_cti_path)
|
|
417
420
|
|
|
418
|
-
# Converts valve_calibration data from dictionary to a tuple of tuples format
|
|
421
|
+
# Converts valve_calibration data from a dictionary to a tuple of tuples format
|
|
419
422
|
if not isinstance(self.microcontrollers.valve_calibration_data, tuple):
|
|
420
423
|
self.microcontrollers.valve_calibration_data = tuple(
|
|
421
424
|
(k, v) for k, v in self.microcontrollers.valve_calibration_data.items()
|
|
@@ -483,7 +486,7 @@ def set_system_configuration_file(path: Path) -> None:
|
|
|
483
486
|
the managed machine (PC).
|
|
484
487
|
|
|
485
488
|
This function is used to initially configure or override the existing configuration of any data acquisition system
|
|
486
|
-
used in the lab. The path to the configuration file is stored inside the user's data directory
|
|
489
|
+
used in the lab. The path to the configuration file is stored inside the user's data directory so that all
|
|
487
490
|
Sun lab libraries can automatically access that information during every runtime. Since the storage directory is
|
|
488
491
|
typically hidden and varies between OSes and machines, this function provides a convenient way for setting that
|
|
489
492
|
path without manually editing the storage cache.
|
|
@@ -14,10 +14,10 @@ class AcquisitionSystems(StrEnum):
|
|
|
14
14
|
class ExperimentState:
|
|
15
15
|
"""Encapsulates the information used to set and maintain the desired experiment and system state.
|
|
16
16
|
|
|
17
|
-
Broadly, each experiment runtime can be conceptualized as a two
|
|
17
|
+
Broadly, each experiment runtime can be conceptualized as a two-state-system. The first is the experiment task,
|
|
18
18
|
which reflects the behavior goal, the rules for achieving the goal, and the reward for achieving the goal. The
|
|
19
19
|
second is the data acquisition system state, which is a snapshot of all hardware module states that make up the
|
|
20
|
-
system that acquires the data and controls the task environment. Overall, experiment state is about
|
|
20
|
+
system that acquires the data and controls the task environment. Overall, the experiment state is about
|
|
21
21
|
'what the animal is doing', while the system state is about 'what the hardware is doing'.
|
|
22
22
|
|
|
23
23
|
Note:
|
|
@@ -53,16 +53,16 @@ class ExperimentTrial:
|
|
|
53
53
|
class MesoscopeExperimentConfiguration(YamlConfig):
|
|
54
54
|
"""Stores the configuration of a single experiment runtime that uses the Mesoscope_VR data acquisition system.
|
|
55
55
|
|
|
56
|
-
Primarily, this includes the sequence of experiment and system states that
|
|
56
|
+
Primarily, this includes the sequence of experiment and system states that define the flow of the experiment
|
|
57
57
|
runtime and the configuration of various trials supported by the experiment runtime. During runtime, the main
|
|
58
58
|
runtime control function traverses the sequence of states stored in this class instance start-to-end in the exact
|
|
59
|
-
order specified by the user. Together with custom Unity projects
|
|
60
|
-
responds to animal interactions with the VR system) this class allows flexibly implementing a wide range of
|
|
59
|
+
order specified by the user. Together with custom Unity projects, which define the task logic (how the system
|
|
60
|
+
responds to animal interactions with the VR system), this class allows flexibly implementing a wide range of
|
|
61
61
|
experiments using the Mesoscope-VR system.
|
|
62
62
|
|
|
63
63
|
Each project should define one or more experiment configurations and save them as .yaml files inside the project
|
|
64
64
|
'configuration' folder. The name for each configuration file is defined by the user and is used to identify and load
|
|
65
|
-
the experiment configuration when 'sl-experiment' CLI command exposed by the sl-experiment library is executed.
|
|
65
|
+
the experiment configuration when the 'sl-experiment' CLI command exposed by the sl-experiment library is executed.
|
|
66
66
|
|
|
67
67
|
Notes:
|
|
68
68
|
This class is designed exclusively for the Mesoscope-VR system. Any other system needs to define a separate
|
|
@@ -73,6 +73,7 @@ class MesoscopeExperimentConfiguration(YamlConfig):
|
|
|
73
73
|
|
|
74
74
|
cue_map: dict[int, float] = field(default_factory=Incomplete)
|
|
75
75
|
cue_offset_cm: float = ...
|
|
76
|
+
unity_scene_name: str = ...
|
|
76
77
|
experiment_states: dict[str, ExperimentState] = field(default_factory=Incomplete)
|
|
77
78
|
trial_structures: dict[str, ExperimentTrial] = field(default_factory=Incomplete)
|
|
78
79
|
|
|
@@ -197,7 +198,7 @@ def set_system_configuration_file(path: Path) -> None:
|
|
|
197
198
|
the managed machine (PC).
|
|
198
199
|
|
|
199
200
|
This function is used to initially configure or override the existing configuration of any data acquisition system
|
|
200
|
-
used in the lab. The path to the configuration file is stored inside the user's data directory
|
|
201
|
+
used in the lab. The path to the configuration file is stored inside the user's data directory so that all
|
|
201
202
|
Sun lab libraries can automatically access that information during every runtime. Since the storage directory is
|
|
202
203
|
typically hidden and varies between OSes and machines, this function provides a convenient way for setting that
|
|
203
204
|
path without manually editing the storage cache.
|
|
@@ -35,7 +35,7 @@ class MesoscopeHardwareState(YamlConfig):
|
|
|
35
35
|
any field in this dataclass to None also functions as a flag for whether to parse the log associated with the
|
|
36
36
|
module that provides this field's information.
|
|
37
37
|
|
|
38
|
-
This class is automatically configured by _MesoscopeVRSystem class from sl-experiment library to facilitate
|
|
38
|
+
This class is automatically configured by _MesoscopeVRSystem class from the sl-experiment library to facilitate
|
|
39
39
|
proper log parsing.
|
|
40
40
|
"""
|
|
41
41
|
|
|
@@ -200,7 +200,7 @@ class WindowCheckingDescriptor(YamlConfig):
|
|
|
200
200
|
|
|
201
201
|
Notes:
|
|
202
202
|
Window Checking sessions are different from all other sessions. Unlike other sessions, their purpose is not to
|
|
203
|
-
generate data
|
|
203
|
+
generate data but rather to assess the suitability of the particular animal to be included in training and
|
|
204
204
|
experiment cohorts. These sessions are automatically excluded from any automated data processing and analysis.
|
|
205
205
|
"""
|
|
206
206
|
|
|
@@ -28,7 +28,7 @@ class MesoscopeHardwareState(YamlConfig):
|
|
|
28
28
|
any field in this dataclass to None also functions as a flag for whether to parse the log associated with the
|
|
29
29
|
module that provides this field's information.
|
|
30
30
|
|
|
31
|
-
This class is automatically configured by _MesoscopeVRSystem class from sl-experiment library to facilitate
|
|
31
|
+
This class is automatically configured by _MesoscopeVRSystem class from the sl-experiment library to facilitate
|
|
32
32
|
proper log parsing.
|
|
33
33
|
"""
|
|
34
34
|
|
|
@@ -102,7 +102,7 @@ class WindowCheckingDescriptor(YamlConfig):
|
|
|
102
102
|
|
|
103
103
|
Notes:
|
|
104
104
|
Window Checking sessions are different from all other sessions. Unlike other sessions, their purpose is not to
|
|
105
|
-
generate data
|
|
105
|
+
generate data but rather to assess the suitability of the particular animal to be included in training and
|
|
106
106
|
experiment cohorts. These sessions are automatically excluded from any automated data processing and analysis.
|
|
107
107
|
"""
|
|
108
108
|
|
|
@@ -29,7 +29,7 @@ class SessionTypes(StrEnum):
|
|
|
29
29
|
|
|
30
30
|
Notes:
|
|
31
31
|
This enumeration does not differentiate between different acquisition systems. Different acquisition systems
|
|
32
|
-
support different session types
|
|
32
|
+
support different session types and may not be suited for acquiring some of the session types listed in this
|
|
33
33
|
enumeration.
|
|
34
34
|
"""
|
|
35
35
|
|
|
@@ -288,7 +288,7 @@ class SessionData(YamlConfig):
|
|
|
288
288
|
name. If the session is not an experiment session, this field should be left as Null (None)."""
|
|
289
289
|
python_version: str = "3.11.13"
|
|
290
290
|
"""Stores the Python version that was used to acquire session data."""
|
|
291
|
-
sl_experiment_version: str = "
|
|
291
|
+
sl_experiment_version: str = "3.0.0"
|
|
292
292
|
"""Stores the version of the sl-experiment library that was used to acquire the session data."""
|
|
293
293
|
raw_data: RawData = field(default_factory=lambda: RawData())
|
|
294
294
|
"""Stores absolute paths to all directories and files that jointly make the session's raw data hierarchy. This
|
|
@@ -405,7 +405,7 @@ class SessionData(YamlConfig):
|
|
|
405
405
|
raw_data.resolve_paths(root_directory_path=session_path.joinpath("raw_data"))
|
|
406
406
|
raw_data.make_directories() # Generates the local 'raw_data' directory tree
|
|
407
407
|
|
|
408
|
-
# Resolves
|
|
408
|
+
# Resolves but does not make processed_data directories. All runtimes that require access to 'processed_data'
|
|
409
409
|
# are configured to generate those directories if necessary, so there is no need to make them here.
|
|
410
410
|
processed_data = ProcessedData()
|
|
411
411
|
processed_data.resolve_paths(root_directory_path=session_path.joinpath("processed_data"))
|
|
@@ -425,18 +425,18 @@ class SessionData(YamlConfig):
|
|
|
425
425
|
sl_experiment_version=sl_experiment_version,
|
|
426
426
|
)
|
|
427
427
|
|
|
428
|
-
# Saves the configured instance data to the session's folder
|
|
428
|
+
# Saves the configured instance data to the session's folder so that it can be reused during processing or
|
|
429
429
|
# preprocessing.
|
|
430
430
|
instance._save()
|
|
431
431
|
|
|
432
432
|
# Also saves the SystemConfiguration and ExperimentConfiguration instances to the same folder using the paths
|
|
433
433
|
# resolved for the RawData instance above.
|
|
434
434
|
|
|
435
|
-
# Dumps the acquisition system's configuration data to session's folder
|
|
435
|
+
# Dumps the acquisition system's configuration data to the session's folder
|
|
436
436
|
acquisition_system.save(path=instance.raw_data.system_configuration_path)
|
|
437
437
|
|
|
438
438
|
if experiment_name is not None:
|
|
439
|
-
# Copies the experiment_configuration.yaml file to session's folder
|
|
439
|
+
# Copies the experiment_configuration.yaml file to the session's folder
|
|
440
440
|
experiment_configuration_path = acquisition_system.paths.root_directory.joinpath(
|
|
441
441
|
project_name, "configuration", f"{experiment_name}.yaml"
|
|
442
442
|
)
|
|
@@ -473,8 +473,8 @@ class SessionData(YamlConfig):
|
|
|
473
473
|
provide the path to the root project directory (directory that stores all Sun lab projects) on that
|
|
474
474
|
drive. The method will automatically resolve the project/animal/session/processed_data hierarchy using
|
|
475
475
|
this root path. If raw and processed data are kept on the same drive, keep this set to None.
|
|
476
|
-
make_processed_data_directory: Determines whether this method should create processed_data directory if
|
|
477
|
-
does not exist.
|
|
476
|
+
make_processed_data_directory: Determines whether this method should create the processed_data directory if
|
|
477
|
+
it does not exist.
|
|
478
478
|
|
|
479
479
|
Returns:
|
|
480
480
|
An initialized SessionData instance for the session whose data is stored at the provided path.
|
|
@@ -484,7 +484,7 @@ class SessionData(YamlConfig):
|
|
|
484
484
|
|
|
485
485
|
"""
|
|
486
486
|
# To properly initialize the SessionData instance, the provided path should contain the raw_data directory
|
|
487
|
-
# with session_data.yaml file.
|
|
487
|
+
# with the session_data.yaml file.
|
|
488
488
|
session_data_path = session_path.joinpath("raw_data", "session_data.yaml")
|
|
489
489
|
if not session_data_path.exists():
|
|
490
490
|
message = (
|
|
@@ -495,7 +495,7 @@ class SessionData(YamlConfig):
|
|
|
495
495
|
)
|
|
496
496
|
console.error(message=message, error=FileNotFoundError)
|
|
497
497
|
|
|
498
|
-
# Loads class data from .yaml file
|
|
498
|
+
# Loads class data from the .yaml file
|
|
499
499
|
instance: SessionData = cls.from_yaml(file_path=session_data_path) # type: ignore
|
|
500
500
|
|
|
501
501
|
# The method assumes that the 'donor' .yaml file is always stored inside the raw_data directory of the session
|
|
@@ -538,7 +538,7 @@ class SessionData(YamlConfig):
|
|
|
538
538
|
def _save(self) -> None:
|
|
539
539
|
"""Saves the instance data to the 'raw_data' directory of the managed session as a 'session_data.yaml' file.
|
|
540
540
|
|
|
541
|
-
This is used to save the data stored in the instance to disk
|
|
541
|
+
This is used to save the data stored in the instance to disk so that it can be reused during further stages of
|
|
542
542
|
data processing. The method is intended to only be used by the SessionData instance itself during its
|
|
543
543
|
create() method runtime.
|
|
544
544
|
"""
|
|
@@ -547,9 +547,9 @@ class SessionData(YamlConfig):
|
|
|
547
547
|
# processing
|
|
548
548
|
origin = copy.deepcopy(self)
|
|
549
549
|
|
|
550
|
-
# Resets all path fields to null. These fields are not loaded from disk when the instance is loaded, so
|
|
551
|
-
# them to null has no negative consequences. Conversely, keeping these fields with Path objects
|
|
552
|
-
# SessionData instance from being loaded from disk.
|
|
550
|
+
# Resets all path fields to null. These fields are not loaded from the disk when the instance is loaded, so
|
|
551
|
+
# setting them to null has no negative consequences. Conversely, keeping these fields with Path objects
|
|
552
|
+
# prevents the SessionData instance from being loaded from the disk.
|
|
553
553
|
origin.raw_data = None # type: ignore
|
|
554
554
|
origin.processed_data = None # type: ignore
|
|
555
555
|
|
|
@@ -585,6 +585,10 @@ class ProcessingTracker(YamlConfig):
|
|
|
585
585
|
_lock_path: str = field(init=False)
|
|
586
586
|
"""Stores the path to the .lock file for the target tracker .yaml file. This file is used to ensure that only one
|
|
587
587
|
process can simultaneously read from or write to the wrapped .yaml file."""
|
|
588
|
+
_started_runtime: bool = False
|
|
589
|
+
"""This internal service field tracks when the class instance is used to start a runtime. It is set automatically by
|
|
590
|
+
the ProcessingTracker instance and is used to prevent runtime errors from deadlocking the specific processing
|
|
591
|
+
pipeline tracked by the class instance."""
|
|
588
592
|
|
|
589
593
|
def __post_init__(self) -> None:
|
|
590
594
|
# Generates the lock file for the target .yaml file path.
|
|
@@ -594,19 +598,18 @@ class ProcessingTracker(YamlConfig):
|
|
|
594
598
|
self._lock_path = ""
|
|
595
599
|
|
|
596
600
|
def __del__(self) -> None:
|
|
597
|
-
"""If the instance
|
|
598
|
-
|
|
601
|
+
"""If the instance as used to start a runtime, ensures that the instance properly marks the runtime as completed
|
|
602
|
+
or erred before being garbage-collected.
|
|
599
603
|
|
|
600
|
-
|
|
601
|
-
data.
|
|
604
|
+
This is a security mechanism to prevent deadlocking the processed session and pipeline for future runtimes.
|
|
602
605
|
"""
|
|
603
|
-
if self._is_running:
|
|
606
|
+
if self._started_runtime and self._is_running:
|
|
604
607
|
self.error()
|
|
605
608
|
|
|
606
609
|
def _load_state(self) -> None:
|
|
607
610
|
"""Reads the current processing state from the wrapped .YAML file."""
|
|
608
611
|
if self.file_path.exists():
|
|
609
|
-
# Loads the data for the state values
|
|
612
|
+
# Loads the data for the state values but does not replace the file path or lock attributes.
|
|
610
613
|
instance: ProcessingTracker = self.from_yaml(self.file_path) # type: ignore
|
|
611
614
|
self._is_complete = instance._is_complete
|
|
612
615
|
self._encountered_error = instance._encountered_error
|
|
@@ -622,6 +625,7 @@ class ProcessingTracker(YamlConfig):
|
|
|
622
625
|
original = copy.deepcopy(self)
|
|
623
626
|
original.file_path = None # type: ignore
|
|
624
627
|
original._lock_path = None # type: ignore
|
|
628
|
+
original._started_runtime = False # This field is only used by the instance stored in memory.
|
|
625
629
|
original.to_yaml(file_path=self.file_path)
|
|
626
630
|
|
|
627
631
|
def start(self) -> None:
|
|
@@ -631,13 +635,13 @@ class ProcessingTracker(YamlConfig):
|
|
|
631
635
|
with an error.
|
|
632
636
|
|
|
633
637
|
Raises:
|
|
634
|
-
TimeoutError: If the file
|
|
638
|
+
TimeoutError: If the .lock file for the target .YAML file cannot be acquired within the timeout period.
|
|
635
639
|
"""
|
|
636
640
|
try:
|
|
637
641
|
# Acquires the lock
|
|
638
642
|
lock = FileLock(self._lock_path)
|
|
639
643
|
with lock.acquire(timeout=10.0):
|
|
640
|
-
# Loads tracker state from .yaml file
|
|
644
|
+
# Loads tracker state from the .yaml file
|
|
641
645
|
self._load_state()
|
|
642
646
|
|
|
643
647
|
# If the runtime is already running, aborts with an error
|
|
@@ -656,6 +660,10 @@ class ProcessingTracker(YamlConfig):
|
|
|
656
660
|
self._encountered_error = False
|
|
657
661
|
self._save_state()
|
|
658
662
|
|
|
663
|
+
# Sets the start tracker flag to True, which ensures that the class tries to mark the runtime as
|
|
664
|
+
# completed or erred before it being garbage-collected.
|
|
665
|
+
self._started_runtime = True
|
|
666
|
+
|
|
659
667
|
# If lock acquisition fails for any reason, aborts with an error
|
|
660
668
|
except Timeout:
|
|
661
669
|
message = (
|
|
@@ -676,14 +684,14 @@ class ProcessingTracker(YamlConfig):
|
|
|
676
684
|
from the process that calls this method.
|
|
677
685
|
|
|
678
686
|
Raises:
|
|
679
|
-
TimeoutError: If the file
|
|
687
|
+
TimeoutError: If the .lock file for the target .YAML file cannot be acquired within the timeout period.
|
|
680
688
|
"""
|
|
681
689
|
|
|
682
690
|
try:
|
|
683
691
|
# Acquires the lock
|
|
684
692
|
lock = FileLock(self._lock_path)
|
|
685
693
|
with lock.acquire(timeout=10.0):
|
|
686
|
-
# Loads tracker state from .yaml file
|
|
694
|
+
# Loads tracker state from the .yaml file
|
|
687
695
|
self._load_state()
|
|
688
696
|
|
|
689
697
|
# If the runtime is not running, aborts with an error
|
|
@@ -702,6 +710,9 @@ class ProcessingTracker(YamlConfig):
|
|
|
702
710
|
self._encountered_error = True
|
|
703
711
|
self._save_state()
|
|
704
712
|
|
|
713
|
+
# Disables the security flag
|
|
714
|
+
self._started_runtime = False
|
|
715
|
+
|
|
705
716
|
# If lock acquisition fails for any reason, aborts with an error
|
|
706
717
|
except Timeout:
|
|
707
718
|
message = (
|
|
@@ -720,14 +731,14 @@ class ProcessingTracker(YamlConfig):
|
|
|
720
731
|
at the end of the runtime.
|
|
721
732
|
|
|
722
733
|
Raises:
|
|
723
|
-
TimeoutError: If the file
|
|
734
|
+
TimeoutError: If the .lock file for the target .YAML file cannot be acquired within the timeout period.
|
|
724
735
|
"""
|
|
725
736
|
|
|
726
737
|
try:
|
|
727
738
|
# Acquires the lock
|
|
728
739
|
lock = FileLock(self._lock_path)
|
|
729
740
|
with lock.acquire(timeout=10.0):
|
|
730
|
-
# Loads tracker state from .yaml file
|
|
741
|
+
# Loads tracker state from the .yaml file
|
|
731
742
|
self._load_state()
|
|
732
743
|
|
|
733
744
|
# If the runtime is not running, aborts with an error
|
|
@@ -746,6 +757,9 @@ class ProcessingTracker(YamlConfig):
|
|
|
746
757
|
self._encountered_error = False
|
|
747
758
|
self._save_state()
|
|
748
759
|
|
|
760
|
+
# Disables the security flag
|
|
761
|
+
self._started_runtime = False
|
|
762
|
+
|
|
749
763
|
# If lock acquisition fails for any reason, aborts with an error
|
|
750
764
|
except Timeout:
|
|
751
765
|
message = (
|
|
@@ -764,7 +778,7 @@ class ProcessingTracker(YamlConfig):
|
|
|
764
778
|
# Acquires the lock
|
|
765
779
|
lock = FileLock(self._lock_path)
|
|
766
780
|
with lock.acquire(timeout=10.0):
|
|
767
|
-
# Loads tracker state from .yaml file
|
|
781
|
+
# Loads tracker state from the .yaml file
|
|
768
782
|
self._load_state()
|
|
769
783
|
return self._is_complete
|
|
770
784
|
|
|
@@ -786,7 +800,7 @@ class ProcessingTracker(YamlConfig):
|
|
|
786
800
|
# Acquires the lock
|
|
787
801
|
lock = FileLock(self._lock_path)
|
|
788
802
|
with lock.acquire(timeout=10.0):
|
|
789
|
-
# Loads tracker state from .yaml file
|
|
803
|
+
# Loads tracker state from the .yaml file
|
|
790
804
|
self._load_state()
|
|
791
805
|
return self._encountered_error
|
|
792
806
|
|
|
@@ -808,7 +822,7 @@ class ProcessingTracker(YamlConfig):
|
|
|
808
822
|
# Acquires the lock
|
|
809
823
|
lock = FileLock(self._lock_path)
|
|
810
824
|
with lock.acquire(timeout=10.0):
|
|
811
|
-
# Loads tracker state from .yaml file
|
|
825
|
+
# Loads tracker state from the .yaml file
|
|
812
826
|
self._load_state()
|
|
813
827
|
return self._is_running
|
|
814
828
|
|
|
@@ -20,7 +20,7 @@ class SessionTypes(StrEnum):
|
|
|
20
20
|
|
|
21
21
|
Notes:
|
|
22
22
|
This enumeration does not differentiate between different acquisition systems. Different acquisition systems
|
|
23
|
-
support different session types
|
|
23
|
+
support different session types and may not be suited for acquiring some of the session types listed in this
|
|
24
24
|
enumeration.
|
|
25
25
|
"""
|
|
26
26
|
|
|
@@ -206,8 +206,8 @@ class SessionData(YamlConfig):
|
|
|
206
206
|
provide the path to the root project directory (directory that stores all Sun lab projects) on that
|
|
207
207
|
drive. The method will automatically resolve the project/animal/session/processed_data hierarchy using
|
|
208
208
|
this root path. If raw and processed data are kept on the same drive, keep this set to None.
|
|
209
|
-
make_processed_data_directory: Determines whether this method should create processed_data directory if
|
|
210
|
-
does not exist.
|
|
209
|
+
make_processed_data_directory: Determines whether this method should create the processed_data directory if
|
|
210
|
+
it does not exist.
|
|
211
211
|
|
|
212
212
|
Returns:
|
|
213
213
|
An initialized SessionData instance for the session whose data is stored at the provided path.
|
|
@@ -226,7 +226,7 @@ class SessionData(YamlConfig):
|
|
|
226
226
|
def _save(self) -> None:
|
|
227
227
|
"""Saves the instance data to the 'raw_data' directory of the managed session as a 'session_data.yaml' file.
|
|
228
228
|
|
|
229
|
-
This is used to save the data stored in the instance to disk
|
|
229
|
+
This is used to save the data stored in the instance to disk so that it can be reused during further stages of
|
|
230
230
|
data processing. The method is intended to only be used by the SessionData instance itself during its
|
|
231
231
|
create() method runtime.
|
|
232
232
|
"""
|
|
@@ -245,13 +245,13 @@ class ProcessingTracker(YamlConfig):
|
|
|
245
245
|
_encountered_error: bool = ...
|
|
246
246
|
_is_running: bool = ...
|
|
247
247
|
_lock_path: str = field(init=False)
|
|
248
|
+
_started_runtime: bool = ...
|
|
248
249
|
def __post_init__(self) -> None: ...
|
|
249
250
|
def __del__(self) -> None:
|
|
250
|
-
"""If the instance
|
|
251
|
-
|
|
251
|
+
"""If the instance as used to start a runtime, ensures that the instance properly marks the runtime as completed
|
|
252
|
+
or erred before beign garbage-collected.
|
|
252
253
|
|
|
253
|
-
|
|
254
|
-
data.
|
|
254
|
+
This is a security mechanism to prevent deadlocking the processed session and pipeline for future runtimes.
|
|
255
255
|
"""
|
|
256
256
|
def _load_state(self) -> None:
|
|
257
257
|
"""Reads the current processing state from the wrapped .YAML file."""
|
|
@@ -264,7 +264,7 @@ class ProcessingTracker(YamlConfig):
|
|
|
264
264
|
with an error.
|
|
265
265
|
|
|
266
266
|
Raises:
|
|
267
|
-
TimeoutError: If the file
|
|
267
|
+
TimeoutError: If the .lock file for the target .YAML file cannot be acquired within the timeout period.
|
|
268
268
|
"""
|
|
269
269
|
def error(self) -> None:
|
|
270
270
|
"""Configures the tracker file to indicate that the tracked processing runtime encountered an error and failed
|
|
@@ -276,7 +276,7 @@ class ProcessingTracker(YamlConfig):
|
|
|
276
276
|
from the process that calls this method.
|
|
277
277
|
|
|
278
278
|
Raises:
|
|
279
|
-
TimeoutError: If the file
|
|
279
|
+
TimeoutError: If the .lock file for the target .YAML file cannot be acquired within the timeout period.
|
|
280
280
|
"""
|
|
281
281
|
def stop(self) -> None:
|
|
282
282
|
"""Configures the tracker file to indicate that the tracked processing runtime has been completed successfully.
|
|
@@ -286,7 +286,7 @@ class ProcessingTracker(YamlConfig):
|
|
|
286
286
|
at the end of the runtime.
|
|
287
287
|
|
|
288
288
|
Raises:
|
|
289
|
-
TimeoutError: If the file
|
|
289
|
+
TimeoutError: If the .lock file for the target .YAML file cannot be acquired within the timeout period.
|
|
290
290
|
"""
|
|
291
291
|
@property
|
|
292
292
|
def is_complete(self) -> bool:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""This package provides the classes and methods used by all Sun lab libraries to submit remote jobs to the BioHPC
|
|
2
|
-
and other compute servers. This package is also used across all Sun lab members private code to interface with the
|
|
2
|
+
and other compute servers. This package is also used across all Sun lab members' private code to interface with the
|
|
3
3
|
shared server."""
|
|
4
4
|
|
|
5
5
|
from .job import Job, JupyterJob
|
sl_shared_assets/server/job.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""This module provides the core Job class, used as the starting point for all SLURM-managed job executed on lab compute
|
|
2
2
|
server(s). Specifically, the Job class acts as a wrapper around the SLURM configuration and specific logic of each
|
|
3
|
-
job. During runtime, Server class interacts with input job objects to manage their transfer and execution on the
|
|
3
|
+
job. During runtime, the Server class interacts with input job objects to manage their transfer and execution on the
|
|
4
4
|
remote servers.
|
|
5
5
|
|
|
6
6
|
Since version 3.0.0, this module also provides the specialized JupyterJob class used to launch remote Jupyter
|
|
@@ -97,8 +97,8 @@ class Job:
|
|
|
97
97
|
Attributes:
|
|
98
98
|
remote_script_path: Stores the path to the script file relative to the root of the remote server that runs the
|
|
99
99
|
command.
|
|
100
|
-
job_id: Stores the unique job identifier assigned by the SLURM manager to this job
|
|
101
|
-
execution. This field initialized to None and is overwritten by the Server class that submits the job.
|
|
100
|
+
job_id: Stores the unique job identifier assigned by the SLURM manager to this job when it is accepted for
|
|
101
|
+
execution. This field is initialized to None and is overwritten by the Server class that submits the job.
|
|
102
102
|
job_name: Stores the descriptive name of the SLURM job.
|
|
103
103
|
_command: Stores the managed SLURM command object.
|
|
104
104
|
"""
|
|
@@ -174,7 +174,7 @@ class Job:
|
|
|
174
174
|
# initialization would not work as expected.
|
|
175
175
|
fixed_script_content = script_content.replace("\\$", "$")
|
|
176
176
|
|
|
177
|
-
# Returns the script content to caller as a string
|
|
177
|
+
# Returns the script content to the caller as a string
|
|
178
178
|
return fixed_script_content
|
|
179
179
|
|
|
180
180
|
|
|
@@ -202,8 +202,8 @@ class JupyterJob(Job):
|
|
|
202
202
|
conda_environment: The name of the conda environment to activate on the server before running the job logic. The
|
|
203
203
|
environment should contain the necessary Python packages and CLIs to support running the job's logic. For
|
|
204
204
|
Jupyter jobs, this necessarily includes the Jupyter notebook and jupyterlab packages.
|
|
205
|
-
port: The connection port number for Jupyter server. Do not change the default value unless you know what
|
|
206
|
-
are doing, as the server has most common communication ports closed for security reasons.
|
|
205
|
+
port: The connection port number for the Jupyter server. Do not change the default value unless you know what
|
|
206
|
+
you are doing, as the server has most common communication ports closed for security reasons.
|
|
207
207
|
notebook_directory: The directory to use as Jupyter's root. During runtime, Jupyter will only have access to
|
|
208
208
|
items stored in or under this directory. For most runtimes, this should be set to the user's root data or
|
|
209
209
|
working directory.
|
|
@@ -270,7 +270,7 @@ class JupyterJob(Job):
|
|
|
270
270
|
self._build_jupyter_command(jupyter_args)
|
|
271
271
|
|
|
272
272
|
def _build_jupyter_command(self, jupyter_args: str) -> None:
|
|
273
|
-
"""Builds the command to launch Jupyter notebook server on the remote Sun lab server."""
|
|
273
|
+
"""Builds the command to launch the Jupyter notebook server on the remote Sun lab server."""
|
|
274
274
|
|
|
275
275
|
# Gets the hostname of the compute node and caches it in the connection data file. Also caches the port name.
|
|
276
276
|
self.add_command('echo "COMPUTE_NODE: $(hostname)" > {}'.format(self.connection_info_file))
|
|
@@ -297,7 +297,7 @@ class JupyterJob(Job):
|
|
|
297
297
|
if jupyter_args:
|
|
298
298
|
jupyter_cmd.append(jupyter_args)
|
|
299
299
|
|
|
300
|
-
# Adds resolved jupyter command to the list of job commands.
|
|
300
|
+
# Adds the resolved jupyter command to the list of job commands.
|
|
301
301
|
jupyter_cmd_str = " ".join(jupyter_cmd)
|
|
302
302
|
self.add_command(jupyter_cmd_str)
|
|
303
303
|
|
|
@@ -324,7 +324,7 @@ class JupyterJob(Job):
|
|
|
324
324
|
message = f"Could not parse connection information file for the Jupyter server job with id {self.job_id}."
|
|
325
325
|
console.error(message, ValueError)
|
|
326
326
|
|
|
327
|
-
# Stores extracted data inside connection_info attribute as a JupyterConnectionInfo instance.
|
|
327
|
+
# Stores extracted data inside the connection_info attribute as a JupyterConnectionInfo instance.
|
|
328
328
|
self.connection_info = _JupyterConnectionInfo(
|
|
329
329
|
compute_node=compute_node_match.group(1).strip(), # type: ignore
|
|
330
330
|
port=int(port_match.group(1)), # type: ignore
|
|
@@ -352,7 +352,7 @@ class JupyterJob(Job):
|
|
|
352
352
|
)
|
|
353
353
|
return # No connection information available, so does not proceed with printing.
|
|
354
354
|
|
|
355
|
-
# Prints generic connection details to terminal
|
|
355
|
+
# Prints generic connection details to the terminal
|
|
356
356
|
console.echo(f"Jupyter is running on: {self.connection_info.compute_node}")
|
|
357
357
|
console.echo(f"Port: {self.connection_info.port}")
|
|
358
358
|
console.echo(f"Token: {self.connection_info.token}")
|