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

@@ -6,6 +6,7 @@ these classes contain all necessary information to restore the data hierarchy on
6
6
  libraries use these classes to work with all lab-generated data."""
7
7
 
8
8
  import copy
9
+ from enum import StrEnum
9
10
  import shutil as sh
10
11
  from pathlib import Path
11
12
  from dataclasses import field, dataclass
@@ -15,18 +16,43 @@ from ataraxis_base_utilities import LogLevel, console, ensure_directory_exists
15
16
  from ataraxis_data_structures import YamlConfig
16
17
  from ataraxis_time.time_helpers import get_timestamp
17
18
 
18
- from .configuration_data import get_system_configuration_data
19
+ from .configuration_data import AcquisitionSystems, get_system_configuration_data
19
20
 
20
- # Stores all supported input for SessionData class 'session_type' fields.
21
- _valid_session_types = {"lick training", "run training", "mesoscope experiment", "window checking"}
21
+
22
+ class SessionTypes(StrEnum):
23
+ """Defines the set of data acquisition session types supported by various data acquisition systems used in the
24
+ Sun lab.
25
+
26
+ A data acquisition session broadly encompasses a recording session carried out to either: acquire experiment data,
27
+ train the animal for the upcoming experiments, or to assess the quality of surgical or other pre-experiment
28
+ intervention.
29
+
30
+ Notes:
31
+ This enumeration does not differentiate between different acquisition systems. Different acquisition systems
32
+ support different session types, and may not be suited for acquiring some of the session types listed in this
33
+ enumeration.
34
+ """
35
+
36
+ LICK_TRAINING = "lick training"
37
+ """Mesoscope-VR session designed to teach animals to use the water delivery port while being head-fixed."""
38
+ RUN_TRAINING = "run training"
39
+ """Mesoscope-VR session designed to teach animals how to run on the treadmill while being head-fixed."""
40
+ MESOSCOPE_EXPERIMENT = "mesoscope experiment"
41
+ """Mesoscope-VR experiment session. The session uses Unity game engine to run experiments in virtual reality task
42
+ environments and collects brain activity data using Mesoscope."""
43
+ WINDOW_CHECKING = "window checking"
44
+ """A special Mesoscope-VR session designed to evaluate the suitability of the given animal to be included into the
45
+ experiment dataset. Specifically, the session involves using the Mesoscope to check the quality of the cell
46
+ activity data."""
22
47
 
23
48
 
24
49
  @dataclass()
25
50
  class RawData:
26
51
  """Stores the paths to the directories and files that make up the 'raw_data' session-specific directory.
27
52
 
28
- The raw_data directory stores the data acquired during the session runtime before and after preprocessing. Since
29
- preprocessing does not alter the data, any data in that folder is considered 'raw'.
53
+ The raw_data directory stores the data acquired during the session data acquisition runtime, before and after
54
+ preprocessing. Since preprocessing does not irreversibly alter the data, any data in that folder is considered
55
+ 'raw,' event if preprocessing losslessly re-compresses the data for efficient transfer.
30
56
 
31
57
  Notes:
32
58
  Sun lab data management strategy primarily relies on keeping multiple redundant copies of the raw_data for
@@ -43,35 +69,34 @@ class RawData:
43
69
  includes .mp4 video files from each recorded camera."""
44
70
  mesoscope_data_path: Path = Path()
45
71
  """Stores the path to the directory that contains all Mesoscope data acquired during the session. Primarily, this
46
- includes the mesoscope-acquired .tiff files (brain activity data) and the motion estimation data. This directory is
47
- created for all sessions, but is only used (filled) by the sessions that use the Mesoscope-VR system to acquire
48
- brain activity data."""
72
+ includes the mesoscope-acquired .tiff files (brain activity data) and the MotionEstimator.me file (motion
73
+ estimation data). This directory is created for all sessions, but is only used (filled) by the sessions that use
74
+ the Mesoscope-VR system to acquire brain activity data."""
49
75
  behavior_data_path: Path = Path()
50
76
  """Stores the path to the directory that contains all non-video behavior data acquired during the session.
51
77
  Primarily, this includes the .npz log files that store serialized data acquired by all hardware components of the
52
- data acquisition system other than cameras and brain activity data acquisition devices (such as the Mesoscope).
53
- The reason why the directory is called 'behavior' is primarily because all .npz files are parsed to infer the
54
- behavior of the animal, in contrast to brain (cell) activity data."""
78
+ data acquisition system other than cameras and brain activity data acquisition devices (such as the Mesoscope)."""
55
79
  zaber_positions_path: Path = Path()
56
80
  """Stores the path to the zaber_positions.yaml file. This file contains the snapshot of all Zaber motor positions
57
- at the end of the session. Zaber motors are used to position the LickPort and the HeadBar manipulators, which is
58
- essential for supporting proper brain imaging and animal's running behavior during the session. This file is only
59
- created for sessions that use the Mesoscope-VR system."""
81
+ at the end of the session. Zaber motors are used to position the LickPort, HeadBar, and Wheel Mesoscope-VR modules
82
+ to support proper brain activity recording and behavior during the session. This file is only created for sessions
83
+ that use the Mesoscope-VR system."""
60
84
  session_descriptor_path: Path = Path()
61
- """Stores the path to the session_descriptor.yaml file. This file is partially filled by the system during runtime
62
- and partially by the experimenter after the runtime. It contains session-specific information, such as the specific
63
- task parameters and the notes made by the experimenter during runtime."""
85
+ """Stores the path to the session_descriptor.yaml file. This file is filled jointly by the data acquisition system
86
+ and the experimenter. It contains session-specific information, such as the specific task parameters and the notes
87
+ made by the experimenter during runtime. Each supported session type uses a unique SessionDescriptor class to define
88
+ the format and content of the session_descriptor.yaml file."""
64
89
  hardware_state_path: Path = Path()
65
90
  """Stores the path to the hardware_state.yaml file. This file contains the partial snapshot of the calibration
66
- parameters used by the data acquisition and runtime management system modules during the session. Primarily,
67
- this is used during data processing to read the .npz data log files generated during runtime."""
91
+ parameters used by the data acquisition system modules during the session. Primarily, it is used during data
92
+ processing to interpret the raw data stored inside .npz log files."""
68
93
  surgery_metadata_path: Path = Path()
69
94
  """Stores the path to the surgery_metadata.yaml file. This file contains the most actual information about the
70
95
  surgical intervention(s) performed on the animal prior to the session."""
71
96
  session_data_path: Path = Path()
72
97
  """Stores the path to the session_data.yaml file. This path is used by the SessionData instance to save itself to
73
- disk as a .yaml file. The file contains the paths to all raw and processed data directories used during data
74
- acquisition or processing runtime."""
98
+ disk as a .yaml file. In turn, the cached data is reused to reinstate the same data hierarchy across all supported
99
+ destinations, enabling various libraries to interface with the session data."""
75
100
  experiment_configuration_path: Path = Path()
76
101
  """Stores the path to the experiment_configuration.yaml file. This file contains the snapshot of the
77
102
  experiment runtime configuration used by the session. This file is only created for experiment sessions."""
@@ -81,13 +106,13 @@ class RawData:
81
106
  the 'virtual' tip, tilt, and fastZ positions set via ScanImage software. This file is only created for sessions that
82
107
  use the Mesoscope-VR system to acquire brain activity data."""
83
108
  window_screenshot_path: Path = Path()
84
- """Stores the path to the .png screenshot of the ScanImagePC screen. The screenshot should contain the image of the
85
- cranial window and the red-dot alignment windows. This is used to generate a visual snapshot of the cranial window
86
- alignment and appearance for each experiment session. This file is only created for sessions that use the
87
- Mesoscope-VR system to acquire brain activity data."""
109
+ """Stores the path to the .png screenshot of the ScanImagePC screen. As a minimum, the screenshot should contain the
110
+ image of the imaging plane and the red-dot alignment window. This is used to generate a visual snapshot of the
111
+ cranial window alignment and cell appearance for each experiment session. This file is only created for sessions
112
+ that use the Mesoscope-VR system to acquire brain activity data."""
88
113
  system_configuration_path: Path = Path()
89
114
  """Stores the path to the system_configuration.yaml file. This file contains the exact snapshot of the data
90
- acquisition and runtime management system configuration parameters used to acquire session data."""
115
+ acquisition system configuration parameters used to acquire session data."""
91
116
  checksum_path: Path = Path()
92
117
  """Stores the path to the ax_checksum.txt file. This file is generated as part of packaging the data for
93
118
  transmission and stores the xxHash-128 checksum of the data. It is used to verify that the transmission did not
@@ -98,18 +123,16 @@ class RawData:
98
123
  telomere.bin file are considered 'incomplete' and are excluded from all automated processing, as they may contain
99
124
  corrupted, incomplete, or otherwise unusable data."""
100
125
  ubiquitin_path: Path = Path()
101
- """Stores the path to the ubiquitin.bin file. This file is primarily used by the sl-experiment libraries to mark
126
+ """Stores the path to the ubiquitin.bin file. This file is primarily used by the sl-experiment library to mark
102
127
  local session data directories for deletion (purging). Typically, it is created once the data is safely moved to
103
128
  the long-term storage destinations (NAS and Server) and the integrity of the moved data is verified on at least one
104
- destination. During 'purge' sl-experiment runtimes, the library discovers and removes all session data marked with
105
- 'ubiquitin.bin' files from the machine that runs the code."""
129
+ destination. During 'sl-purge' sl-experiment runtimes, the library discovers and removes all session data marked
130
+ with 'ubiquitin.bin' files from the machine that runs the command."""
106
131
  nk_path: Path = Path()
107
- """Stores the path to the nk.bin file. This file is used during new data acquisition by the sl-experiment library
108
- to mark sessions going through initial runtime initialization. Since runtime initialization is a complex process
109
- that may fail at many different time-points, it is important to know whether the runtime initialized before
110
- encountering an error. The presence of an nk.bin marker notifies post-runtime processes that the runtime failed to
111
- initialize, marking that session's data for immediate deletion from all sources, as it does not contain any valid
112
- information."""
132
+ """Stores the path to the nk.bin file. This file is used by the sl-experiment library to mark sessions undergoing
133
+ runtime initialization. Since runtime initialization is a complex process that may encounter a runtime error, the
134
+ marker is used to discover sessions that failed to initialize. Since uninitialized sessions by definition do not
135
+ contain any valuable data, they are marked for immediate deletion from all managed destinations."""
113
136
  integrity_verification_tracker_path: Path = Path()
114
137
  """Stores the path to the integrity_verification.yaml tracker file. This file stores the current state of the data
115
138
  integrity verification pipeline. It prevents more than one instance of the pipeline from working with the data
@@ -118,13 +141,12 @@ class RawData:
118
141
  def resolve_paths(self, root_directory_path: Path) -> None:
119
142
  """Resolves all paths managed by the class instance based on the input root directory path.
120
143
 
121
- This method is called each time the class is instantiated to regenerate the managed path hierarchy on any
122
- machine that instantiates the class.
144
+ This method is called each time the (wrapper) SessionData class is instantiated to regenerate the managed path
145
+ hierarchy on any machine that instantiates the class.
123
146
 
124
147
  Args:
125
- root_directory_path: The path to the top-level directory of the local hierarchy. Depending on the managed
126
- hierarchy, this has to point to a directory under the main /session, /animal, or /project directory of
127
- the managed session.
148
+ root_directory_path: The path to the top-level directory of the session. Typically, this path is assembled
149
+ using the following hierarchy: root/project/animal/session_id
128
150
  """
129
151
 
130
152
  # Generates the managed paths
@@ -148,7 +170,11 @@ class RawData:
148
170
  self.integrity_verification_tracker_path = self.raw_data_path.joinpath("integrity_verification_tracker.yaml")
149
171
 
150
172
  def make_directories(self) -> None:
151
- """Ensures that all major subdirectories and the root directory exist, creating any missing directories."""
173
+ """Ensures that all major subdirectories and the root directory exist, creating any missing directories.
174
+
175
+ This method is called each time the (wrapper) SessionData class is instantiated and allowed to generate
176
+ missing data directories.
177
+ """
152
178
  ensure_directory_exists(self.raw_data_path)
153
179
  ensure_directory_exists(self.camera_data_path)
154
180
  ensure_directory_exists(self.mesoscope_data_path)
@@ -165,30 +191,30 @@ class ProcessedData:
165
191
  """
166
192
 
167
193
  processed_data_path: Path = Path()
168
- """Stores the path to the root processed_data directory of the session. This directory stores the processed data
169
- as it is generated by various data processing pipelines."""
194
+ """Stores the path to the root processed_data directory of the session. This directory stores the processed session
195
+ data, generated from raw_data directory contents by various data processing pipelines."""
170
196
  camera_data_path: Path = Path()
171
- """Stores the path to the directory that contains video tracking data generated by our DeepLabCut-based video
172
- processing pipelines."""
197
+ """Stores the path to the directory that contains video tracking data generated by the Sun lab DeepLabCut-based
198
+ video processing pipeline(s)."""
173
199
  mesoscope_data_path: Path = Path()
174
- """Stores path to the directory that contains processed brain activity (cell) data generated by our suite2p-based
175
- photometry processing pipelines (single-day and multi-day). This directory is only used by sessions acquired with
176
- the Mesoscope-VR system. For all other sessions, it will be created, but kept empty."""
200
+ """Stores path to the directory that contains processed brain activity (cell) data generated by sl-suite2p
201
+ processing pipelines (single-day and multi-day). This directory is only used by sessions acquired with
202
+ the Mesoscope-VR system."""
177
203
  behavior_data_path: Path = Path()
178
204
  """Stores the path to the directory that contains the non-video and non-brain-activity data extracted from
179
- .npz log files by our in-house log parsing pipeline."""
205
+ .npz log files by the sl-behavior log processing pipeline."""
180
206
  suite2p_processing_tracker_path: Path = Path()
181
- """Stores the path to the suite2p_processing_tracker.yaml tracker file. This file stores the current state of the
182
- sl-suite2p single-day data processing pipeline."""
207
+ """Stores the path to the suite2p_processing_tracker.yaml tracker file. This file stores the current state of
208
+ processing the session with the sl-suite2p single-day pipeline."""
183
209
  behavior_processing_tracker_path: Path = Path()
184
- """Stores the path to the behavior_processing_tracker.yaml file. This file stores the current state of the
185
- behavior (log) data processing pipeline."""
210
+ """Stores the path to the behavior_processing_tracker.yaml file. This file stores the current state of processing
211
+ the session with the sl-behavior log-parsing pipeline."""
186
212
  video_processing_tracker_path: Path = Path()
187
- """Stores the path to the video_processing_tracker.yaml file. This file stores the current state of the video
188
- tracking (DeepLabCut) processing pipeline."""
213
+ """Stores the path to the video_processing_tracker.yaml file. This file stores the current state of processing
214
+ the session with the DeepLabCut-based video processing pipeline."""
189
215
  p53_path: Path = Path()
190
216
  """Stores the path to the p53.bin file. This file serves as a lock-in marker that determines whether the session is
191
- in the processing or dataset mode. Specifically, if the file does not exist, the session data cannot be integrated
217
+ in the processing or dataset state. Specifically, if the file does not exist, the session data cannot be integrated
192
218
  into any dataset, as it may be actively worked on by processing pipelines. Conversely, if the marker exists,
193
219
  processing pipelines are not allowed to work with the session, as it may be actively integrated into one or more
194
220
  datasets."""
@@ -196,13 +222,12 @@ class ProcessedData:
196
222
  def resolve_paths(self, root_directory_path: Path) -> None:
197
223
  """Resolves all paths managed by the class instance based on the input root directory path.
198
224
 
199
- This method is called each time the class is instantiated to regenerate the managed path hierarchy on any
200
- machine that instantiates the class.
225
+ This method is called each time the (wrapper) SessionData class is instantiated to regenerate the managed path
226
+ hierarchy on any machine that instantiates the class.
201
227
 
202
228
  Args:
203
- root_directory_path: The path to the top-level directory of the local hierarchy. Depending on the managed
204
- hierarchy, this has to point to a directory under the main /session, /animal, or /project directory of
205
- the managed session.
229
+ root_directory_path: The path to the top-level directory of the session. Typically, this path is assembled
230
+ using the following hierarchy: root/project/animal/session_id
206
231
  """
207
232
  # Generates the managed paths
208
233
  self.processed_data_path = root_directory_path
@@ -215,7 +240,11 @@ class ProcessedData:
215
240
  self.p53_path = self.processed_data_path.joinpath("p53.bin")
216
241
 
217
242
  def make_directories(self) -> None:
218
- """Ensures that all major subdirectories and the root directory exist, creating any missing directories."""
243
+ """Ensures that all major subdirectories and the root directory exist, creating any missing directories.
244
+
245
+ This method is called each time the (wrapper) SessionData class is instantiated and allowed to generate
246
+ missing data directories.
247
+ """
219
248
 
220
249
  ensure_directory_exists(self.processed_data_path)
221
250
  ensure_directory_exists(self.camera_data_path)
@@ -224,54 +253,51 @@ class ProcessedData:
224
253
 
225
254
  @dataclass
226
255
  class SessionData(YamlConfig):
227
- """Stores and manages the data layout of a single training or experiment session acquired in the Sun lab.
228
-
229
- The primary purpose of this class is to maintain the session data structure across all supported destinations and
230
- during all processing stages. It generates the paths used by all other classes from all Sun lab libraries that
231
- interact with the session's data from the point of its creation and until the data is integrated into an
232
- analysis dataset.
256
+ """Stores and manages the data layout of a single Sun lab data acquisition session.
233
257
 
234
- When necessary, the class can be used to either generate a new session or load the layout of an already existing
235
- session. When the class is used to create a new session, it generates the new session's name using the current
236
- UTC timestamp, accurate to microseconds. This ensures that each session name is unique and preserves the overall
237
- session order.
258
+ The primary purpose of this class is to maintain the session data structure across all supported destinations and to
259
+ provide a unified data access interface shared by all Sun lab libraries. The class can be used to either generate a
260
+ new session or load the layout of an already existing session. When the class is used to create a new session, it
261
+ generates the new session's name using the current UTC timestamp, accurate to microseconds. This ensures that each
262
+ session 'name' is unique and preserves the overall session order.
238
263
 
239
264
  Notes:
240
265
  This class is specifically designed for working with the data from a single session, performed by a single
241
266
  animal under the specific experiment. The class is used to manage both raw and processed data. It follows the
242
- data through acquisition, preprocessing and processing stages of the Sun lab data workflow. Together with
243
- ProjectConfiguration class, this class serves as an entry point for all interactions with the managed session's
244
- data.
267
+ data through acquisition, preprocessing and processing stages of the Sun lab data workflow. This class serves as
268
+ an entry point for all interactions with the managed session's data.
245
269
  """
246
270
 
247
271
  project_name: str
248
- """Stores the name of the managed session's project."""
272
+ """Stores the name of the project for which the session was acquired."""
249
273
  animal_id: str
250
- """Stores the unique identifier of the animal that participates in the managed session."""
274
+ """Stores the unique identifier of the animal that participates in the session."""
251
275
  session_name: str
252
- """Stores the name (timestamp-based ID) of the managed session."""
253
- session_type: str
254
- """Stores the type of the session. Primarily, this determines how to read the session_descriptor.yaml file. Has
255
- to be set to one of the supported types: 'lick training', 'run training', 'window checking' or
256
- 'mesoscope experiment'.
276
+ """Stores the name (timestamp-based ID) of the session."""
277
+ session_type: str | SessionTypes
278
+ """Stores the type of the session. Has to be set to one of the supported session types, defined in the SessionTypes
279
+ enumeration exposed by the sl-shared-assets library.
257
280
  """
258
- acquisition_system: str
259
- """Stores the name of the data acquisition and runtime management system that acquired the data."""
281
+ acquisition_system: str | AcquisitionSystems
282
+ """Stores the name of the data acquisition system that acquired the data. Has to be set to one of the supported
283
+ acquisition systems, defined in the AcquisitionSystems enumeration exposed by the sl-shared-assets library."""
260
284
  experiment_name: str | None
261
- """Stores the name of the experiment configuration file. If the session_type field is set to 'Experiment' and this
262
- field is not None (null), it communicates the specific experiment configuration used by the session. During runtime,
263
- the name stored here is used to load the specific experiment configuration data stored in a .yaml file with the
264
- same name. If the session is not an experiment session, this field is ignored."""
285
+ """Stores the name of the experiment performed during the session. If the session_type field indicates that the
286
+ session is an experiment, this field communicates the specific experiment configuration used by the session. During
287
+ runtime, this name is used to load the specific experiment configuration data stored in a .yaml file with the same
288
+ name. If the session is not an experiment session, this field should be left as Null (None)."""
265
289
  python_version: str = "3.11.13"
266
- """Stores the Python version used to acquire raw session data."""
290
+ """Stores the Python version that was used to acquire session data."""
267
291
  sl_experiment_version: str = "2.0.0"
268
- """Stores the version of the sl-experiment library that was used to acquire the raw session data."""
292
+ """Stores the version of the sl-experiment library that was used to acquire the session data."""
269
293
  raw_data: RawData = field(default_factory=lambda: RawData())
270
- """Stores the paths to all subfolders and files found under the /project/animal/session/raw_data directory of any
271
- PC used to work with Sun lab data."""
294
+ """Stores absolute paths to all directories and files that jointly make the session's raw data hierarchy. This
295
+ directory structure is resolved for each machine that creates or loads the SessionData class to ensure that all
296
+ Sun lab data can be accessed via the same API on any destination."""
272
297
  processed_data: ProcessedData = field(default_factory=lambda: ProcessedData())
273
- """Stores the paths to all subfolders and files found under the /project/animal/session/processed_data directory of
274
- any PC used to work with Sun lab data."""
298
+ """Stores absolute paths to all directories and files that jointly make the session's processed data hierarchy.
299
+ Typically, this hierarchy is only used on the lab's processing server(s), but it can also be used to run local
300
+ testing on end-user machines."""
275
301
 
276
302
  def __post_init__(self) -> None:
277
303
  """Ensures raw_data and processed_data are always instances of RawData and ProcessedData."""
@@ -286,7 +312,7 @@ class SessionData(YamlConfig):
286
312
  cls,
287
313
  project_name: str,
288
314
  animal_id: str,
289
- session_type: str,
315
+ session_type: SessionTypes | str,
290
316
  experiment_name: str | None = None,
291
317
  session_name: str | None = None,
292
318
  python_version: str = "3.11.13",
@@ -301,35 +327,37 @@ class SessionData(YamlConfig):
301
327
  To load an already existing session data structure, use the load() method instead.
302
328
 
303
329
  This method automatically dumps the data of the created SessionData instance into the session_data.yaml file
304
- inside the root raw_data directory of the created hierarchy. It also finds and dumps other configuration
305
- files, such as experiment_configuration.yaml and system_configuration.yaml into the same raw_data directory.
306
- This ensures that if the session's runtime is interrupted unexpectedly, the acquired data can still be
307
- processed.
330
+ inside the root 'raw_data' directory of the created hierarchy. It also finds and dumps other configuration
331
+ files, such as experiment_configuration.yaml and system_configuration.yaml into the same 'raw_data'
332
+ directory. If the session's runtime is interrupted unexpectedly, the acquired data can still be processed
333
+ using these pre-saved class instances.
308
334
 
309
335
  Args:
310
- project_name: The name of the project for which the data is acquired.
311
- animal_id: The ID code of the animal for which the data is acquired.
312
- session_type: The type of the session. Primarily, this determines how to read the session_descriptor.yaml
313
- file. Valid options are 'Lick training', 'Run training', 'Window checking', or 'Experiment'.
314
- experiment_name: The name of the experiment executed during managed session. This optional argument is only
315
- used for 'Experiment' session types. It is used to find the experiment configuration .YAML file.
316
- session_name: An optional session_name override. Generally, this argument should not be provided for most
336
+ project_name: The name of the project for which the session is carried out.
337
+ animal_id: The ID code of the animal participating in the session.
338
+ session_type: The type of the session. Has to be one of the supported session types exposed by the
339
+ SessionTypes enumeration.
340
+ experiment_name: The name of the experiment executed during the session. This optional argument is only
341
+ used for experiment sessions. Note! The name passed to this argument has to match the name of the
342
+ experiment configuration .yaml file.
343
+ session_name: An optional session name override. Generally, this argument should not be provided for most
317
344
  sessions. When provided, the method uses this name instead of generating a new timestamp-based name.
318
345
  This is only used during the 'ascension' runtime to convert old data structures to the modern
319
346
  lab standards.
320
- python_version: The string that specifies the Python version used to collect raw session data. Has to be
347
+ python_version: The string that specifies the Python version used to collect session data. Has to be
321
348
  specified using the major.minor.patch version format.
322
349
  sl_experiment_version: The string that specifies the version of the sl-experiment library used to collect
323
- raw session data. Has to be specified using the major.minor.patch version format.
350
+ session data. Has to be specified using the major.minor.patch version format.
324
351
 
325
352
  Returns:
326
353
  An initialized SessionData instance that stores the layout of the newly created session's data.
327
354
  """
328
355
 
329
- if session_type.lower() not in _valid_session_types:
356
+ # Need to convert to tuple to support Python 3.11
357
+ if session_type not in tuple(SessionTypes):
330
358
  message = (
331
- f"Invalid session type '{session_type.lower()}' encountered when creating a new SessionData instance. "
332
- f"Use one of the supported session types: {_valid_session_types}"
359
+ f"Invalid session type '{session_type}' encountered when creating a new SessionData instance. "
360
+ f"Use one of the supported session types from the SessionTypes enumeration."
333
361
  )
334
362
  console.error(message=message, error=ValueError)
335
363
 
@@ -388,7 +416,7 @@ class SessionData(YamlConfig):
388
416
  project_name=project_name,
389
417
  animal_id=animal_id,
390
418
  session_name=session_name,
391
- session_type=session_type.lower(),
419
+ session_type=session_type,
392
420
  acquisition_system=acquisition_system.name,
393
421
  raw_data=raw_data,
394
422
  processed_data=processed_data,
@@ -432,9 +460,9 @@ class SessionData(YamlConfig):
432
460
  """Loads the SessionData instance from the target session's session_data.yaml file.
433
461
 
434
462
  This method is used to load the data layout information of an already existing session. Primarily, this is used
435
- when preprocessing or processing session data. Due to how SessionData is stored and used in the lab, this
436
- method always loads the data layout from the session_data.yaml file stored inside the raw_data session
437
- subfolder. Currently, all interactions with Sun lab data require access to the 'raw_data' folder.
463
+ when processing session data. Due to how SessionData is stored and used in the lab, this method always loads the
464
+ data layout from the session_data.yaml file stored inside the 'raw_data' session subfolder. Currently, all
465
+ interactions with Sun lab data require access to the 'raw_data' folder of each session.
438
466
 
439
467
  Notes:
440
468
  To create a new session, use the create() method instead.
@@ -498,19 +526,19 @@ class SessionData(YamlConfig):
498
526
  # Returns the initialized SessionData instance to caller
499
527
  return instance
500
528
 
501
- def mark_initialization(self) -> None:
502
- """Ensures that the 'nk.bin' marker file is removed from the session's raw_dat folder.
529
+ def runtime_initialized(self) -> None:
530
+ """Ensures that the 'nk.bin' marker file is removed from the session's raw_data folder.
503
531
 
504
- This marker is generated as part of the SessionData initialization (creation) process to mark sessions that did
505
- not fully initialize during runtime. Call this method after fully initializing the data acquisition runtime
506
- control class to ensure that the session is not marker for automated deletion upon runtime completion.
532
+ The 'nk.bin' marker is generated as part of the SessionData initialization (creation) process to mark sessions
533
+ that did not fully initialize during runtime. This service method is designed to be called by the sl-experiment
534
+ library classes to remove the 'nk.bin' marker when it is safe to do so. It should not be called by end-users.
507
535
  """
508
536
  self.raw_data.nk_path.unlink(missing_ok=True)
509
537
 
510
538
  def _save(self) -> None:
511
539
  """Saves the instance data to the 'raw_data' directory of the managed session as a 'session_data.yaml' file.
512
540
 
513
- This is used to save the data stored in the instance to disk, so that it can be reused during preprocessing or
541
+ This is used to save the data stored in the instance to disk, so that it can be reused during further stages of
514
542
  data processing. The method is intended to only be used by the SessionData instance itself during its
515
543
  create() method runtime.
516
544
  """
@@ -561,6 +589,16 @@ class ProcessingTracker(YamlConfig):
561
589
  else:
562
590
  self._lock_path = ""
563
591
 
592
+ def __del__(self) -> None:
593
+ """If the instance is garbage-collected without calling the stop() method, assumes this is due to a runtime
594
+ error.
595
+
596
+ It is essential to always resolve the runtime as either 'stopped' or 'erred' to avoid deadlocking the session
597
+ data.
598
+ """
599
+ if self._is_running:
600
+ self.error()
601
+
564
602
  def _load_state(self) -> None:
565
603
  """Reads the current processing state from the wrapped .YAML file."""
566
604
  if self.file_path.exists():
@@ -671,7 +709,11 @@ class ProcessingTracker(YamlConfig):
671
709
  raise Timeout(message) # Fallback to appease mypy, should not be reachable
672
710
 
673
711
  def stop(self) -> None:
674
- """Mark processing as started.
712
+ """Configures the tracker file to indicate that the tracked processing runtime has been completed successfully.
713
+
714
+ After this method returns, it is UNSAFE to do any further processing from the process that calls this method.
715
+ Any process that calls the 'start' method of this class is expected to also call this method or 'error' method
716
+ at the end of the runtime.
675
717
 
676
718
  Raises:
677
719
  TimeoutError: If the file lock for the target .YAML file cannot be acquired within the timeout period.
@@ -713,7 +755,7 @@ class ProcessingTracker(YamlConfig):
713
755
  @property
714
756
  def is_complete(self) -> bool:
715
757
  """Returns True if the tracker wrapped by the instance indicates that the processing runtime has been completed
716
- successfully and False otherwise."""
758
+ successfully at least once and that there is no ongoing processing that uses the target session."""
717
759
  try:
718
760
  # Acquires the lock
719
761
  lock = FileLock(self._lock_path)
@@ -734,8 +776,8 @@ class ProcessingTracker(YamlConfig):
734
776
 
735
777
  @property
736
778
  def encountered_error(self) -> bool:
737
- """Returns True if the tracker wrapped by the instance indicates that the processing runtime aborted due to
738
- encountering an error and False otherwise."""
779
+ """Returns True if the tracker wrapped by the instance indicates that the processing runtime for the target
780
+ session has aborted due to encountering an error."""
739
781
  try:
740
782
  # Acquires the lock
741
783
  lock = FileLock(self._lock_path)
@@ -757,7 +799,7 @@ class ProcessingTracker(YamlConfig):
757
799
  @property
758
800
  def is_running(self) -> bool:
759
801
  """Returns True if the tracker wrapped by the instance indicates that the processing runtime is currently
760
- running and False otherwise."""
802
+ running for the target session."""
761
803
  try:
762
804
  # Acquires the lock
763
805
  lock = FileLock(self._lock_path)