babs 0.3.2__tar.gz → 0.4.0__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.
- {babs-0.3.2 → babs-0.4.0}/.circleci/config.yml +34 -51
- {babs-0.3.2 → babs-0.4.0}/Dockerfile +3 -2
- {babs-0.3.2 → babs-0.4.0}/DockerfileSLURM +4 -5
- babs-0.4.0/Dockerfile_testing +6 -0
- {babs-0.3.2 → babs-0.4.0}/PKG-INFO +5 -3
- {babs-0.3.2 → babs-0.4.0}/README.rst +3 -0
- babs-0.4.0/babs/__init__.py +13 -0
- {babs-0.3.2 → babs-0.4.0}/babs/_version.py +2 -2
- babs-0.4.0/babs/base.py +207 -0
- babs-0.4.0/babs/bootstrap.py +532 -0
- babs-0.4.0/babs/check_setup.py +322 -0
- babs-0.4.0/babs/cli.py +603 -0
- {babs-0.3.2 → babs-0.4.0}/babs/constants.py +0 -1
- {babs-0.3.2 → babs-0.4.0}/babs/container.py +2 -2
- {babs-0.3.2 → babs-0.4.0}/babs/generate_bidsapp_runscript.py +6 -54
- babs-0.4.0/babs/input_dataset.py +383 -0
- babs-0.4.0/babs/input_datasets.py +128 -0
- babs-0.4.0/babs/interaction.py +203 -0
- babs-0.4.0/babs/merge.py +298 -0
- babs-0.4.0/babs/scheduler.py +353 -0
- babs-0.4.0/babs/templates/babs_proj_config.yaml.jinja2 +17 -0
- {babs-0.3.2 → babs-0.4.0}/babs/templates/bidsapp_run.sh.jinja2 +1 -3
- {babs-0.3.2 → babs-0.4.0}/babs/templates/determine_zipfilename.sh.jinja2 +2 -2
- babs-0.4.0/babs/templates/job_status_report.jinja +18 -0
- {babs-0.3.2 → babs-0.4.0}/babs/templates/participant_job.sh.jinja2 +10 -7
- babs-0.4.0/babs/templates/test_array_job.sh.jinja2 +24 -0
- {babs-0.3.2 → babs-0.4.0}/babs/templates/unzip_inputds.sh.jinja2 +1 -1
- babs-0.4.0/babs/utils.py +794 -0
- {babs-0.3.2 → babs-0.4.0}/docs/babs-init.rst +3 -3
- {babs-0.3.2 → babs-0.4.0}/docs/cli.rst +3 -4
- {babs-0.3.2 → babs-0.4.0}/docs/create_babs_project.rst +1 -1
- {babs-0.3.2 → babs-0.4.0}/docs/developer_babs_status.rst +8 -8
- {babs-0.3.2 → babs-0.4.0}/docs/jobs.rst +12 -13
- {babs-0.3.2 → babs-0.4.0}/docs/preparation_config_yaml_file.rst +5 -6
- {babs-0.3.2 → babs-0.4.0}/docs/preparation_container.rst +12 -23
- babs-0.4.0/docs/walkthrough.rst +735 -0
- {babs-0.3.2 → babs-0.4.0}/docs/walkthrough_babs-check-setup_printed_messages.txt +6 -7
- {babs-0.3.2 → babs-0.4.0}/docs/whats_new.md +25 -3
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_aslprep-0-7-5.yaml +10 -6
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_fmriprep-24-1-1_anatonly.yaml +9 -5
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_fmriprep-24-1-1_ingressed-fs.yaml +16 -7
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_fmriprep-24-1-1_regular.yaml +9 -6
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_mriqc-24-0-2.yaml +7 -0
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_qsiprep-1-0-0_regular.yaml +17 -7
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_qsirecon-1-0-1_custom_spec.yaml +10 -0
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_qsirecon-1-0-1_hsvs.yaml +18 -2
- babs-0.4.0/notebooks/eg_simbids_0-0-3_multiinput.yaml +41 -0
- babs-0.4.0/notebooks/eg_simbids_0-0-3_raw_mri.yaml +42 -0
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_toybidsapp-0-0-7_rawBIDS-walkthrough.yaml +7 -0
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_toybidsapp-0-0-7_zipped.yaml +6 -4
- {babs-0.3.2 → babs-0.4.0}/notebooks/eg_xcpd-0-10-6_linc.yaml +10 -2
- {babs-0.3.2 → babs-0.4.0}/pyproject.toml +4 -2
- babs-0.4.0/tests/conftest.py +244 -0
- babs-0.4.0/tests/e2e-slurm/container/config_simbids.yaml +38 -0
- babs-0.4.0/tests/e2e-slurm/container/config_simbids_multiinput.yaml +41 -0
- babs-0.4.0/tests/e2e-slurm/container/simbids_fmriprep-24-1-1_anatonly.yaml +45 -0
- {babs-0.3.2 → babs-0.4.0}/tests/e2e-slurm/container/walkthrough-tests.sh +60 -54
- babs-0.4.0/tests/e2e_in_docker.sh +17 -0
- babs-0.4.0/tests/pytest_in_docker.sh +13 -0
- babs-0.4.0/tests/test_babs_workflow.py +186 -0
- {babs-0.3.2 → babs-0.4.0}/tests/test_generate_bidsapp_runscript.py +14 -14
- {babs-0.3.2 → babs-0.4.0}/tests/test_generate_submit_script.py +14 -14
- babs-0.4.0/tests/test_input_datasets.py +229 -0
- babs-0.4.0/tests/test_slurm.py +136 -0
- babs-0.4.0/tests/test_template_job.py +55 -0
- babs-0.4.0/tests/test_utils.py +211 -0
- babs-0.3.2/Dockerfile_testing +0 -6
- babs-0.3.2/babs/__init__.py +0 -6
- babs-0.3.2/babs/babs.py +0 -1913
- babs-0.3.2/babs/cli.py +0 -1286
- babs-0.3.2/babs/input_datasets.py +0 -599
- babs-0.3.2/babs/templates/babs_proj_config.yaml.jinja2 +0 -17
- babs-0.3.2/babs/templates/datalad_run.sh.jinja2 +0 -20
- babs-0.3.2/babs/utils.py +0 -1339
- babs-0.3.2/docs/babs-sync-code.rst +0 -45
- babs-0.3.2/docs/walkthrough.rst +0 -909
- babs-0.3.2/docs/walkthrough_babs-init_printed_messages.txt +0 -154
- babs-0.3.2/tests/download_datasets.py +0 -30
- babs-0.3.2/tests/e2e-slurm/container/config_toybidsapp.yaml +0 -1
- babs-0.3.2/tests/get_data.py +0 -290
- babs-0.3.2/tests/origin_input_dataset.yaml +0 -9
- babs-0.3.2/tests/pytest_in_docker.sh +0 -7
- babs-0.3.2/tests/test_babs_check_setup.py +0 -143
- babs-0.3.2/tests/test_babs_init.py +0 -315
- babs-0.3.2/tests/test_input_datasets.py +0 -290
- {babs-0.3.2 → babs-0.4.0}/.codespellrc +0 -0
- {babs-0.3.2 → babs-0.4.0}/.gitattributes +0 -0
- {babs-0.3.2 → babs-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {babs-0.3.2 → babs-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {babs-0.3.2 → babs-0.4.0}/.github/release.yml +0 -0
- {babs-0.3.2 → babs-0.4.0}/.github/workflows/codespell.yml +0 -0
- {babs-0.3.2 → babs-0.4.0}/.github/workflows/e2e-slurm.yml +0 -0
- {babs-0.3.2 → babs-0.4.0}/.github/workflows/ruff.yml +0 -0
- {babs-0.3.2 → babs-0.4.0}/.github/workflows/shellcheck.yml +0 -0
- {babs-0.3.2 → babs-0.4.0}/.gitignore +0 -0
- {babs-0.3.2 → babs-0.4.0}/.readthedocs.yaml +0 -0
- {babs-0.3.2 → babs-0.4.0}/CITATION.cff +0 -0
- {babs-0.3.2 → babs-0.4.0}/LICENSE +0 -0
- {babs-0.3.2 → babs-0.4.0}/MANIFEST.in +0 -0
- {babs-0.3.2 → babs-0.4.0}/Makefile +0 -0
- {babs-0.3.2 → babs-0.4.0}/babs/bids_skeletons/multi_ses_qsiprep.yaml +0 -0
- {babs-0.3.2 → babs-0.4.0}/babs/bids_skeletons/no_ses_qsiprep.yaml +0 -0
- {babs-0.3.2 → babs-0.4.0}/babs/dict_cluster_systems.yaml +0 -0
- {babs-0.3.2 → babs-0.4.0}/babs/generate_submit_script.py +0 -0
- {babs-0.3.2 → babs-0.4.0}/babs/system.py +0 -0
- {babs-0.3.2 → babs-0.4.0}/babs/template_test_job.py +0 -0
- {babs-0.3.2 → babs-0.4.0}/babs/templates/filter_file.sh.jinja2 +0 -0
- {babs-0.3.2 → babs-0.4.0}/babs/templates/job_submit.yaml.jinja2 +0 -0
- {babs-0.3.2 → babs-0.4.0}/babs/templates/test_job.sh.jinja2 +0 -0
- {babs-0.3.2 → babs-0.4.0}/babs/templates/zipping.sh.jinja2 +0 -0
- {babs-0.3.2 → babs-0.4.0}/docker/docker-entrypoint.sh +0 -0
- {babs-0.3.2 → babs-0.4.0}/docker/environment.yml +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/Makefile +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/_static/babs_cli.png +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/_static/babs_workflow.png +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/_static/datalad_logo.png +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/_templates/autosummary/module.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/after_jobs.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/babs-check-setup.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/babs-merge.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/babs-status.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/babs-submit.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/conf.py +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/developer.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/developer_config_yaml_file.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/developer_how_to_test.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/index.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/installation.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/links.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/overview.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/preparation.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/preparation_input_dataset.rst +0 -0
- {babs-0.3.2 → babs-0.4.0}/docs/walkthrough_babs-merge_printed_messages.txt +0 -0
- {babs-0.3.2 → babs-0.4.0}/environment_hpc.yml +0 -0
- {babs-0.3.2 → babs-0.4.0}/notebooks/README.md +0 -0
- {babs-0.3.2 → babs-0.4.0}/notebooks/initial_sub_list_multi-ses.csv +0 -0
- {babs-0.3.2 → babs-0.4.0}/notebooks/initial_sub_list_single-ses.csv +0 -0
- {babs-0.3.2 → babs-0.4.0}/tests/e2e-slurm/container/sleep_array.sh +0 -0
- {babs-0.3.2 → babs-0.4.0}/tests/test_system.py +0 -0
- {babs-0.3.2 → babs-0.4.0}/tox.ini +0 -0
|
@@ -2,55 +2,47 @@
|
|
|
2
2
|
# See: https://circleci.com/docs/2.0/configuration-reference
|
|
3
3
|
version: 2.1
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- image: pennlinc/slurm-docker-ci:0.11
|
|
5
|
+
orbs:
|
|
6
|
+
codecov: codecov/codecov@5.2.1
|
|
8
7
|
|
|
9
8
|
jobs:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
steps:
|
|
15
|
-
- checkout:
|
|
16
|
-
path: /home/circleci/src/babs
|
|
17
|
-
- restore_cache:
|
|
18
|
-
keys:
|
|
19
|
-
- test-data-v2
|
|
20
|
-
- run:
|
|
21
|
-
name: Download test datasets
|
|
22
|
-
command: |
|
|
23
|
-
mkdir -p /home/circleci/test_data
|
|
24
|
-
cd /home/circleci/test_data
|
|
25
|
-
# Install datalad if not already in the image
|
|
26
|
-
pip install datalad-osf
|
|
27
|
-
# Download each dataset from origin_input_dataset.yaml
|
|
28
|
-
python3 /home/circleci/src/babs/tests/download_datasets.py
|
|
29
|
-
# Debug output
|
|
30
|
-
echo "Contents of test_data directory:"
|
|
31
|
-
ls -la /home/circleci/test_data/
|
|
32
|
-
- save_cache:
|
|
33
|
-
key: test-data-v2
|
|
34
|
-
paths:
|
|
35
|
-
- /home/circleci/test_data
|
|
36
|
-
|
|
37
|
-
pytest: # run pytest
|
|
38
|
-
<<: *dockersetup
|
|
39
|
-
resource_class: xlarge
|
|
9
|
+
pytest:
|
|
10
|
+
machine:
|
|
11
|
+
image: ubuntu-2204:current
|
|
12
|
+
resource_class: large
|
|
40
13
|
working_directory: /home/circleci/src/babs
|
|
41
14
|
steps:
|
|
42
15
|
- checkout:
|
|
43
16
|
path: /home/circleci/src/babs
|
|
44
|
-
- restore_cache:
|
|
45
|
-
keys:
|
|
46
|
-
- test-data-v2
|
|
47
17
|
- run:
|
|
48
18
|
name: pytest of BABS
|
|
49
19
|
no_output_timeout: 1h
|
|
50
20
|
command: |
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
21
|
+
docker build \
|
|
22
|
+
-t pennlinc/slurm-docker-ci:unstable \
|
|
23
|
+
-f Dockerfile_testing .
|
|
24
|
+
|
|
25
|
+
# Make a directory that will hold the test artifacts
|
|
26
|
+
mkdir -p ${HOME}/e2e-testing
|
|
27
|
+
docker run -it \
|
|
28
|
+
-v ${PWD}:/tests \
|
|
29
|
+
-v ${HOME}/e2e-testing:/test-temp:rw \
|
|
30
|
+
-h slurmctl --cap-add sys_admin \
|
|
31
|
+
--privileged \
|
|
32
|
+
pennlinc/slurm-docker-ci:unstable \
|
|
33
|
+
pytest -n 4 -sv \
|
|
34
|
+
--durations=0 \
|
|
35
|
+
--timeout=300 \
|
|
36
|
+
--junitxml=/test-temp/junit.xml \
|
|
37
|
+
--cov-report term-missing \
|
|
38
|
+
--cov-report xml:/test-temp/coverage.xml \
|
|
39
|
+
--cov=babs \
|
|
40
|
+
/babs
|
|
41
|
+
|
|
42
|
+
- store_test_results:
|
|
43
|
+
path: /home/circleci/e2e-testing/junit.xml
|
|
44
|
+
- codecov/upload:
|
|
45
|
+
files: /home/circleci/e2e-testing/coverage.xml
|
|
54
46
|
|
|
55
47
|
e2e-slurm:
|
|
56
48
|
machine:
|
|
@@ -61,9 +53,6 @@ jobs:
|
|
|
61
53
|
steps:
|
|
62
54
|
- checkout:
|
|
63
55
|
path: /home/circleci/src/babs
|
|
64
|
-
- restore_cache:
|
|
65
|
-
keys:
|
|
66
|
-
- test-data-v2
|
|
67
56
|
- run:
|
|
68
57
|
name: pytest of BABS
|
|
69
58
|
no_output_timeout: 1h
|
|
@@ -103,7 +92,9 @@ jobs:
|
|
|
103
92
|
destination: test-artifacts
|
|
104
93
|
|
|
105
94
|
deployable: # checkpoint of deployable: requires all success
|
|
106
|
-
|
|
95
|
+
resource_class: small
|
|
96
|
+
docker:
|
|
97
|
+
- image: busybox:latest
|
|
107
98
|
steps:
|
|
108
99
|
- run: echo Deploying!
|
|
109
100
|
|
|
@@ -128,19 +119,11 @@ workflows:
|
|
|
128
119
|
# version: 2
|
|
129
120
|
build_test_deploy:
|
|
130
121
|
jobs:
|
|
131
|
-
- download_test_data:
|
|
132
|
-
filters:
|
|
133
|
-
tags:
|
|
134
|
-
only: /.*/
|
|
135
122
|
- pytest:
|
|
136
|
-
requires:
|
|
137
|
-
- download_test_data
|
|
138
123
|
filters:
|
|
139
124
|
tags:
|
|
140
125
|
only: /.*/
|
|
141
126
|
- e2e-slurm:
|
|
142
|
-
requires:
|
|
143
|
-
- download_test_data
|
|
144
127
|
filters:
|
|
145
128
|
tags:
|
|
146
129
|
only: /.*/
|
|
@@ -36,8 +36,9 @@ RUN git config --global user.name "CircleCI" \
|
|
|
36
36
|
# Create toy bids app
|
|
37
37
|
RUN mkdir -p /singularity_images \
|
|
38
38
|
&& apptainer build \
|
|
39
|
-
/singularity_images/
|
|
40
|
-
docker://pennlinc/
|
|
39
|
+
/singularity_images/simbids_0.0.1.sif \
|
|
40
|
+
docker://pennlinc/simbids:0.0.1
|
|
41
|
+
|
|
41
42
|
|
|
42
43
|
# # install BABS
|
|
43
44
|
# COPY . $HOME/babs
|
|
@@ -19,12 +19,11 @@ ENV PATH=/opt/conda/envs/babs/bin:$PATH
|
|
|
19
19
|
RUN git config --global user.name "CircleCI" \
|
|
20
20
|
&& git config --global user.email "circleci@example.com"
|
|
21
21
|
|
|
22
|
-
#
|
|
22
|
+
# Add Simbids
|
|
23
23
|
RUN mkdir -p /singularity_images \
|
|
24
|
-
&&
|
|
25
|
-
/singularity_images/
|
|
26
|
-
docker://pennlinc/
|
|
27
|
-
|
|
24
|
+
&& apptainer build \
|
|
25
|
+
/singularity_images/simbids_0.0.3.sif \
|
|
26
|
+
docker://pennlinc/simbids:0.0.3
|
|
28
27
|
# # install BABS
|
|
29
28
|
# COPY . /babs
|
|
30
29
|
# WORKDIR /babs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: babs
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: BABS: BIDS App BootStrap
|
|
5
5
|
Project-URL: Homepage, https://github.com/pennlinc/babs
|
|
6
6
|
Project-URL: Documentation, https://pennlinc-babs.readthedocs.io/en/stable/
|
|
@@ -41,6 +41,7 @@ Requires-Dist: pyyaml>=6.0
|
|
|
41
41
|
Requires-Dist: regex
|
|
42
42
|
Requires-Dist: tqdm
|
|
43
43
|
Provides-Extra: all
|
|
44
|
+
Requires-Dist: coverage; extra == 'all'
|
|
44
45
|
Requires-Dist: datalad-osf; extra == 'all'
|
|
45
46
|
Requires-Dist: docutils<0.17; extra == 'all'
|
|
46
47
|
Requires-Dist: fuzzywuzzy; extra == 'all'
|
|
@@ -48,7 +49,7 @@ Requires-Dist: jinja2<3.1.0; extra == 'all'
|
|
|
48
49
|
Requires-Dist: myst-parser; extra == 'all'
|
|
49
50
|
Requires-Dist: pre-commit; extra == 'all'
|
|
50
51
|
Requires-Dist: pytest; extra == 'all'
|
|
51
|
-
Requires-Dist: pytest-
|
|
52
|
+
Requires-Dist: pytest-cov; extra == 'all'
|
|
52
53
|
Requires-Dist: pytest-xdist; extra == 'all'
|
|
53
54
|
Requires-Dist: python-levenshtein; extra == 'all'
|
|
54
55
|
Requires-Dist: recommonmark==0.7.1; extra == 'all'
|
|
@@ -73,7 +74,8 @@ Provides-Extra: maint
|
|
|
73
74
|
Requires-Dist: fuzzywuzzy; extra == 'maint'
|
|
74
75
|
Requires-Dist: python-levenshtein; extra == 'maint'
|
|
75
76
|
Provides-Extra: tests
|
|
77
|
+
Requires-Dist: coverage; extra == 'tests'
|
|
76
78
|
Requires-Dist: datalad-osf; extra == 'tests'
|
|
77
79
|
Requires-Dist: pytest; extra == 'tests'
|
|
78
|
-
Requires-Dist: pytest-
|
|
80
|
+
Requires-Dist: pytest-cov; extra == 'tests'
|
|
79
81
|
Requires-Dist: pytest-xdist; extra == 'tests'
|
|
@@ -7,6 +7,9 @@ BABS: BIDS App Bootstrap
|
|
|
7
7
|
:alt: Documentation Status
|
|
8
8
|
.. image:: https://circleci.com/gh/PennLINC/babs/tree/main.svg?style=svg
|
|
9
9
|
:target: https://circleci.com/gh/PennLINC/babs/tree/main
|
|
10
|
+
.. image:: https://codecov.io/gh/PennLINC/babs/branch/main/graph/badge.svg
|
|
11
|
+
:target: https://codecov.io/gh/PennLINC/babs
|
|
12
|
+
:alt: Code Coverage
|
|
10
13
|
.. image:: https://zenodo.org/badge/456981533.svg
|
|
11
14
|
:target: https://zenodo.org/badge/latestdoi/456981533
|
|
12
15
|
:alt: DOI
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Top-level package for BABS."""
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
from ._version import __version__
|
|
5
|
+
except ImportError:
|
|
6
|
+
__version__ = '0+unknown'
|
|
7
|
+
|
|
8
|
+
from .bootstrap import BABSBootstrap
|
|
9
|
+
from .check_setup import BABSCheckSetup
|
|
10
|
+
from .interaction import BABSInteraction
|
|
11
|
+
from .merge import BABSMerge
|
|
12
|
+
|
|
13
|
+
__all__ = ['BABSBootstrap', 'BABSCheckSetup', 'BABSInteraction', 'BABSMerge']
|
babs-0.4.0/babs/base.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""This is the main module."""
|
|
2
|
+
|
|
3
|
+
import os.path as op
|
|
4
|
+
import subprocess
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from urllib.parse import urlparse
|
|
7
|
+
|
|
8
|
+
from babs.input_datasets import InputDatasets
|
|
9
|
+
from babs.system import validate_queue
|
|
10
|
+
from babs.utils import (
|
|
11
|
+
read_yaml,
|
|
12
|
+
validate_processing_level,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
CONFIG_SECTIONS = ['processing_level', 'queue', 'input_datasets', 'container']
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BABS:
|
|
19
|
+
"""The BABS base class holds common attributes and methods for all BABS classes."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, project_root):
|
|
22
|
+
"""The BABS class is for babs projects of BIDS Apps.
|
|
23
|
+
|
|
24
|
+
The constructor only initializes the attributes.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
project_root: Path
|
|
29
|
+
absolute path to the root of this babs project
|
|
30
|
+
|
|
31
|
+
Attributes
|
|
32
|
+
----------
|
|
33
|
+
project_root: str
|
|
34
|
+
absolute path to the root of this babs project
|
|
35
|
+
processing_level : {'subject', 'session'}
|
|
36
|
+
whether processing is done on a subject-wise or session-wise basis
|
|
37
|
+
queue: str
|
|
38
|
+
the type of job scheduling system, "sge" or "slurm"
|
|
39
|
+
config_path: str
|
|
40
|
+
path to the config yaml file
|
|
41
|
+
analysis_path: str
|
|
42
|
+
path to the `analysis` folder.
|
|
43
|
+
analysis_datalad_handle: datalad dataset
|
|
44
|
+
the `analysis` datalad dataset
|
|
45
|
+
input_ria_path: str
|
|
46
|
+
Path to the input RIA store, the sibling of `analysis`.
|
|
47
|
+
The computation of each job will start with a clone from this input RIA store.
|
|
48
|
+
output_ria_path: str
|
|
49
|
+
Path to the output RIA store, the sibling of `analysis`.
|
|
50
|
+
The results of jobs will be pushed to this output RIA store.
|
|
51
|
+
input_ria_url: str
|
|
52
|
+
URL of input RIA store, starting with "ria+file://".
|
|
53
|
+
output_ria_url: str
|
|
54
|
+
URL of output RIA store, starting with "ria+file://".
|
|
55
|
+
output_ria_data_dir: str
|
|
56
|
+
Path to the output RIA's data directory.
|
|
57
|
+
Example: /full/path/to/project_root/output_ria/238/da2f2-2fc4-4b88-a2c5-aa6e754b5d0b
|
|
58
|
+
analysis_dataset_id: str
|
|
59
|
+
The ID of DataLad dataset `analysis`.
|
|
60
|
+
This will be used to get the full path to the dataset in input RIA.
|
|
61
|
+
Example: '238da2f2-2fc4-4b88-a2c5-aa6e754b5d0b'
|
|
62
|
+
list_sub_path_rel: str
|
|
63
|
+
Path to the list of final included subjects (and sessions) CSV file.
|
|
64
|
+
This is relative to `analysis` folder.
|
|
65
|
+
list_sub_path_abs: str
|
|
66
|
+
Absolute path of `list_sub_path_rel`.
|
|
67
|
+
Example: '/path/to/analysis/code/processing_inclusion.csv'
|
|
68
|
+
job_status_path_rel: str
|
|
69
|
+
Path to the `job_status.csv` file.
|
|
70
|
+
This is relative to `analysis` folder.
|
|
71
|
+
job_status_path_abs: str
|
|
72
|
+
Absolute path of `job_status_path_abs`.
|
|
73
|
+
Example: '/path/to/analysis/code/job_status.csv'
|
|
74
|
+
job_submit_path_abs: str
|
|
75
|
+
Absolute path of `job_submit_path_abs`.
|
|
76
|
+
Example: '/path/to/analysis/code/job_submit.csv'
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
# validation:
|
|
80
|
+
|
|
81
|
+
# attributes:
|
|
82
|
+
self.project_root = str(project_root)
|
|
83
|
+
|
|
84
|
+
self.analysis_path = op.join(self.project_root, 'analysis')
|
|
85
|
+
self.analysis_datalad_handle = None
|
|
86
|
+
|
|
87
|
+
self.config_path = op.join(self.analysis_path, 'code/babs_proj_config.yaml')
|
|
88
|
+
|
|
89
|
+
self.input_ria_path = op.join(self.project_root, 'input_ria')
|
|
90
|
+
self.output_ria_path = op.join(self.project_root, 'output_ria')
|
|
91
|
+
|
|
92
|
+
self.input_ria_url = 'ria+file://' + self.input_ria_path
|
|
93
|
+
self.output_ria_url = 'ria+file://' + self.output_ria_path
|
|
94
|
+
|
|
95
|
+
self.output_ria_data_dir = None # not known yet before output_ria is created
|
|
96
|
+
self.analysis_dataset_id = None # to update later
|
|
97
|
+
|
|
98
|
+
self.list_sub_path_rel = 'code/processing_inclusion.csv'
|
|
99
|
+
self.list_sub_path_abs = op.join(self.analysis_path, self.list_sub_path_rel)
|
|
100
|
+
|
|
101
|
+
self.job_status_path_rel = 'code/job_status.csv'
|
|
102
|
+
self.job_status_path_abs = op.join(self.analysis_path, self.job_status_path_rel)
|
|
103
|
+
self.job_submit_path_abs = op.join(self.analysis_path, 'code/job_submit.csv')
|
|
104
|
+
self._apply_config()
|
|
105
|
+
|
|
106
|
+
def _apply_config(self):
|
|
107
|
+
"""Apply the configuration to the BABS project.
|
|
108
|
+
|
|
109
|
+
The following attributes are set in this function:
|
|
110
|
+
|
|
111
|
+
- processing_level
|
|
112
|
+
- queue
|
|
113
|
+
- container
|
|
114
|
+
- input_datasets
|
|
115
|
+
|
|
116
|
+
"""
|
|
117
|
+
# Sanity check: the path `project_root` exists:
|
|
118
|
+
if not op.exists(self.project_root):
|
|
119
|
+
raise Exception(
|
|
120
|
+
f'`project_root` does not exist! Requested `project_root` was: {self.project_root}'
|
|
121
|
+
)
|
|
122
|
+
if not op.exists(self.analysis_path):
|
|
123
|
+
raise FileNotFoundError(
|
|
124
|
+
f'Missing: {self.analysis_path}\n'
|
|
125
|
+
f'{self.project_root} is not a valid BABS project.\n\n'
|
|
126
|
+
'Please run `babs init` first.'
|
|
127
|
+
)
|
|
128
|
+
if not op.exists(self.config_path):
|
|
129
|
+
raise FileNotFoundError(
|
|
130
|
+
f'Missing: {self.config_path}\n'
|
|
131
|
+
f'{self.project_root} is not a valid BABS project.\n\n'
|
|
132
|
+
'Please run `babs init` first.'
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
config_yaml = read_yaml(self.config_path)
|
|
136
|
+
for section in CONFIG_SECTIONS:
|
|
137
|
+
if section not in config_yaml:
|
|
138
|
+
raise ValueError(f'Section {section} not found in {self.config_path}')
|
|
139
|
+
|
|
140
|
+
self.processing_level = validate_processing_level(config_yaml['processing_level'])
|
|
141
|
+
self.queue = validate_queue(config_yaml['queue'])
|
|
142
|
+
self.container = config_yaml['container']
|
|
143
|
+
|
|
144
|
+
# Check the output RIA:
|
|
145
|
+
self.wtf_key_info(flag_output_ria_only=True)
|
|
146
|
+
|
|
147
|
+
self.input_datasets = InputDatasets(self.processing_level, config_yaml['input_datasets'])
|
|
148
|
+
self.input_datasets.update_abs_paths(Path(self.project_root) / 'analysis')
|
|
149
|
+
|
|
150
|
+
def wtf_key_info(self, flag_output_ria_only=False):
|
|
151
|
+
"""
|
|
152
|
+
This is to get some key information on DataLad dataset `analysis`,
|
|
153
|
+
and assign to `output_ria_data_dir` and `analysis_dataset_id`.
|
|
154
|
+
This function relies on `git` and `datalad wtf`
|
|
155
|
+
This needs to be done after the output RIA is created.
|
|
156
|
+
|
|
157
|
+
Parameters
|
|
158
|
+
----------
|
|
159
|
+
flag_output_ria_only: bool
|
|
160
|
+
if only to get information on output RIA.
|
|
161
|
+
This may expedite the process as other information requires
|
|
162
|
+
calling `datalad` in terminal, which would takes several seconds.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
# Get the `self.output_ria_data_dir`:
|
|
166
|
+
# e.g., /full/path/output_ria/238/da2f2-2fc4-4b88-a2c5-aa6e754b5d0b
|
|
167
|
+
analysis_git_path = op.join(self.analysis_path, '.git')
|
|
168
|
+
proc_output_ria_data_dir = subprocess.run(
|
|
169
|
+
[
|
|
170
|
+
'git',
|
|
171
|
+
'--git-dir',
|
|
172
|
+
analysis_git_path,
|
|
173
|
+
'remote',
|
|
174
|
+
'get-url',
|
|
175
|
+
'--push',
|
|
176
|
+
'output',
|
|
177
|
+
],
|
|
178
|
+
stdout=subprocess.PIPE,
|
|
179
|
+
)
|
|
180
|
+
# ^^: for `analysis`: git remote get-url --push output
|
|
181
|
+
# ^^ another way to change the wd temporarily: add `cwd=self.xxx` in `subprocess.run()`
|
|
182
|
+
# if success: no output; if failed: will raise CalledProcessError
|
|
183
|
+
proc_output_ria_data_dir.check_returncode()
|
|
184
|
+
self.output_ria_data_dir = urlparse(proc_output_ria_data_dir.stdout.decode('utf-8')).path
|
|
185
|
+
if self.output_ria_data_dir[-1:] == '\n':
|
|
186
|
+
# remove the last 2 characters
|
|
187
|
+
self.output_ria_data_dir = self.output_ria_data_dir[:-1]
|
|
188
|
+
|
|
189
|
+
if not flag_output_ria_only: # also want other information:
|
|
190
|
+
# Get the dataset ID of `analysis`, i.e., `analysis_dataset_id`:
|
|
191
|
+
# way #2: command line of datalad:
|
|
192
|
+
proc_analysis_dataset_id = subprocess.run(
|
|
193
|
+
['datalad', '-f', "'{infos[dataset][id]}'", 'wtf', '-S', 'dataset'],
|
|
194
|
+
cwd=self.analysis_path,
|
|
195
|
+
stdout=subprocess.PIPE,
|
|
196
|
+
)
|
|
197
|
+
# datalad -f '{infos[dataset][id]}' wtf -S dataset
|
|
198
|
+
proc_analysis_dataset_id.check_returncode()
|
|
199
|
+
self.analysis_dataset_id = proc_analysis_dataset_id.stdout.decode('utf-8')
|
|
200
|
+
# remove the `\n`:
|
|
201
|
+
if self.analysis_dataset_id[-1:] == '\n':
|
|
202
|
+
# remove the last 2 characters
|
|
203
|
+
self.analysis_dataset_id = self.analysis_dataset_id[:-1]
|
|
204
|
+
# remove the double quotes:
|
|
205
|
+
if (self.analysis_dataset_id[0] == "'") & (self.analysis_dataset_id[-1] == "'"):
|
|
206
|
+
# if first and the last characters are quotes: remove them
|
|
207
|
+
self.analysis_dataset_id = self.analysis_dataset_id[1:-1]
|