Skip to content

Commit 034a3d5

Browse files
authored
Add dataset creation code from BABS (#5)
* Update bids.py * Fix up. * Update stuff. * Use current path. * Whoops! * Fix up more stuff.
1 parent a5f656b commit 034a3d5

File tree

4 files changed

+159
-501
lines changed

4 files changed

+159
-501
lines changed

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ classifiers = [
1919
]
2020
dependencies = [
2121
"acres",
22+
"datalad",
2223
"nipype",
24+
"pandas",
2325
"pybids >= 0.15.6",
2426
"typer",
27+
"yaml",
2528
]
2629
dynamic = ["version"]
2730

src/simbids/cli/run.py

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,9 @@ def main():
3434
import sys
3535
from multiprocessing import Manager, Process
3636
from os import EX_SOFTWARE
37-
from pathlib import Path
3837

3938
from simbids.cli.parser import parse_args
4039
from simbids.cli.workflow import build_workflow
41-
from simbids.utils.bids import write_bidsignore, write_derivative_description
4240

4341
parse_args()
4442

@@ -144,7 +142,6 @@ def main():
144142
'\n'.join(['SimBIDS config:'] + [f'\t\t{s}' for s in config.dumps().splitlines()]),
145143
)
146144
config.loggers.workflow.log(25, 'SimBIDS started!')
147-
errno = 1 # Default is error exit unless otherwise set
148145
try:
149146
simbids_wf.run(**config.nipype.get_plugin())
150147
except Exception as e:
@@ -172,32 +169,6 @@ def main():
172169
sentry_sdk.add_breadcrumb(message=success_message, level='info')
173170
sentry_sdk.capture_message(success_message, level='info')
174171

175-
# Bother users with the boilerplate only iff the workflow went okay.
176-
boiler_file = config.execution.output_dir / 'logs' / 'CITATION.md'
177-
if boiler_file.exists():
178-
if config.environment.exec_env in (
179-
'singularity',
180-
'docker',
181-
'simbids-docker',
182-
):
183-
boiler_file = Path('<OUTPUT_PATH>') / boiler_file.relative_to(
184-
config.execution.output_dir
185-
)
186-
187-
config.loggers.workflow.log(
188-
25,
189-
'Works derived from this SimBIDS execution should include the '
190-
f'boilerplate text found in {boiler_file}.',
191-
)
192-
193-
if config.workflow.run_reconall:
194-
from niworkflows.utils.misc import _copy_any
195-
from templateflow import api
196-
197-
dseg_tsv = str(api.get('fsaverage', suffix='dseg', extension=['.tsv']))
198-
_copy_any(dseg_tsv, str(config.execution.output_dir / 'desc-aseg_dseg.tsv'))
199-
_copy_any(dseg_tsv, str(config.execution.output_dir / 'desc-aparcaseg_dseg.tsv'))
200-
errno = 0
201172
finally:
202173
# Code Carbon
203174
if config.execution.track_carbon:
@@ -206,28 +177,6 @@ def main():
206177
config.loggers.workflow.log(25, f'Saving logs at: {config.execution.log_dir}')
207178
config.loggers.workflow.log(25, f'Carbon emissions: {emissions} kg')
208179

209-
from simbids.reports.core import generate_reports
210-
211-
# Generate reports phase
212-
failed_reports = generate_reports(
213-
subject_list=config.execution.participant_label,
214-
output_dir=config.execution.output_dir,
215-
run_uuid=config.execution.run_uuid,
216-
)
217-
write_derivative_description(
218-
input_dir=config.execution.bids_dir,
219-
output_dir=config.execution.output_dir,
220-
dataset_links=config.execution.dataset_links,
221-
)
222-
write_bidsignore(config.execution.output_dir)
223-
224-
if sentry_sdk is not None and failed_reports:
225-
sentry_sdk.capture_message(
226-
f'Report generation failed for {failed_reports} subjects',
227-
level='error',
228-
)
229-
sys.exit(int((errno + len(failed_reports)) > 0))
230-
231180

232181
def migas_exit() -> None:
233182
"""Exit migas.

src/simbids/tests/test_utils_bids.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""Test the bids module."""
2+
3+
import zipfile
4+
5+
import pytest
6+
7+
import simbids.utils.bids as sbids
8+
9+
10+
def test_simulate_dataset_no_zip(temp_dir):
11+
"""Test dataset creation without zipping."""
12+
output = sbids.simulate_dataset(temp_dir, 'multi_ses_qsiprep.yaml', 'none')
13+
14+
# Check if directory structure is created correctly
15+
assert (output / 'simbids').exists()
16+
assert (output / 'simbids' / 'sub-01').exists()
17+
assert (output / 'simbids' / 'sub-01' / 'ses-01').exists()
18+
assert (output / 'simbids' / 'dataset_description.json').exists()
19+
20+
21+
def test_simulate_dataset_subject_zip(temp_dir):
22+
"""Test dataset creation with subject-level zipping."""
23+
output = sbids.simulate_dataset(temp_dir, 'multi_ses_qsiprep.yaml', 'subject')
24+
25+
# Check if zip file is created
26+
zip_file = output / 'sub-01_simbids-1-0-1.zip'
27+
assert zip_file.exists()
28+
29+
# Verify zip contents
30+
with zipfile.ZipFile(zip_file) as zf:
31+
files = zf.namelist()
32+
assert 'simbids/sub-01/ses-01/anat/sub-01_ses-01_T1w.nii.gz' in files
33+
assert 'simbids/sub-01/ses-01/anat/sub-01_ses-01_T1w.json' in files
34+
35+
36+
def test_simulate_dataset_session_zip(temp_dir):
37+
"""Test dataset creation with session-level zipping."""
38+
output = sbids.simulate_dataset(temp_dir, 'multi_ses_qsiprep.yaml', 'session')
39+
40+
# Check if zip file is created
41+
zip_file = output / 'sub-01_ses-01_simbids-1-0-1.zip'
42+
assert zip_file.exists()
43+
44+
# Verify zip contents
45+
with zipfile.ZipFile(zip_file) as zf:
46+
files = zf.namelist()
47+
assert 'simbids/sub-01/ses-01/anat/sub-01_ses-01_T1w.nii.gz' in files
48+
assert 'simbids/sub-01/ses-01/anat/sub-01_ses-01_T1w.json' in files
49+
50+
51+
def test_simulate_dataset_with_filled_files(temp_dir):
52+
"""Test dataset creation with filled files."""
53+
output = sbids.simulate_dataset(temp_dir, 'multi_ses_qsiprep.yaml', 'none', fill_files=True)
54+
55+
# Check if nifti file exists and has content
56+
nifti_file = output / 'simbids' / 'sub-01' / 'ses-01' / 'anat' / 'sub-01_ses-01_T1w.nii.gz'
57+
assert nifti_file.exists()
58+
assert nifti_file.stat().st_size > 0 # File should not be empty
59+
60+
61+
def test_simulate_dataset_invalid_yaml(temp_dir):
62+
"""Test error handling for non-existent YAML file."""
63+
with pytest.raises(FileNotFoundError):
64+
sbids.simulate_dataset(temp_dir, 'nonexistent.yaml', 'none')
65+
66+
67+
def test_simulate_dataset_invalid_zip_level(temp_dir):
68+
"""Test with invalid zip level."""
69+
with pytest.raises(ValueError, match='Invalid zip level: invalid_level'):
70+
sbids.simulate_dataset(temp_dir, 'multi_ses_qsiprep.yaml', 'invalid_level')

0 commit comments

Comments
 (0)