sl-shared-assets 3.0.0rc14__py3-none-any.whl → 3.1.0__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.

Files changed (30) hide show
  1. sl_shared_assets/__init__.py +2 -0
  2. sl_shared_assets/__init__.pyi +2 -0
  3. sl_shared_assets/cli.py +38 -14
  4. sl_shared_assets/cli.pyi +11 -11
  5. sl_shared_assets/data_classes/__init__.py +2 -2
  6. sl_shared_assets/data_classes/configuration_data.py +11 -8
  7. sl_shared_assets/data_classes/configuration_data.pyi +8 -7
  8. sl_shared_assets/data_classes/runtime_data.py +2 -2
  9. sl_shared_assets/data_classes/runtime_data.pyi +2 -2
  10. sl_shared_assets/data_classes/session_data.py +43 -29
  11. sl_shared_assets/data_classes/session_data.pyi +11 -11
  12. sl_shared_assets/server/__init__.py +1 -1
  13. sl_shared_assets/server/job.py +10 -10
  14. sl_shared_assets/server/job.pyi +5 -5
  15. sl_shared_assets/server/server.py +15 -15
  16. sl_shared_assets/server/server.pyi +7 -7
  17. sl_shared_assets/tools/__init__.py +7 -1
  18. sl_shared_assets/tools/__init__.pyi +2 -0
  19. sl_shared_assets/tools/ascension_tools.py +8 -8
  20. sl_shared_assets/tools/packaging_tools.py +2 -1
  21. sl_shared_assets/tools/project_management_tools.py +87 -41
  22. sl_shared_assets/tools/project_management_tools.pyi +23 -11
  23. sl_shared_assets/tools/transfer_tools.py +1 -1
  24. sl_shared_assets/tools/transfer_tools.pyi +1 -1
  25. {sl_shared_assets-3.0.0rc14.dist-info → sl_shared_assets-3.1.0.dist-info}/METADATA +122 -5
  26. sl_shared_assets-3.1.0.dist-info/RECORD +36 -0
  27. sl_shared_assets-3.0.0rc14.dist-info/RECORD +0 -36
  28. {sl_shared_assets-3.0.0rc14.dist-info → sl_shared_assets-3.1.0.dist-info}/WHEEL +0 -0
  29. {sl_shared_assets-3.0.0rc14.dist-info → sl_shared_assets-3.1.0.dist-info}/entry_points.txt +0 -0
  30. {sl_shared_assets-3.0.0rc14.dist-info → sl_shared_assets-3.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -11,15 +11,15 @@ from ataraxis_base_utilities import console
11
11
 
12
12
  from ..data_classes import (
13
13
  SessionData,
14
+ SessionTypes,
14
15
  ProcessingTracker,
15
16
  RunTrainingDescriptor,
16
17
  LickTrainingDescriptor,
18
+ WindowCheckingDescriptor,
17
19
  MesoscopeExperimentDescriptor,
18
20
  )
19
21
  from .packaging_tools import calculate_directory_checksum
20
22
 
21
- _valid_session_types = {"lick training", "run training", "mesoscope experiment", "window checking"}
22
-
23
23
 
24
24
  class ProjectManifest:
25
25
  """Wraps the contents of a Sun lab project manifest .feather file and exposes methods for visualizing and
@@ -220,8 +220,7 @@ class ProjectManifest:
220
220
 
221
221
  Returns:
222
222
  A Polars DataFrame with the following columns: 'animal', 'date', 'notes', 'session', 'type', 'complete',
223
- 'intensity_verification', 'suite2p', 'behavior', 'video',
224
- 'dataset'.
223
+ 'intensity_verification', 'suite2p', 'behavior', 'video', 'dataset'.
225
224
  """
226
225
 
227
226
  df = self._data
@@ -330,23 +329,31 @@ def generate_project_manifest(
330
329
 
331
330
  # Depending on the session type, instantiates the appropriate descriptor instance and uses it to read the
332
331
  # experimenter notes
333
- if session_data.session_type == "lick training":
332
+ if session_data.session_type == SessionTypes.LICK_TRAINING:
334
333
  descriptor: LickTrainingDescriptor = LickTrainingDescriptor.from_yaml( # type: ignore
335
334
  file_path=session_data.raw_data.session_descriptor_path
336
335
  )
337
336
  manifest["notes"].append(descriptor.experimenter_notes)
338
- elif session_data.session_type == "run training":
337
+ elif session_data.session_type == SessionTypes.RUN_TRAINING:
339
338
  descriptor: RunTrainingDescriptor = RunTrainingDescriptor.from_yaml( # type: ignore
340
339
  file_path=session_data.raw_data.session_descriptor_path
341
340
  )
342
341
  manifest["notes"].append(descriptor.experimenter_notes)
343
- elif session_data.session_type == "mesoscope experiment":
342
+ elif session_data.session_type == SessionTypes.MESOSCOPE_EXPERIMENT:
344
343
  descriptor: MesoscopeExperimentDescriptor = MesoscopeExperimentDescriptor.from_yaml( # type: ignore
345
344
  file_path=session_data.raw_data.session_descriptor_path
346
345
  )
347
346
  manifest["notes"].append(descriptor.experimenter_notes)
348
- elif session_data.session_type == "window checking":
349
- manifest["notes"].append("N/A")
347
+ elif session_data.session_type == SessionTypes.WINDOW_CHECKING:
348
+ # sl-experiment version 3.0.0 added session descriptors to Window Checking runtimes. Since the file does not
349
+ # exist in prior versions, this section is written to statically handle the discrepancy.
350
+ try:
351
+ descriptor: WindowCheckingDescriptor = WindowCheckingDescriptor.from_yaml( # type: ignore
352
+ file_path=session_data.raw_data.session_descriptor_path
353
+ )
354
+ manifest["notes"].append(descriptor.experimenter_notes)
355
+ except Exception:
356
+ manifest["notes"].append("N/A")
350
357
 
351
358
  # If the session raw_data folder contains the telomere.bin file, marks the session as complete.
352
359
  manifest["complete"].append(session_data.raw_data.telomere_path.exists())
@@ -377,9 +384,7 @@ def generate_project_manifest(
377
384
  tracker = ProcessingTracker(file_path=session_data.processed_data.video_processing_tracker_path)
378
385
  manifest["video"].append(tracker.is_complete)
379
386
 
380
- # Tracks whether the session's data is ready for dataset integration. To be considered ready, the data must be
381
- # successfully processed with all relevant pipelines. Any session currently being processed with any processing
382
- # pipeline is considered NOT ready.
387
+ # Tracks whether the session's data is currently in the processing or dataset integration mode.
383
388
  manifest["dataset"].append(session_data.processed_data.p53_path.exists())
384
389
 
385
390
  # If all animal IDs are integer-convertible, stores them as numbers to promote proper sorting. Otherwise, stores
@@ -419,7 +424,10 @@ def generate_project_manifest(
419
424
 
420
425
 
421
426
  def verify_session_checksum(
422
- session_path: Path, create_processed_data_directory: bool = True, processed_data_root: None | Path = None
427
+ session_path: Path,
428
+ create_processed_data_directory: bool = True,
429
+ processed_data_root: None | Path = None,
430
+ update_manifest: bool = False,
423
431
  ) -> None:
424
432
  """Verifies the integrity of the session's raw data by generating the checksum of the raw_data directory and
425
433
  comparing it against the checksum stored in the ax_checksum.txt file.
@@ -435,6 +443,9 @@ def verify_session_checksum(
435
443
  This function is also used to create the processed data hierarchy on the BioHPC server, when it is called as
436
444
  part of the data preprocessing runtime performed by a data acquisition system.
437
445
 
446
+ Since version 3.1.0, this functon also supports (re) generating the processed session's project manifest file,
447
+ which is used to support further Sun lab data processing pipelines.
448
+
438
449
  Args:
439
450
  session_path: The path to the session directory to be verified. Note, the input session directory must contain
440
451
  the 'raw_data' subdirectory.
@@ -442,6 +453,9 @@ def verify_session_checksum(
442
453
  processed_data_root: The root directory where to store the processed data hierarchy. This path has to point to
443
454
  the root directory where to store the processed data from all projects, and it will be automatically
444
455
  modified to include the project name, the animal name, and the session ID.
456
+ update_manifest: Determines whether to update (regenerate) the project manifest file for the processed session's
457
+ project. This should always be enabled when working with remote compute server(s) to ensure that the
458
+ project manifest file contains the most actual snapshot of the project's state.
445
459
  """
446
460
 
447
461
  # Loads session data layout. If configured to do so, also creates the processed data hierarchy
@@ -487,12 +501,33 @@ def verify_session_checksum(
487
501
  if tracker.is_running:
488
502
  tracker.error()
489
503
 
504
+ # If the runtime is configured to generate the project manifest file, attempts to generate and overwrite the
505
+ # existing manifest file for the target project.
506
+ if update_manifest:
507
+ # All sessions are stored under root/project/animal/session. Therefore, the grandparent of the session is
508
+ # the raw project directory.
509
+ raw_directory = session_path.parents[1]
510
+
511
+ # Depending on the processed_data_root configuration, determines the path for the project's processed
512
+ # data directory.
513
+ processed_directory: Path | None = None
514
+ if processed_data_root is not None:
515
+ processed_directory = processed_data_root.joinpath(session_data.project_name)
516
+
517
+ # Generates the manifest file inside the root raw data project directory
518
+ generate_project_manifest(
519
+ raw_project_directory=session_path.parents[1],
520
+ processed_project_directory=processed_directory,
521
+ output_directory=raw_directory,
522
+ )
523
+
490
524
 
491
525
  def resolve_p53_marker(
492
526
  session_path: Path,
493
527
  create_processed_data_directory: bool = True,
494
528
  processed_data_root: None | Path = None,
495
529
  remove: bool = False,
530
+ update_manifest: bool = False,
496
531
  ) -> None:
497
532
  """Depending on configuration, either creates or removes the p53.bin marker file for the target session.
498
533
 
@@ -504,11 +539,12 @@ def resolve_p53_marker(
504
539
  from altering the data while it is integrated into a dataset. The p53.bin marker solves this issue by ensuring
505
540
  that only one type of runtimes (processing or dataset integration) is allowed to work with the session.
506
541
 
507
- For the p53.bin marker to be created, the session must currently not undergo any processing and must be
508
- successfully processed with the minimal set of pipelines for its session type. Removing the p53.bin marker does
509
- not have any dependencies and will be executed even if the session is currently undergoing dataset integration.
510
- Due to this limitation, it is only possible to call this function with the 'remove' flag manually (via the
511
- dedicated CLI).
542
+ For the p53.bin marker to be created, the session must currently not undergo any processing. Removing the
543
+ p53.bin marker does not have any dependencies and will be executed even if the session is currently undergoing
544
+ dataset integration. This is due to data access hierarchy limitations of the Sun lab compute server.
545
+
546
+ Since version 3.1.0, this functon also supports (re)generating the processed session's project manifest file,
547
+ which is used to support further Sun lab data processing pipelines.
512
548
 
513
549
  Args:
514
550
  session_path: The path to the session directory for which the p53.bin marker needs to be resolved. Note, the
@@ -518,6 +554,9 @@ def resolve_p53_marker(
518
554
  the root directory where to store the processed data from all projects, and it will be automatically
519
555
  modified to include the project name, the animal name, and the session ID.
520
556
  remove: Determines whether this function is called to create or remove the p53.bin marker.
557
+ update_manifest: Determines whether to update (regenerate) the project manifest file for the processed session's
558
+ project. This should always be enabled when working with remote compute server(s) to ensure that the
559
+ project manifest file contains the most actual snapshot of the project's state.
521
560
  """
522
561
 
523
562
  # Loads session data layout. If configured to do so, also creates the processed data hierarchy
@@ -528,7 +567,7 @@ def resolve_p53_marker(
528
567
  )
529
568
 
530
569
  # If the p53.bin marker exists and the runtime is configured to remove it, removes the marker file. If the runtime
531
- # is configured to create the marker, aborts the runtime (as the marker already exists).
570
+ # is configured to create the marker, the method aborts the runtime (as the marker already exists).
532
571
  if session_data.processed_data.p53_path.exists():
533
572
  if remove:
534
573
  session_data.processed_data.p53_path.unlink()
@@ -544,43 +583,50 @@ def resolve_p53_marker(
544
583
  # Queries the type of the processed session
545
584
  session_type = session_data.session_type
546
585
 
547
- # If the session type is not supported, aborts with an error
548
- if session_type not in _valid_session_types:
549
- message = (
550
- f"Unable to determine the mandatory processing pipelines for session {session_data.session_name} of animal "
551
- f"{session_data.animal_id} and project {session_data.processed_data}. The type of the session "
552
- f"{session_type} is not one of the supported session types: {', '.join(_valid_session_types)}."
553
- )
554
- console.error(message=message, error=ValueError)
555
-
556
- # Window checking sessions are not designed to be integrated into datasets, so they cannot be marked with p53.bin
557
- # file. Similarly, any incomplete session is automatically excluded from dataset formation.
558
- if session_type == "window checking" or not session_data.raw_data.telomere_path.exists():
586
+ # Window checking sessions are not designed to be integrated into datasets, so they cannot be marked with the
587
+ # p53.bin file. Similarly, any incomplete session is automatically excluded from dataset formation.
588
+ if session_type == SessionTypes.WINDOW_CHECKING or not session_data.raw_data.telomere_path.exists():
559
589
  return
560
590
 
561
591
  # Training sessions collect similar data and share processing pipeline requirements
562
- if session_type == "lick training" or session_type == "run training":
563
- # If the session has not been successfully processed with the behavior processing pipeline, aborts without
564
- # creating the marker file. Also ensures that the video tracking pipeline is not actively running, although it
565
- # is not required
592
+ if session_type == SessionTypes.LICK_TRAINING or session_type == SessionTypes.RUN_TRAINING:
593
+ # Ensures that the session is not being processed with one of the supported pipelines.
566
594
  behavior_tracker = ProcessingTracker(file_path=session_data.processed_data.behavior_processing_tracker_path)
567
595
  video_tracker = ProcessingTracker(file_path=session_data.processed_data.video_processing_tracker_path)
568
- if not behavior_tracker.is_complete or video_tracker.is_running:
596
+ if behavior_tracker.is_running or video_tracker.is_running:
569
597
  # Note, training runtimes do not require suite2p processing.
570
598
  return
571
599
 
572
600
  # Mesoscope experiment sessions require additional processing with suite2p
573
- if session_type == "mesoscope experiment":
601
+ if session_type == SessionTypes.MESOSCOPE_EXPERIMENT:
574
602
  behavior_tracker = ProcessingTracker(file_path=session_data.processed_data.behavior_processing_tracker_path)
575
603
  suite2p_tracker = ProcessingTracker(file_path=session_data.processed_data.suite2p_processing_tracker_path)
576
604
  video_tracker = ProcessingTracker(file_path=session_data.processed_data.video_processing_tracker_path)
577
605
 
578
- # Similar to above, if the session is not processed with the behavior pipeline or the suite2p pipeline, aborts
579
- # without creating the marker file. Video tracker is not required for p53 marker creation, but the video
580
- # tracking pipeline must not be actively running.
581
- if not behavior_tracker.is_complete or not suite2p_tracker.is_complete or video_tracker.is_running:
606
+ # Similar to the above, ensures that the session is not being processed with one of the supported pipelines.
607
+ if behavior_tracker.is_running or suite2p_tracker.is_running or video_tracker.is_running:
582
608
  return
583
609
 
584
610
  # If the runtime reached this point, the session is eligible for dataset integration. Creates the p53.bin marker
585
611
  # file, preventing the session from being processed again as long as the marker exists.
586
612
  session_data.processed_data.p53_path.touch()
613
+
614
+ # If the runtime is configured to generate the project manifest file, attempts to generate and overwrite the
615
+ # existing manifest file for the target project.
616
+ if update_manifest:
617
+ # All sessions are stored under root/project/animal/session. Therefore, the grandparent of the session is
618
+ # the raw project directory.
619
+ raw_directory = session_path.parents[1]
620
+
621
+ # Depending on the processed_data_root configuration, determines the path for the project's processed
622
+ # data directory.
623
+ processed_directory: Path | None = None
624
+ if processed_data_root is not None:
625
+ processed_directory = processed_data_root.joinpath(session_data.project_name)
626
+
627
+ # Generates the manifest file inside the root raw data project directory
628
+ generate_project_manifest(
629
+ raw_project_directory=session_path.parents[1],
630
+ processed_project_directory=processed_directory,
631
+ output_directory=raw_directory,
632
+ )
@@ -1,19 +1,18 @@
1
1
  from pathlib import Path
2
2
 
3
3
  import polars as pl
4
- from _typeshed import Incomplete
5
4
 
6
5
  from ..data_classes import (
7
6
  SessionData as SessionData,
7
+ SessionTypes as SessionTypes,
8
8
  ProcessingTracker as ProcessingTracker,
9
9
  RunTrainingDescriptor as RunTrainingDescriptor,
10
10
  LickTrainingDescriptor as LickTrainingDescriptor,
11
+ WindowCheckingDescriptor as WindowCheckingDescriptor,
11
12
  MesoscopeExperimentDescriptor as MesoscopeExperimentDescriptor,
12
13
  )
13
14
  from .packaging_tools import calculate_directory_checksum as calculate_directory_checksum
14
15
 
15
- _valid_session_types: Incomplete
16
-
17
16
  class ProjectManifest:
18
17
  """Wraps the contents of a Sun lab project manifest .feather file and exposes methods for visualizing and
19
18
  working with the data stored inside the file.
@@ -104,8 +103,7 @@ class ProjectManifest:
104
103
 
105
104
  Returns:
106
105
  A Polars DataFrame with the following columns: 'animal', 'date', 'notes', 'session', 'type', 'complete',
107
- 'intensity_verification', 'suite2p', 'behavior', 'video',
108
- 'dataset'.
106
+ 'intensity_verification', 'suite2p', 'behavior', 'video', 'dataset'.
109
107
  """
110
108
 
111
109
  def generate_project_manifest(
@@ -133,7 +131,10 @@ def generate_project_manifest(
133
131
  """
134
132
 
135
133
  def verify_session_checksum(
136
- session_path: Path, create_processed_data_directory: bool = True, processed_data_root: None | Path = None
134
+ session_path: Path,
135
+ create_processed_data_directory: bool = True,
136
+ processed_data_root: None | Path = None,
137
+ update_manifest: bool = False,
137
138
  ) -> None:
138
139
  """Verifies the integrity of the session's raw data by generating the checksum of the raw_data directory and
139
140
  comparing it against the checksum stored in the ax_checksum.txt file.
@@ -149,6 +150,9 @@ def verify_session_checksum(
149
150
  This function is also used to create the processed data hierarchy on the BioHPC server, when it is called as
150
151
  part of the data preprocessing runtime performed by a data acquisition system.
151
152
 
153
+ Since version 3.1.0, this functon also supports (re) generating the processed session's project manifest file,
154
+ which is used to support further Sun lab data processing pipelines.
155
+
152
156
  Args:
153
157
  session_path: The path to the session directory to be verified. Note, the input session directory must contain
154
158
  the 'raw_data' subdirectory.
@@ -156,6 +160,9 @@ def verify_session_checksum(
156
160
  processed_data_root: The root directory where to store the processed data hierarchy. This path has to point to
157
161
  the root directory where to store the processed data from all projects, and it will be automatically
158
162
  modified to include the project name, the animal name, and the session ID.
163
+ update_manifest: Determines whether to update (regenerate) the project manifest file for the processed session's
164
+ project. This should always be enabled when working with remote compute server(s) to ensure that the
165
+ project manifest file contains the most actual snapshot of the project's state.
159
166
  """
160
167
 
161
168
  def resolve_p53_marker(
@@ -163,6 +170,7 @@ def resolve_p53_marker(
163
170
  create_processed_data_directory: bool = True,
164
171
  processed_data_root: None | Path = None,
165
172
  remove: bool = False,
173
+ update_manifest: bool = False,
166
174
  ) -> None:
167
175
  """Depending on configuration, either creates or removes the p53.bin marker file for the target session.
168
176
 
@@ -174,11 +182,12 @@ def resolve_p53_marker(
174
182
  from altering the data while it is integrated into a dataset. The p53.bin marker solves this issue by ensuring
175
183
  that only one type of runtimes (processing or dataset integration) is allowed to work with the session.
176
184
 
177
- For the p53.bin marker to be created, the session must currently not undergo any processing and must be
178
- successfully processed with the minimal set of pipelines for its session type. Removing the p53.bin marker does
179
- not have any dependencies and will be executed even if the session is currently undergoing dataset integration.
180
- Due to this limitation, it is only possible to call this function with the 'remove' flag manually (via the
181
- dedicated CLI).
185
+ For the p53.bin marker to be created, the session must currently not undergo any processing. Removing the
186
+ p53.bin marker does not have any dependencies and will be executed even if the session is currently undergoing
187
+ dataset integration. This is due to data access hierarchy limitations of the Sun lab compute server.
188
+
189
+ Since version 3.1.0, this functon also supports (re)generating the processed session's project manifest file,
190
+ which is used to support further Sun lab data processing pipelines.
182
191
 
183
192
  Args:
184
193
  session_path: The path to the session directory for which the p53.bin marker needs to be resolved. Note, the
@@ -188,4 +197,7 @@ def resolve_p53_marker(
188
197
  the root directory where to store the processed data from all projects, and it will be automatically
189
198
  modified to include the project name, the animal name, and the session ID.
190
199
  remove: Determines whether this function is called to create or remove the p53.bin marker.
200
+ update_manifest: Determines whether to update (regenerate) the project manifest file for the processed session's
201
+ project. This should always be enabled when working with remote compute server(s) to ensure that the
202
+ project manifest file contains the most actual snapshot of the project's state.
191
203
  """
@@ -45,7 +45,7 @@ def transfer_directory(source: Path, destination: Path, num_threads: int = 1, ve
45
45
  done before copying the files.
46
46
 
47
47
  The method executes a multithreading copy operation. It does not clean up the source files. That job is handed
48
- to the specific preprocessing function from the sl_experiment or sl-forgery libraries that calls this function.
48
+ to the specific preprocessing function from the sl_experiment or sl-forgery libraries that call this function.
49
49
 
50
50
  If the method is configured to verify transferred file integrity, it reruns the xxHash3-128 checksum calculation
51
51
  and compares the returned checksum to the one stored in the source directory. The method assumes that all input
@@ -30,7 +30,7 @@ def transfer_directory(source: Path, destination: Path, num_threads: int = 1, ve
30
30
  done before copying the files.
31
31
 
32
32
  The method executes a multithreading copy operation. It does not clean up the source files. That job is handed
33
- to the specific preprocessing function from the sl_experiment or sl-forgery libraries that calls this function.
33
+ to the specific preprocessing function from the sl_experiment or sl-forgery libraries that call this function.
34
34
 
35
35
  If the method is configured to verify transferred file integrity, it reruns the xxHash3-128 checksum calculation
36
36
  and compares the returned checksum to the one stored in the source directory. The method assumes that all input
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sl-shared-assets
3
- Version: 3.0.0rc14
3
+ Version: 3.1.0
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/
@@ -772,6 +772,7 @@ A Python library that stores assets shared between multiple Sun (NeuroAI) lab da
772
772
  ![PyPI - License](https://img.shields.io/pypi/l/sl-shared-assets)
773
773
  ![PyPI - Status](https://img.shields.io/pypi/status/sl-shared-assets)
774
774
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/sl-shared-assets)
775
+
775
776
  ___
776
777
 
777
778
  ## Detailed Description
@@ -813,7 +814,7 @@ All software library dependencies are installed automatically as part of library
813
814
 
814
815
  Note, installation from source is ***highly discouraged*** for everyone who is not an active project developer.
815
816
 
816
- 1. Download this repository to your local machine using your preferred method, such as Git-cloning. Use one
817
+ 1. Download this repository to your local machine using any method, such as Git-cloning. Use one
817
818
  of the stable releases from [GitHub](https://github.com/Sun-Lab-NBB/sl-shared-assets/releases).
818
819
  2. Unpack the downloaded zip and note the path to the binary wheel (`.whl`) file contained in the archive.
819
820
  3. Run ```python -m pip install WHEEL_PATH```, replacing 'WHEEL_PATH' with the path to the wheel file, to install the
@@ -826,12 +827,128 @@ Use the following command to install the library using pip: ```pip install sl-sh
826
827
 
827
828
  ## Usage
828
829
 
829
- All library components are intended to be used via other Sun lab libraries. Developers should study the API and CLI
830
+ Most library components are intended to be used via other Sun lab libraries. Developers should study the API and CLI
830
831
  documentation below to learn how to use library components in other Sun lab libraries. For notes on using shared
831
832
  assets for data acquisition, see the [sl-experiment](https://github.com/Sun-Lab-NBB/sl-experiment) library ReadMe.
832
833
  For notes on using shared assets for data processing, see the [sl-forgery](https://github.com/Sun-Lab-NBB/sl-forgery)
833
834
  library ReadMe.
834
835
 
836
+ The only exception to the note above is the **server.py** package exposed by this library. This package exposes an API
837
+ for running headless and a CLI for running interactive Simple Linux Utility for Resource Management (SLURM)-managed
838
+ jobs on remote compute clusters.
839
+
840
+ ### Generating Access Credentials
841
+
842
+ To access any remote server, the user is required to first generate the access credentials. The credentials are stored
843
+ inside the 'server_credentials.yaml' file, which is generated by using the `sl-create-server-credentials` command.
844
+ **Note!** Users are advised to generate this file in a secure (non-shared) location on their local machine.
845
+
846
+ ### Running Headless Jobs
847
+
848
+ A headless job is a job that does not require any user interaction during runtime. Currently, all headless jobs in the
849
+ lab rely on pip-installable packages that expose a callable Command-Line Interface to carry out some type of
850
+ data processing. In this regard, **running a headless job is equivalent to calling a CLI command on your local
851
+ machine**, except that the command is executed on a remote compute server. Therefore, the primary purpose of the API
852
+ exposed by this library is to transfer the target command request to the remote server, execute it, and monitor the
853
+ runtime status until it is complete.
854
+
855
+ For example, the [sl-suite2p package](https://github.com/Sun-Lab-NBB/suite2p) maintained in the lab exposes a CLI to
856
+ process 2-Photon data from experiment sessions. During data processing by the
857
+ [sl-forgery](https://github.com/Sun-Lab-NBB/sl-forgery) library, a remote job is sent to the server that uses the CLI
858
+ exposed by the sl-suite2p package to process target session(s).
859
+
860
+ ### Creating Jobs
861
+ All remote jobs are sent to the server in the form of an executable *shell* (.sh) script. The script is composed on the
862
+ local machine that uses this library and transferred to a temporary server directory using Secure Shell File
863
+ Transfer Protocol (SFTP). The server is then instructed to evaluate (run) the script using SLURM job manager, via a
864
+ Secure Shell (SSH) session.
865
+
866
+ Broadly, each job consists of three major steps, which correspond to three major sections of the job shell script:
867
+ 1. **Setting up the job environment**. Each job script starts with a SLURM job parameter block, which tells SLURM
868
+ what resources (CPUs, GPUs, RAM, etc.) the job requires. When resources become available, SLURM generates a virtual
869
+ environment and runs the rest of the job script in that environment. This forms the basis for using the shared
870
+ compute resources fairly, as SLURM balances resource allocation and the order of job execution for all users.
871
+ 2. **Activating the target conda environment**. Currently, all jobs are assumed to use Python libraries to execute the
872
+ intended data processing. Similar to processing data locally, each job expects the remote server to provide a
873
+ Conda environment preconfigured with necessary assets (packages) to run the job. Therefore, each job contains a
874
+ section that activates the user-defined conda environment before running the rest of the job.
875
+ 3. **Executing processing**. The final section is typically unique to each job and calls specific CLI commands or runs
876
+ specific Python modules. Since each job is submitted as a shell script, it can do anything a server shell can
877
+ do. Therefore, despite python-centric approach to data processing in the lab, a remote job composed via this library
878
+ can execute ***any*** arbitrary command available to the user on the remove server.
879
+
880
+ Use the *Job* class exposed by this library to compose remote jobs. **Steps 1 and 2** of each job are configured when
881
+ initializing the Job instance, while **step 3** is added via the `add_command()` method of the Job class:
882
+ ```
883
+ # First, import the job class
884
+ from pathlib import Path
885
+ from sl_shared_assets import Job
886
+
887
+ # Next, instantiate a new Job object. For example, this job is used to verify the integrity of raw experiment data as
888
+ # it is transferred to the long-term storage destination (server) by the sl-experiment library.
889
+ job = Job(
890
+ job_name="data_integrity_verification",
891
+ output_log=Path("/temp/output.txt"),
892
+ error_log=Path("/temp/errors.txt"),
893
+ working_directory=Path("/temp/test_job"),
894
+ conda_environment="test_environment",
895
+ cpus_to_use=20,
896
+ ram_gb=50,
897
+ time_limit=20,
898
+ )
899
+
900
+ # Finally, add a CLI command call (the actual work to be done by the job). Here, the job calls the
901
+ # 'sl-verify-session' command exposed by the sl-shared-assets library installed in the target environment on the server.
902
+ # Use this method to add commands as you would type them in your local terminal / shell / command line.
903
+ job.add_command(f"sl-verify-session -sp /temp/test_session")
904
+ ```
905
+
906
+ ### Submitting and Monitoring Jobs:
907
+ To submit the job to the remote server, use a **Server** class instance. This class encapsulates access to the target
908
+ remote compute server and uses the server_credentials.yaml file to determine server access credentials (see above):
909
+ ```
910
+ # Initialize the Server class using precreated server credentials file
911
+ server = Server(credentials_path=Path("/temp/server_credentials.yaml"))
912
+
913
+ # Submit the job (generated in the previous code snippet) to the server
914
+ job = server.submit_job(job)
915
+
916
+ # Wait for the server to complete the job
917
+ delay_timer = PrecisionTimer("s")
918
+ while not server.job_complete(job=job):
919
+ delay_timer.delay_noblock(delay=5, allow_sleep=True)
920
+ ```
921
+
922
+ **Note!** The Server class only checks whether the job is running on the server, but not the outcome of the job. For
923
+ that, you can either manually check the output and error logs for the job or come up with a programmatic way of
924
+ checking the outcome. All developers are highly advised to study the API documentation for the Job and Server classes
925
+ to use them most effectively.
926
+
927
+ **Critical!** Since running remote jobs is largely equivalent to executing them locally, all users are highly encouraged
928
+ to test their job scripts locally before deploying them server-side. If a script works on a local machine, it is likely
929
+ that the script would behave similarly and work on the server.
930
+
931
+ ### Interactive Jobs
932
+
933
+ Interactive jobs are a special extension of the headless job type discussed above. Specifically, an interactive job is
934
+ a headless job, whose only purpose is to **create and maintain a Jupyter lab server** under the SLURM control.
935
+ Specifically, it requests SLURM to set up an isolated environment, starts a Jupyter server in that environment, and
936
+ sends the credentials for the started server back to the user.
937
+
938
+ In essence, this allocates a set of resources the user can use interactively by running various Jupyter notebooks.
939
+ While convenient for certain data analysis cases, this type of jobs has the potential to inefficiently hog server
940
+ resources for prolonged periods of time. Therefore, users are encouraged to only resort to this type of jobs when
941
+ strictly necessary and to minimize the resources and time allocated to running these jobs.
942
+
943
+ To run an interactive job, call the `sl-start-jupyter` CLI command exposed by this library and follow the instructions
944
+ printed to the terminal by the command during runtime.
945
+
946
+ **Critical!** While this command tries to minimize collisions with other users, it is possible that an access port
947
+ collision occurs when multiple users try to instantiate a jupyter server at the same time. If you cannot authenticate
948
+ with the Jupyter server, this likely indicates that the target port was in use and Jupyter automatically incremented the
949
+ port number by 1. In this case, add 1 to your port number and try connecting to that port using the Jupyter credentials
950
+ provided by the command. For example, if your target port was '8888,' try port '8889.'
951
+
835
952
  ---
836
953
 
837
954
  ## API Documentation
@@ -847,7 +964,7 @@ ___
847
964
 
848
965
  ## Versioning
849
966
 
850
- We use [semantic versioning](https://semver.org/) for this project. For the versions available, see the
967
+ This project uses [semantic versioning](https://semver.org/). For the versions available, see the
851
968
  [tags on this repository](https://github.com/Sun-Lab-NBB/sl-shared-assets/tags).
852
969
 
853
970
  ---
@@ -870,7 +987,7 @@ ___
870
987
 
871
988
  - All Sun lab [members](https://neuroai.github.io/sunlab/people) for providing the inspiration and comments during the
872
989
  development of this library.
873
- - The creators of all other projects used in our development automation pipelines and source code
990
+ - The creators of all other projects used in the development automation pipelines and source code of this project
874
991
  [see pyproject.toml](pyproject.toml).
875
992
 
876
993
  ---
@@ -0,0 +1,36 @@
1
+ sl_shared_assets/__init__.py,sha256=ybThh0XDtijjwahKkSEnnQ44rxrN2SVyjB5dHaXts0E,2391
2
+ sl_shared_assets/__init__.pyi,sha256=Cb-umRqvnynk2udbgqAJ6h5_tiJyvVtWmx0kLKrL2Yg,2678
3
+ sl_shared_assets/cli.py,sha256=OIwXf6pNPnzqzUPL7mSmEw17KIa3yAOpP0Mpo1Zpf88,19087
4
+ sl_shared_assets/cli.pyi,sha256=5hEbOnYaH4q5qdqJ-zhM9-ElzgcaBeMAX34tuHaUDos,5328
5
+ sl_shared_assets/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ sl_shared_assets/data_classes/__init__.py,sha256=mP__bBIIjMf0EETM4PgQzKy1ZKsjp6paRPNDWWbPRV4,1962
7
+ sl_shared_assets/data_classes/__init__.pyi,sha256=J7ZCH9qQ4qz-3Wq9ILdihlmK9zFR3iU1cpLcSaN45Y8,2238
8
+ sl_shared_assets/data_classes/configuration_data.py,sha256=npMYu9WQMJnoanzC2_5rheDbWS-r4SWAyQZT5Tw1AYQ,36359
9
+ sl_shared_assets/data_classes/configuration_data.pyi,sha256=1_kmBDPGkHmVwXEGYR_3uERBSsenQOTuquMBtjKVTA8,11068
10
+ sl_shared_assets/data_classes/runtime_data.py,sha256=kmXTUk5rDAJBN3XrYLYgusJRfVJ5WiBBk0RPNiSk2pE,16725
11
+ sl_shared_assets/data_classes/runtime_data.pyi,sha256=Hyc-dBePM0xIGgkSIoKmwwUUmdOokm1LUwy1OHHalyU,6771
12
+ sl_shared_assets/data_classes/session_data.py,sha256=YKXako1sNB87LDkGEXx9WZFs6lG3aD619lga5g4L4Ks,49172
13
+ sl_shared_assets/data_classes/session_data.pyi,sha256=CgB4nIDBl4bY1JvcIILfFTlos3ukl3WK4AOaku4CL3Y,15959
14
+ sl_shared_assets/data_classes/surgery_data.py,sha256=5B1OPKFq4bnzbAoe-_c5dFV3kbSD5YFzXbX2zXmfGs8,7485
15
+ sl_shared_assets/data_classes/surgery_data.pyi,sha256=rf59lJ3tGSYKHQlEGXg75MnjajBwl0DYhL4TClAO4SM,2605
16
+ sl_shared_assets/server/__init__.py,sha256=GOQ7wWjiS5Xg_WgTqeEqCTRF9ms9GXx0nffCr-BmKsA,453
17
+ sl_shared_assets/server/__init__.pyi,sha256=Zc12G90fZdgEMwaVZbFzrRVV1wH_LEj3sxaV3lhk1Cw,316
18
+ sl_shared_assets/server/job.py,sha256=wZbppMrv6fqch79bKLjOGQ9AYfjiDKDnTyUe7xgAT44,19461
19
+ sl_shared_assets/server/job.pyi,sha256=wop4ulVY2u6eb3twajeA9MS0EAtNb89aA56pPoGF1Xc,11673
20
+ sl_shared_assets/server/server.py,sha256=oEwdXisyel72Hdk7ZpEwTPq3Lu64UbQWfGHArV8Y6nI,32978
21
+ sl_shared_assets/server/server.pyi,sha256=84XFtqU9fYbxu6Ldf-OMB2nFe6wdGneZM1MFtR9rz4s,15133
22
+ sl_shared_assets/tools/__init__.py,sha256=i-oUVw_un3lzyyII4Sc75s4BnUfZh_aUbQe6dP2Vrbc,743
23
+ sl_shared_assets/tools/__init__.pyi,sha256=pi-5AJyQYeuqIFGWpJ_HhUpXLq6P_nItIqDhsdaIJFU,686
24
+ sl_shared_assets/tools/ascension_tools.py,sha256=xI-hrkR9NIgb7lyhj-ntc8tCYQvDEv6YgYJXl1yvxCs,14639
25
+ sl_shared_assets/tools/ascension_tools.pyi,sha256=fs5j7nbnZ4WpgK8D75A7WJcvFMwK_MUO9ULIYo1YkGo,3739
26
+ sl_shared_assets/tools/packaging_tools.py,sha256=VxQoluGPDUWjPj1ftEt2dvUcdmj0g7T1frGZhZPM8NE,7541
27
+ sl_shared_assets/tools/packaging_tools.pyi,sha256=vgGbAQCExwg-0A5F72MzEhzHxu97Nqg1yuz-5P89ycU,3118
28
+ sl_shared_assets/tools/project_management_tools.py,sha256=vutKi0pdQn5dxBk1OcxPB4XspzQyJwzerNhGi4Vg4iw,31935
29
+ sl_shared_assets/tools/project_management_tools.pyi,sha256=hdn0U9e3_j9McJH75Dzoas-FxcB9nVCTHEFHPofdLtg,11361
30
+ sl_shared_assets/tools/transfer_tools.py,sha256=vqYO4sERZV0W1DFNFnTpJA6QBZ4QJA94a2TyUhZW2Qk,6605
31
+ sl_shared_assets/tools/transfer_tools.pyi,sha256=WtUGfaKV9FP_CnhBg_UvclpuDvOlEESOSMlEDtWpOLg,3293
32
+ sl_shared_assets-3.1.0.dist-info/METADATA,sha256=SbnWSGHffTfwIaQGGP04zsSZ-T2yFga1jL79eLLoib8,56944
33
+ sl_shared_assets-3.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
+ sl_shared_assets-3.1.0.dist-info/entry_points.txt,sha256=UmO1rl7ly9N7HWPwWyP9E0b5KBUStpBo4TRoqNtizDY,430
35
+ sl_shared_assets-3.1.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
36
+ sl_shared_assets-3.1.0.dist-info/RECORD,,
@@ -1,36 +0,0 @@
1
- sl_shared_assets/__init__.py,sha256=rCu1VYs2Lc1l0jqHO3UtfuymU0uY2ccxEn4UyscIut8,2347
2
- sl_shared_assets/__init__.pyi,sha256=WCWIS-I3ToP4XybNZAi3fA7j2CZ48dl9D-fmd7oZKCo,2615
3
- sl_shared_assets/cli.py,sha256=R_h_Dlla48mG1LpFDDE9flZ_NyDC9UguRUAYZL6gA9s,18383
4
- sl_shared_assets/cli.pyi,sha256=8ZJK56_jh2QlF3XCN6c7fI6Z022XtehB0eCrQDJbAsU,5515
5
- sl_shared_assets/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- sl_shared_assets/data_classes/__init__.py,sha256=bdm0hyQpNF0RL2SPhUgaOz33FsRzpM2L_z5-91HyZBE,1998
7
- sl_shared_assets/data_classes/__init__.pyi,sha256=J7ZCH9qQ4qz-3Wq9ILdihlmK9zFR3iU1cpLcSaN45Y8,2238
8
- sl_shared_assets/data_classes/configuration_data.py,sha256=HAdYUVy_8gg_ECN56RAEih9UB7DoZ4J3S5a8ky8o4dQ,36076
9
- sl_shared_assets/data_classes/configuration_data.pyi,sha256=11Q6OJjN6PdrlZwVPYCL4TEGxkbKL7mGb2S1sSMKsqs,11027
10
- sl_shared_assets/data_classes/runtime_data.py,sha256=MLIef6s9n2gG6sbp197gpFfzb05e_8vwVzyS_oSmXYQ,16722
11
- sl_shared_assets/data_classes/runtime_data.pyi,sha256=LzNuEWu-GlPGdyyi8Hn2OFUjGCWOaOplKsRQBbjn2vQ,6768
12
- sl_shared_assets/data_classes/session_data.py,sha256=R1xYEEKL6DzqyURWRZXNN37uyu8C7L77ECoMfMdh8bM,48237
13
- sl_shared_assets/data_classes/session_data.pyi,sha256=g53jIe-v8VkQJHc7ITS0KBGRhzn6LOIb6f96SEbEGig,15898
14
- sl_shared_assets/data_classes/surgery_data.py,sha256=5B1OPKFq4bnzbAoe-_c5dFV3kbSD5YFzXbX2zXmfGs8,7485
15
- sl_shared_assets/data_classes/surgery_data.pyi,sha256=rf59lJ3tGSYKHQlEGXg75MnjajBwl0DYhL4TClAO4SM,2605
16
- sl_shared_assets/server/__init__.py,sha256=w7y73RXXjBrWQsjU5g1QNCv_gsXDYnHos3NpOoR2AHA,452
17
- sl_shared_assets/server/__init__.pyi,sha256=Zc12G90fZdgEMwaVZbFzrRVV1wH_LEj3sxaV3lhk1Cw,316
18
- sl_shared_assets/server/job.py,sha256=DnEVIswZXm9queBgy6MlpIrCosXvQ_tweOeko7LN9yc,19431
19
- sl_shared_assets/server/job.pyi,sha256=uYfOuKgPL1hSHQvy5nmXzFkVjS316F3IZTdT-PmluZU,11663
20
- sl_shared_assets/server/server.py,sha256=MGk1v49aEFeIChMDsiR7CXjVkWwDpD9kA1TK0fwuTXw,32926
21
- sl_shared_assets/server/server.pyi,sha256=5Yxq4txhjtd9w-6U9fPehzMeIZL5GcprVCHd9mPP6FI,15113
22
- sl_shared_assets/tools/__init__.py,sha256=NktXk62E_HHOrO_93z_MVmSd6-Oir3mE4xE9Yr8Qa7U,682
23
- sl_shared_assets/tools/__init__.pyi,sha256=0UXorfCXXmHQOP5z7hODpsqEX0DAkOta5VZqN6FSS-w,623
24
- sl_shared_assets/tools/ascension_tools.py,sha256=tRV_tpoQURDD03slrRdh12Qbf9_ZQo4RU0PgYbUWOc0,14620
25
- sl_shared_assets/tools/ascension_tools.pyi,sha256=fs5j7nbnZ4WpgK8D75A7WJcvFMwK_MUO9ULIYo1YkGo,3739
26
- sl_shared_assets/tools/packaging_tools.py,sha256=QikjeaE_A8FyVJi3cnWLeW-hUXy1-FF1N23muA5VfT4,7526
27
- sl_shared_assets/tools/packaging_tools.pyi,sha256=vgGbAQCExwg-0A5F72MzEhzHxu97Nqg1yuz-5P89ycU,3118
28
- sl_shared_assets/tools/project_management_tools.py,sha256=Z_U0R26w9Le1O-u66gyF5CG8M_YaLFNpH9diQeH1AZQ,29381
29
- sl_shared_assets/tools/project_management_tools.pyi,sha256=4kok98nOZ4KnT-Sg-ZCZYg-WIM5qZqiyK8g1XiiDjHM,10375
30
- sl_shared_assets/tools/transfer_tools.py,sha256=J26kwOp_NpPSY0-xu5FTw9udte-rm_mW1FJyaTNoqQI,6606
31
- sl_shared_assets/tools/transfer_tools.pyi,sha256=FoH7eYZe7guGHfPr0MK5ggO62uXKwD2aJ7h1Bu7PaEE,3294
32
- sl_shared_assets-3.0.0rc14.dist-info/METADATA,sha256=lofwFKkF_-Qf2uQ7HeRBTB2CtEV4ktJPcgNKfT9JzH4,49214
33
- sl_shared_assets-3.0.0rc14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
- sl_shared_assets-3.0.0rc14.dist-info/entry_points.txt,sha256=UmO1rl7ly9N7HWPwWyP9E0b5KBUStpBo4TRoqNtizDY,430
35
- sl_shared_assets-3.0.0rc14.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
36
- sl_shared_assets-3.0.0rc14.dist-info/RECORD,,