sl-shared-assets 2.0.1__tar.gz → 3.0.0rc2__tar.gz

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 (50) hide show
  1. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/PKG-INFO +5 -6
  2. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/README.md +0 -1
  3. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/docs/source/api.rst +8 -0
  4. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/docs/source/conf.py +1 -1
  5. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/docs/source/welcome.rst +3 -2
  6. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/pyproject.toml +11 -9
  7. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/__init__.py +9 -5
  8. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/__init__.pyi +4 -4
  9. sl_shared_assets-3.0.0rc2/src/sl_shared_assets/cli.py +459 -0
  10. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/cli.pyi +48 -5
  11. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/data_classes/configuration_data.py +20 -0
  12. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/data_classes/configuration_data.pyi +14 -0
  13. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/data_classes/runtime_data.py +17 -2
  14. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/data_classes/runtime_data.pyi +6 -2
  15. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/data_classes/session_data.py +7 -11
  16. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/data_classes/session_data.pyi +1 -2
  17. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/server/__init__.py +2 -2
  18. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/server/__init__.pyi +5 -2
  19. sl_shared_assets-3.0.0rc2/src/sl_shared_assets/server/job.py +368 -0
  20. sl_shared_assets-3.0.0rc2/src/sl_shared_assets/server/job.pyi +205 -0
  21. sl_shared_assets-3.0.0rc2/src/sl_shared_assets/server/server.py +622 -0
  22. sl_shared_assets-3.0.0rc2/src/sl_shared_assets/server/server.pyi +272 -0
  23. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/tools/__init__.py +2 -1
  24. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/tools/__init__.pyi +2 -0
  25. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/tools/packaging_tools.py +1 -2
  26. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/tools/project_management_tools.py +150 -34
  27. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/tools/project_management_tools.pyi +46 -3
  28. sl_shared_assets-2.0.1/src/sl_shared_assets/cli.py +0 -218
  29. sl_shared_assets-2.0.1/src/sl_shared_assets/server/job.py +0 -140
  30. sl_shared_assets-2.0.1/src/sl_shared_assets/server/job.pyi +0 -94
  31. sl_shared_assets-2.0.1/src/sl_shared_assets/server/server.py +0 -288
  32. sl_shared_assets-2.0.1/src/sl_shared_assets/server/server.pyi +0 -143
  33. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/.gitignore +0 -0
  34. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/LICENSE +0 -0
  35. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/docs/Makefile +0 -0
  36. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/docs/make.bat +0 -0
  37. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/docs/source/index.rst +0 -0
  38. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/envs/slsa_dev_lin.yml +0 -0
  39. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/envs/slsa_dev_lin_spec.txt +0 -0
  40. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/data_classes/__init__.py +0 -0
  41. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/data_classes/__init__.pyi +0 -0
  42. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/data_classes/surgery_data.py +0 -0
  43. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/data_classes/surgery_data.pyi +0 -0
  44. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/py.typed +0 -0
  45. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/tools/ascension_tools.py +0 -0
  46. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/tools/ascension_tools.pyi +0 -0
  47. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/tools/packaging_tools.pyi +0 -0
  48. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/tools/transfer_tools.py +0 -0
  49. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/src/sl_shared_assets/tools/transfer_tools.pyi +0 -0
  50. {sl_shared_assets-2.0.1 → sl_shared_assets-3.0.0rc2}/tox.ini +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sl-shared-assets
3
- Version: 2.0.1
4
- Summary: Stores assets shared between multiple Sun (NeuroAI) lab data pipelines.
3
+ Version: 3.0.0rc2
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/
7
7
  Author: Ivan Kondratyev, Kushaan Gupta, Natalie Yeung
@@ -681,7 +681,7 @@ License: GNU GENERAL PUBLIC LICENSE
681
681
  Public License instead of this License. But first, please read
682
682
  <https://www.gnu.org/licenses/why-not-lgpl.html>.
683
683
  License-File: LICENSE
684
- Keywords: acquisition,assets,data,processing,sunlab
684
+ Keywords: acquisition,assets,data,processing,server,sunlab
685
685
  Classifier: Development Status :: 5 - Production/Stable
686
686
  Classifier: Intended Audience :: Developers
687
687
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
@@ -697,7 +697,7 @@ Requires-Dist: ataraxis-time==3.0.0
697
697
  Requires-Dist: click==8.2.1
698
698
  Requires-Dist: filelock==3.18.0
699
699
  Requires-Dist: natsort==8.4.0
700
- Requires-Dist: numpy<2.3.0,>=2.0.2
700
+ Requires-Dist: numpy==2.2.6
701
701
  Requires-Dist: paramiko==3.5.1
702
702
  Requires-Dist: polars==1.31.0
703
703
  Requires-Dist: pyarrow==20.0.0
@@ -725,7 +725,7 @@ Requires-Dist: appdirs==1.4.4; extra == 'condarun'
725
725
  Requires-Dist: click==8.2.1; extra == 'condarun'
726
726
  Requires-Dist: filelock==3.18.0; extra == 'condarun'
727
727
  Requires-Dist: natsort==8.4.0; extra == 'condarun'
728
- Requires-Dist: numpy<2.3.0,>=2.0.2; extra == 'condarun'
728
+ Requires-Dist: numpy==2.2.6; extra == 'condarun'
729
729
  Requires-Dist: paramiko==3.5.1; extra == 'condarun'
730
730
  Requires-Dist: polars==1.31.0; extra == 'condarun'
731
731
  Requires-Dist: pyarrow==20.0.0; extra == 'condarun'
@@ -858,7 +858,6 @@ We use [semantic versioning](https://semver.org/) for this project. For the vers
858
858
 
859
859
  - Ivan Kondratyev ([Inkaros](https://github.com/Inkaros))
860
860
  - Kushaan Gupta ([kushaangupta](https://github.com/kushaangupta))
861
- - Yuantao Deng ([YuantaoDeng](https://github.com/YuantaoDeng))
862
861
  - Natalie Yeung
863
862
 
864
863
  ___
@@ -93,7 +93,6 @@ We use [semantic versioning](https://semver.org/) for this project. For the vers
93
93
 
94
94
  - Ivan Kondratyev ([Inkaros](https://github.com/Inkaros))
95
95
  - Kushaan Gupta ([kushaangupta](https://github.com/kushaangupta))
96
- - Yuantao Deng ([YuantaoDeng](https://github.com/YuantaoDeng))
97
96
  - Natalie Yeung
98
97
 
99
98
  ___
@@ -25,6 +25,14 @@ Command Line Interfaces
25
25
  :prog: sl-ascend-tyche
26
26
  :nested: full
27
27
 
28
+ .. click:: sl_shared_assets.cli:start_jupyter_server
29
+ :prog: sl-start-jupyter
30
+ :nested: full
31
+
32
+ .. click:: sl_shared_assets.cli:resolve_dataset_marker
33
+ :prog: sl-dataset-marker
34
+ :nested: full
35
+
28
36
  Tools
29
37
  =====
30
38
  .. automodule:: sl_shared_assets.tools
@@ -5,7 +5,7 @@ import importlib_metadata
5
5
  project = 'sl-shared-assets'
6
6
  # noinspection PyShadowingBuiltins
7
7
  copyright = '2025, Sun (NeuroAI) lab'
8
- authors = ['Ivan Kondratyev', 'Kushaan Gupta', 'Yuantao Deng', 'Natalie Yeung']
8
+ authors = ['Ivan Kondratyev', 'Kushaan Gupta', 'Natalie Yeung']
9
9
  # Extracts the project version from the .toml file.
10
10
  release = importlib_metadata.version("sl-shared-assets")
11
11
 
@@ -1,10 +1,11 @@
1
1
  Welcome to sl-shared-assets API documentation page
2
2
  ==================================================
3
3
 
4
- sl-shared-assets is a Python library that stores assets shared between multiple Sun (NeuroAI) lab data pipelines.
4
+ sl-shared-assets is a Python library that provides data acquisition and processing assets shared between Sun (NeuroAI)
5
+ lab libraries.
5
6
 
6
7
  This library is developed in the `Sun lab <https://neuroai.github.io/sunlab/>`_ at Cornell University. The main purpose
7
- of this library is to provide the tools adn assets used by multiple other data acquisition and processing libraries in
8
+ of this library is to provide the tools and assets used by multiple other data acquisition and processing libraries in
8
9
  the lab to avoid cross-dependency issues.
9
10
 
10
11
  This website only contains the API documentation for the classes and methods offered by this library. See the project
@@ -8,21 +8,21 @@ build-backend = "hatchling.build"
8
8
  # Project metdata section. Provides the genral ID information about the project.
9
9
  [project]
10
10
  name = "sl-shared-assets"
11
- version = "2.0.1"
12
- description = "Stores assets shared between multiple Sun (NeuroAI) lab data pipelines."
11
+ version = "3.0.0rc2"
12
+ description = "Provides data acquisition and processing assets shared between Sun (NeuroAI) lab libraries."
13
13
  readme = "README.md"
14
14
  license = { file = "LICENSE" }
15
15
  requires-python = ">=3.11"
16
16
  authors = [
17
- {name = "Ivan Kondratyev"},
18
- {name = "Kushaan Gupta"},
19
- {name = "Natalie Yeung"}
17
+ { name = "Ivan Kondratyev" },
18
+ { name = "Kushaan Gupta" },
19
+ { name = "Natalie Yeung" }
20
20
  ]
21
21
  maintainers = [
22
- {name = "Ivan Kondratyev", email = "ik278@cornell.edu"},
22
+ { name = "Ivan Kondratyev", email = "ik278@cornell.edu" },
23
23
  ]
24
24
 
25
- keywords = ["sunlab", "data", "assets", "acquisition", "processing"]
25
+ keywords = ["sunlab", "data", "assets", "acquisition", "processing", "server"]
26
26
 
27
27
  classifiers = [
28
28
  # Development status
@@ -44,7 +44,7 @@ dependencies = [
44
44
  "ataraxis-time==3.0.0",
45
45
  "ataraxis-base-utilities==3.0.1",
46
46
  "ataraxis-data-structures==3.1.1",
47
- "numpy>=2.0.2,<2.3.0",
47
+ "numpy==2.2.6",
48
48
  "appdirs==1.4.4",
49
49
  "tqdm==4.67.1",
50
50
  "xxhash==3.5.0",
@@ -70,7 +70,7 @@ Documentation = "https://sl-shared-assets-api-docs.netlify.app/"
70
70
  # (OSX ARM64, WIN AMD64, LIN AMD64). This specification is used by ataraxis-automation to resolve as many
71
71
  # project dependencies with conda over pip as possible.
72
72
  condarun = [
73
- "numpy>=2.0.2,<2.3.0",
73
+ "numpy==2.2.6",
74
74
  "appdirs==1.4.4",
75
75
  "tqdm==4.67.1",
76
76
  "paramiko==3.5.1",
@@ -144,6 +144,8 @@ sl-verify-session = "sl_shared_assets.cli:verify_session_integrity"
144
144
  sl-project-manifest = "sl_shared_assets.cli:generate_project_manifest_file"
145
145
  sl-create-server-credentials = "sl_shared_assets.cli:generate_server_credentials_file"
146
146
  sl-ascend-tyche = "sl_shared_assets.cli:ascend_tyche_directory"
147
+ sl-start-jupyter = "sl_shared_assets.cli:start_jupyter_server"
148
+ sl-dataset-marker = "sl_shared_assets.cli:resolve_dataset_marker"
147
149
 
148
150
  # Specifies files that should not be included in the source-code distribution but are also not part of gitignore.
149
151
  [tool.hatch.build.targets.sdist]
@@ -2,13 +2,17 @@
2
2
 
3
3
  See https://github.com/Sun-Lab-NBB/sl-shared-assets for more details.
4
4
  API documentation: https://sl-shared-assets-api-docs.netlify.app/
5
- Authors: Ivan Kondratyev (Inkaros), Kushaan Gupta, Yuantao Deng, Natalie Yeung
5
+ Authors: Ivan Kondratyev (Inkaros), Kushaan Gupta, Natalie Yeung
6
6
  """
7
7
 
8
8
  from ataraxis_base_utilities import console
9
9
 
10
- from .tools import transfer_directory, verify_session_checksum, generate_project_manifest, calculate_directory_checksum
11
- from .server import Job, Server, ServerCredentials
10
+ from .tools import (
11
+ resolve_p53_marker,
12
+ transfer_directory,
13
+ calculate_directory_checksum,
14
+ )
15
+ from .server import Job, Server, JupyterJob, ServerCredentials
12
16
  from .data_classes import (
13
17
  RawData,
14
18
  DrugData,
@@ -48,6 +52,7 @@ __all__ = [
48
52
  "Server",
49
53
  "ServerCredentials",
50
54
  "Job",
55
+ "JupyterJob",
51
56
  # Data classes package
52
57
  "DrugData",
53
58
  "ImplantData",
@@ -77,8 +82,7 @@ __all__ = [
77
82
  "get_system_configuration_data",
78
83
  "set_system_configuration_file",
79
84
  # Tools package
85
+ "resolve_p53_marker",
80
86
  "transfer_directory",
81
- "generate_project_manifest",
82
- "verify_session_checksum",
83
87
  "calculate_directory_checksum",
84
88
  ]
@@ -1,12 +1,12 @@
1
1
  from .tools import (
2
+ resolve_p53_marker as resolve_p53_marker,
2
3
  transfer_directory as transfer_directory,
3
- verify_session_checksum as verify_session_checksum,
4
- generate_project_manifest as generate_project_manifest,
5
4
  calculate_directory_checksum as calculate_directory_checksum,
6
5
  )
7
6
  from .server import (
8
7
  Job as Job,
9
8
  Server as Server,
9
+ JupyterJob as JupyterJob,
10
10
  ServerCredentials as ServerCredentials,
11
11
  )
12
12
  from .data_classes import (
@@ -43,6 +43,7 @@ __all__ = [
43
43
  "Server",
44
44
  "ServerCredentials",
45
45
  "Job",
46
+ "JupyterJob",
46
47
  "DrugData",
47
48
  "ImplantData",
48
49
  "SessionData",
@@ -70,8 +71,7 @@ __all__ = [
70
71
  "MesoscopeAdditionalFirmware",
71
72
  "get_system_configuration_data",
72
73
  "set_system_configuration_file",
74
+ "resolve_p53_marker",
73
75
  "transfer_directory",
74
- "generate_project_manifest",
75
- "verify_session_checksum",
76
76
  "calculate_directory_checksum",
77
77
  ]
@@ -0,0 +1,459 @@
1
+ """This module stores the Command-Line Interfaces (CLIs) exposes by the library as part of the installation process."""
2
+
3
+ from pathlib import Path
4
+
5
+ import click
6
+ from ataraxis_base_utilities import LogLevel, console, ensure_directory_exists
7
+
8
+ from .tools import ascend_tyche_data, resolve_p53_marker, verify_session_checksum, generate_project_manifest
9
+ from .server import Server, JupyterJob, generate_server_credentials
10
+ from .data_classes import SessionData, ProcessingTracker
11
+
12
+
13
+ @click.command()
14
+ @click.option(
15
+ "-sp",
16
+ "--session_path",
17
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path),
18
+ required=True,
19
+ help="The absolute path to the session directory whose raw data needs to be verified for potential corruption.",
20
+ )
21
+ @click.option(
22
+ "-c",
23
+ "--create_processed_directories",
24
+ is_flag=True,
25
+ show_default=True,
26
+ default=False,
27
+ help=(
28
+ "Determines whether to create the processed data hierarchy. This flag should be disabled for most runtimes. "
29
+ "Primarily, it is used by lab acquisition system code to generate processed data directories on the remote "
30
+ "compute servers as part of the data preprocessing pipeline."
31
+ ),
32
+ )
33
+ @click.option(
34
+ "-pdr",
35
+ "--processed_data_root",
36
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path),
37
+ required=False,
38
+ help=(
39
+ "The absolute path to the directory where processed data from all projects is stored on the machine that runs "
40
+ "this command. This argument is used when calling the CLI on the BioHPC server, which uses different data "
41
+ "volumes for raw and processed data. Note, the input path must point to the root directory, as it will be "
42
+ "automatically modified to include the project name, the animal id, and the session ID. This argument is only "
43
+ "used if 'create_processed_directories' flag is True."
44
+ ),
45
+ )
46
+ def verify_session_integrity(
47
+ session_path: Path, create_processed_directories: bool, processed_data_root: Path | None
48
+ ) -> None:
49
+ """Checks the integrity of the target session's raw data (contents of the raw_data directory).
50
+
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 function
53
+ always verified the integrity of the 'raw_data' directory. It does not work with 'processed_data' or any other
54
+ directories. If the session data was corrupted, the command removes the 'telomere.bin' file, marking the session as
55
+ 'incomplete' and automatically excluding it from all further automated processing runtimes. if the session data
56
+ is intact, generates a 'verified.bin' marker file inside the session's raw_data folder.
57
+
58
+ The command is also used by Sun lab data acquisition systems to generate the processed data hierarchy for each
59
+ processed session. This use case is fully automated and should not be triggered manually by the user.
60
+ """
61
+ session = Path(session_path)
62
+ session_data = SessionData.load(session_path=session)
63
+
64
+ # Runs the verification process
65
+ verify_session_checksum(
66
+ session, create_processed_data_directory=create_processed_directories, processed_data_root=processed_data_root
67
+ )
68
+
69
+ # Checks the outcome of the verification process
70
+ tracker = ProcessingTracker(file_path=session_data.raw_data.integrity_verification_tracker_path)
71
+ if tracker.is_complete:
72
+ # noinspection PyTypeChecker
73
+ console.echo(message=f"Session {session.stem} raw data integrity: Verified.", level=LogLevel.SUCCESS)
74
+ else:
75
+ # noinspection PyTypeChecker
76
+ console.echo(message=f"Session {session.stem} raw data integrity: Compromised!", level=LogLevel.ERROR)
77
+
78
+
79
+ @click.command()
80
+ @click.option(
81
+ "-pp",
82
+ "--project_path",
83
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path),
84
+ required=True,
85
+ help="The absolute path to the project directory where raw session data is stored.",
86
+ )
87
+ @click.option(
88
+ "-od",
89
+ "--output_directory",
90
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path),
91
+ required=True,
92
+ help="The absolute path to the directory where to store the generated project manifest file.",
93
+ )
94
+ @click.option(
95
+ "-ppp",
96
+ "--project_processed_path",
97
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path),
98
+ required=False,
99
+ help=(
100
+ "The absolute path to the project directory where processed session data is stored, if different from the "
101
+ "directory used to store raw session data. Typically, this extra argument is only used when processing data "
102
+ "stored on remote compute server(s)."
103
+ ),
104
+ )
105
+ def generate_project_manifest_file(
106
+ project_path: Path, output_directory: Path, project_processed_path: Path | None
107
+ ) -> None:
108
+ """Generates the manifest .feather file that provides information about the data-processing state of all available
109
+ project sessions.
110
+
111
+ The manifest file is typically used when batch-processing session data on the remote compute server. It contains the
112
+ comprehensive snapshot of the available project's data in a table-compatible format that can also be transferred
113
+ between machines (as it is cached in a file).
114
+ """
115
+ generate_project_manifest(
116
+ raw_project_directory=Path(project_path),
117
+ output_directory=Path(output_directory),
118
+ processed_project_directory=Path(project_processed_path) if project_processed_path else None,
119
+ )
120
+ # noinspection PyTypeChecker
121
+ console.echo(message=f"Project {Path(project_path).stem} data manifest file: generated.", level=LogLevel.SUCCESS)
122
+
123
+
124
+ @click.command()
125
+ @click.option(
126
+ "-od",
127
+ "--output_directory",
128
+ type=click.Path(exists=False, file_okay=False, dir_okay=True, path_type=Path),
129
+ required=True,
130
+ help="The absolute path to the directory where to store the generated server credentials file.",
131
+ )
132
+ @click.option(
133
+ "-h",
134
+ "--host",
135
+ type=str,
136
+ required=True,
137
+ show_default=True,
138
+ default="cbsuwsun.biohpc.cornell.edu",
139
+ help="The host name or IP address of the server to connect to.",
140
+ )
141
+ @click.option(
142
+ "-u",
143
+ "--username",
144
+ type=str,
145
+ required=True,
146
+ help="The username to use for server authentication.",
147
+ )
148
+ @click.option(
149
+ "-p",
150
+ "--password",
151
+ type=str,
152
+ required=True,
153
+ help="The password to use for server authentication.",
154
+ )
155
+ @click.option(
156
+ "-sr",
157
+ "--storage_root",
158
+ type=str,
159
+ required=True,
160
+ show_default=True,
161
+ default="/local/storage",
162
+ help=(
163
+ "The absolute path to to the root storage (slow) server directory. Typically, this is the path to the "
164
+ "top-level (root) directory of the HDD RAID volume."
165
+ ),
166
+ )
167
+ @click.option(
168
+ "-wr",
169
+ "--working_root",
170
+ type=str,
171
+ required=True,
172
+ show_default=True,
173
+ default="/local/workdir",
174
+ help=(
175
+ "The absolute path to the root working (fast) server directory. Typically, this is the path to the top-level "
176
+ "(root) directory of the NVME RAID volume. If the server uses the same volume for both storage and working "
177
+ "directories, enter the same path under both 'storage_root' and 'working_root'."
178
+ ),
179
+ )
180
+ @click.option(
181
+ "-sdn",
182
+ "--shared_directory_name",
183
+ type=str,
184
+ required=True,
185
+ show_default=True,
186
+ default="sun_data",
187
+ help=(
188
+ "The name of the shared directory used to store all Sun lab project data on the storage and working server "
189
+ "volumes."
190
+ ),
191
+ )
192
+ def generate_server_credentials_file(
193
+ output_directory: Path,
194
+ host: str,
195
+ username: str,
196
+ password: str,
197
+ storage_root: str,
198
+ working_root: str,
199
+ shared_directory_name: str,
200
+ ) -> None:
201
+ """Generates a new server_credentials.yaml file under the specified directory, using input information.
202
+
203
+ This command is used to set up access to compute servers and clusters on new machines (PCs). The data stored inside
204
+ the server_credentials.yaml file generated by this command is used by the Server and Job classes used in many Sun
205
+ lab data processing libraries.
206
+ """
207
+
208
+ # If necessary, generates the output directory hierarchy before creating the credentials' file.
209
+ ensure_directory_exists(output_directory)
210
+
211
+ # Generates the credentials' file
212
+ generate_server_credentials(
213
+ output_directory=Path(output_directory),
214
+ username=username,
215
+ password=password,
216
+ host=host,
217
+ storage_root=storage_root,
218
+ working_root=working_root,
219
+ shared_directory_name=shared_directory_name,
220
+ )
221
+ message = (
222
+ f"Server access credentials file: generated. If necessary, remember to edit the data acquisition system "
223
+ f"configuration file to include the path to the credentials file generated via this CLI."
224
+ )
225
+ # noinspection PyTypeChecker
226
+ console.echo(message=message, level=LogLevel.SUCCESS)
227
+ message = f"File location: {output_directory}"
228
+ # noinspection PyTypeChecker
229
+ console.echo(message=message, level=LogLevel.SUCCESS)
230
+
231
+
232
+ @click.command()
233
+ @click.option(
234
+ "-id",
235
+ "--input_directory",
236
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path),
237
+ required=True,
238
+ help="The absolute path to the directory that stores original Tyche animal folders.",
239
+ )
240
+ def ascend_tyche_directory(input_directory: Path) -> None:
241
+ """Restructures old Tyche project data to use the modern Sun lab data structure and uploads them to the processing
242
+ server.
243
+
244
+ This command is used to convert ('ascend') the old Tyche project data to the modern Sun lab structure. After
245
+ ascension, the data can be processed and analyzed using all modern Sun lab (sl-) tools and libraries. Note, this
246
+ process expects the input data to be preprocessed using an old Sun lab mesoscope data preprocessing pipeline. It
247
+ will not work for any other project or data. Also, this command will only work on a machine (PC) that belongs to a
248
+ valid Sun lab data acquisition system, such as VRPC of the Mesoscope-VR system.
249
+ """
250
+ ascend_tyche_data(root_directory=Path(input_directory))
251
+
252
+
253
+ @click.command()
254
+ @click.option(
255
+ "-cp",
256
+ "--credentials_path",
257
+ type=click.Path(exists=True, file_okay=True, dir_okay=False, path_type=Path),
258
+ required=True,
259
+ help=(
260
+ "The absolute path to the server_credentials.yaml file that stores access credentials for the target Sun lab "
261
+ "server. If necessary, use the 'sl-create-server-credentials' command to generate the file."
262
+ ),
263
+ )
264
+ @click.option(
265
+ "-n",
266
+ "--name",
267
+ type=str,
268
+ required=True,
269
+ show_default=True,
270
+ default="jupyter_server",
271
+ help=(
272
+ "The descriptive name to be given to the remote Jupyter server job. Primarily, this is used to identify the "
273
+ "job inside the log files."
274
+ ),
275
+ )
276
+ @click.option(
277
+ "-e",
278
+ "--environment",
279
+ type=str,
280
+ required=True,
281
+ help=(
282
+ "The name of the conda environment to use for running the Jupyter server. At a minimum, the target environment "
283
+ "must contain the 'jupyterlab' and the 'notebook' Python packages. Note, the user whose credentials are used "
284
+ "to connect to the server must have a configured conda / mamba shell that exposes the target environment for "
285
+ "the job to run as expected."
286
+ ),
287
+ )
288
+ @click.option(
289
+ "-d",
290
+ "--directory",
291
+ type=click.Path(exists=False, file_okay=True, dir_okay=True, path_type=Path),
292
+ required=False,
293
+ help=(
294
+ "The absolute path to the server directory to use as the root directory for the jupyter session. If not "
295
+ "provided, this is automatically resolved to user's working directory. Note, during runtime, Jupyter will only "
296
+ "have access to files stored in or under that root directory."
297
+ ),
298
+ )
299
+ @click.option(
300
+ "-c",
301
+ "--cores",
302
+ type=int,
303
+ required=True,
304
+ show_default=True,
305
+ default=2,
306
+ help=(
307
+ "The number of CPU cores to allocate to the Jupyter server. Note, during the interactive Jupyter runtime, it "
308
+ "is be impossible to use more than this number of CPU cores."
309
+ ),
310
+ )
311
+ @click.option(
312
+ "-m",
313
+ "--memory",
314
+ type=int,
315
+ required=True,
316
+ show_default=True,
317
+ default=32,
318
+ help=(
319
+ "The RAM, in Gigabytes, to allocate to the Jupyter server. Note, during the interactive Jupyter runtime, it "
320
+ "is be impossible to use more than this amount of RAM."
321
+ ),
322
+ )
323
+ @click.option(
324
+ "-t",
325
+ "--time",
326
+ type=int,
327
+ required=True,
328
+ show_default=True,
329
+ default=240,
330
+ help=(
331
+ "The maximum runtime duration for this Jupyter server instance, in minutes. If the server job is still running "
332
+ "at the end of this time limit, the job will be forcibly terminated by SLURM. Note, to prevent hogging the "
333
+ "server, make sure this parameter is always set to the smallest feasible period of time you intend to interact "
334
+ "with the server."
335
+ ),
336
+ )
337
+ @click.option(
338
+ "-p",
339
+ "--port",
340
+ type=int,
341
+ required=True,
342
+ show_default=True,
343
+ default=0,
344
+ help=(
345
+ "The port to use for the Jupyter server communication on the remote server. Valid port values are from 8888 "
346
+ "to 9999. Most runtimes should leave this set to the default value (0), which will randomly select one of the "
347
+ "valid ports. Using random selection minimizes the chances of colliding with other interactive jupyter "
348
+ "sessions."
349
+ ),
350
+ )
351
+ def start_jupyter_server(
352
+ credentials_path: Path, name: str, environment: str, directory: Path, cores: int, memory: int, time: int, port: int
353
+ ) -> None:
354
+ """Starts an interactive Jupyter session on the remote Sun lab server.
355
+
356
+ This command should be used to run Jupyter lab and notebooks sessions on the remote Sun lab server. Since all lab
357
+ data is stored on the server, this allows running light interactive analysis sessions on the same node as the data,
358
+ while leveraging considerable compute resources of the server.
359
+
360
+ Calling this command initializes a SLURM session that runs the interactive Jupyter server. Since this server
361
+ directly competes for resources with all other headless jobs running on the server, it is imperative that each
362
+ jupyter runtime uses only the minimum amount of resources and run-time as necessary. Do not use this command to run
363
+ heavy data processing pipelines! Instead, consult with library documentation and use the headless Job class.
364
+ """
365
+ # Initializes server connection
366
+ server = Server(credentials_path)
367
+ job: JupyterJob | None = None
368
+ try:
369
+ # If the caller did not provide an explicit notebook directory, defaults to user's working directory
370
+ if directory is None:
371
+ directory = (server.user_working_root,)
372
+
373
+ # Launches the specified Jupyter server
374
+ job = server.launch_jupyter_server(
375
+ job_name=name,
376
+ conda_environment=environment,
377
+ notebook_directory=directory,
378
+ cpus_to_use=cores,
379
+ ram_gb=memory,
380
+ port=port,
381
+ time_limit=time,
382
+ )
383
+
384
+ # Displays the server connection details to the user via terminal
385
+ job.print_connection_info()
386
+
387
+ # Blocks in-place until the user shuts down the server. This allows terminating the jupyter job early if the
388
+ # user is done working with the server
389
+ input("Enter anything to shut down the server: ")
390
+
391
+ # Ensures that the server created as part of this CLI is always terminated when the CLI terminates
392
+ finally:
393
+ # Terminates the server job
394
+ if job is not None:
395
+ server.abort_job(job)
396
+
397
+ # Closes server connection if it is still open
398
+ server.close()
399
+
400
+
401
+ @click.command()
402
+ @click.option(
403
+ "-sp",
404
+ "--session_path",
405
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path),
406
+ required=True,
407
+ help="The absolute path to the session directory for which to resolve the dataset integration readiness marker.",
408
+ )
409
+ @click.option(
410
+ "-c",
411
+ "--create_processed_directories",
412
+ is_flag=True,
413
+ show_default=True,
414
+ default=False,
415
+ help="Determines whether to create the processed data hierarchy. This flag should be disabled for most runtimes.",
416
+ )
417
+ @click.option(
418
+ "-ppp",
419
+ "--project_processed_path",
420
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path),
421
+ required=False,
422
+ help=(
423
+ "The absolute path to the project directory where processed session data is stored, if different from the "
424
+ "directory used to store raw session data. Typically, this extra argument is only used when processing data "
425
+ "stored on remote compute server(s)."
426
+ ),
427
+ )
428
+ @click.option(
429
+ "-r",
430
+ "--remove",
431
+ is_flag=True,
432
+ show_default=True,
433
+ default=False,
434
+ help=(
435
+ "Determines whether the command should create or remove the dataset integration marker. Do not enable this "
436
+ "flag unless you know what you are doing. It is only safe to enable this flag if the session is not currently "
437
+ "being integrated into any datasets."
438
+ ),
439
+ )
440
+ def resolve_dataset_marker(
441
+ session_path: Path, create_processed_directories: bool, project_processed_path: Path | None, remove: bool
442
+ ) -> None:
443
+ """Depending on configuration, either creates or removes the p53.bin marker from the target session.
444
+
445
+ The p53.bin marker determines whether the session is ready for dataset integration. When the marker exists,
446
+ processing pipelines are not allowed to work with the session data, ensuring that all processed data remains
447
+ unchanged. If the marker does not exist, dataset integration pipelines are not allowed to work with the session
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
+ """
454
+ resolve_p53_marker(
455
+ session_path=session_path,
456
+ create_processed_data_directory=create_processed_directories,
457
+ processed_data_root=project_processed_path,
458
+ remove=remove,
459
+ )