Skip to content

Commit c015b11

Browse files
authored
Merge pull request #4 from PennLINC/reduce-dependencies
Reduce dependencies
2 parents 5fae1dc + b8e2642 commit c015b11

File tree

11 files changed

+119
-35
lines changed

11 files changed

+119
-35
lines changed

pyproject.toml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,8 @@ classifiers = [
1919
]
2020
dependencies = [
2121
"acres",
22-
"fmriprep @ git+https://github.com/nipreps/fmriprep.git@master",
23-
"nipype >= 1.8.5",
24-
"nireports @ git+https://github.com/nipreps/nireports.git@main",
25-
"nitransforms >= 24.0.2",
26-
"niworkflows @ git+https://github.com/nipreps/niworkflows.git@master",
22+
"nipype",
2723
"pybids >= 0.15.6",
28-
"sdcflows @ git+https://github.com/nipreps/sdcflows.git@master",
29-
"smriprep @ git+https://github.com/nipreps/smriprep.git@master",
3024
"typer",
3125
]
3226
dynamic = ["version"]

src/simbids/cli/parser.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,7 @@ def _bids_filter(value, parser):
115115

116116
parser = ArgumentParser(
117117
description=(
118-
'SimBIDS: fMRI POSTprocessing template workflow '
119-
f'v{config.environment.version}'
118+
f'SimBIDS: fMRI POSTprocessing template workflow v{config.environment.version}'
120119
),
121120
formatter_class=ArgumentDefaultsHelpFormatter,
122121
**kwargs,
@@ -185,11 +184,11 @@ def _bids_filter(value, parser):
185184
type=BIDSFilter,
186185
metavar='FILE',
187186
help=(
188-
"A JSON file describing custom BIDS input filters using PyBIDS. "
189-
"For further details, please check out "
190-
"https://fmriprep.readthedocs.io/en/"
191-
f"{currentv.base_version if is_release else 'latest'}/faq.html#"
192-
"how-do-I-select-only-certain-files-to-be-input-to-fMRIPrep"
187+
'A JSON file describing custom BIDS input filters using PyBIDS. '
188+
'For further details, please check out '
189+
'https://fmriprep.readthedocs.io/en/'
190+
f'{currentv.base_version if is_release else "latest"}/faq.html#'
191+
'how-do-I-select-only-certain-files-to-be-input-to-fMRIPrep'
193192
),
194193
)
195194
g_bids.add_argument(
@@ -546,8 +545,7 @@ def parse_args(args=None, namespace=None):
546545
from simbids.utils.bids import validate_input_dir
547546

548547
build_log.info(
549-
'Making sure the input data is BIDS compliant '
550-
'(warnings can be ignored in most cases).'
548+
'Making sure the input data is BIDS compliant (warnings can be ignored in most cases).'
551549
)
552550
validate_input_dir(config.environment.exec_env, opts.bids_dir, opts.participant_label)
553551

@@ -567,8 +565,8 @@ def parse_args(args=None, namespace=None):
567565
missing_subjects = participant_label - set(all_subjects)
568566
if missing_subjects:
569567
parser.error(
570-
"One or more participant labels were not found in the BIDS directory: "
571-
f"{', '.join(missing_subjects)}."
568+
'One or more participant labels were not found in the BIDS directory: '
569+
f'{", ".join(missing_subjects)}.'
572570
)
573571

574572
config.execution.participant_label = sorted(participant_label)

src/simbids/cli/run.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,7 @@ def main():
141141

142142
config.loggers.workflow.log(
143143
15,
144-
'\n'.join(
145-
['SimBIDS config:'] + [f'\t\t{s}' for s in config.dumps().splitlines()]
146-
),
144+
'\n'.join(['SimBIDS config:'] + [f'\t\t{s}' for s in config.dumps().splitlines()]),
147145
)
148146
config.loggers.workflow.log(25, 'SimBIDS started!')
149147
errno = 1 # Default is error exit unless otherwise set

src/simbids/cli/version.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ def check_latest():
6666
if latest is None or outdated is True:
6767
response = None
6868
with suppress(Exception):
69-
response = requests.get(
70-
url='https://pypi.org/pypi/simbids/json', timeout=1.0
71-
)
69+
response = requests.get(url='https://pypi.org/pypi/simbids/json', timeout=1.0)
7270

7371
if response and response.status_code == 200:
7472
versions = [Version(rel) for rel in response.json()['releases'].keys()]

src/simbids/cli/workflow.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ def build_workflow(config_file, retval):
5858
notice_path = Path(pkgrf('simbids', 'data/NOTICE'))
5959
if notice_path.exists():
6060
banner[0] += '\n'
61-
banner += [f"License NOTICE {'#' * 50}"]
61+
banner += [f'License NOTICE {"#" * 50}']
6262
banner += [f'SimBIDS {version}']
6363
banner += notice_path.read_text().splitlines(keepends=False)[1:]
6464
banner += ['#' * len(banner[1])]
65-
build_log.log(25, f"\n{' ' * 9}".join(banner))
65+
build_log.log(25, f'\n{" " * 9}'.join(banner))
6666

6767
# warn if older results exist: check for dataset_description.json in output folder
6868
msg = check_pipeline_version(
@@ -110,7 +110,7 @@ def build_workflow(config_file, retval):
110110
if config.execution.derivatives:
111111
init_msg += [f'Searching for derivatives: {config.execution.derivatives}.']
112112

113-
build_log.log(25, f"\n{' ' * 11}* ".join(init_msg))
113+
build_log.log(25, f'\n{" " * 11}* '.join(init_msg))
114114

115115
retval['workflow'] = init_simbids_wf()
116116

src/simbids/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ class execution(_Config):
430430
the command line) as spatial references for outputs."""
431431
reports_only = False
432432
"""Only build the reports, based on the reportlets found in a cached working directory."""
433-
run_uuid = f"{strftime('%Y%m%d-%H%M%S')}_{uuid4()}"
433+
run_uuid = f'{strftime("%Y%m%d-%H%M%S")}_{uuid4()}'
434434
"""Unique identifier of this particular run."""
435435
participant_label = None
436436
"""List of participant identifiers that are to be preprocessed."""

src/simbids/tests/run_local_tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def run_command(command, env=None):
8383

8484
if process.returncode != 0:
8585
raise RuntimeError(
86-
f'Non zero return code: {process.returncode}\n' f'{command}\n\n{process.stdout.read()}'
86+
f'Non zero return code: {process.returncode}\n{command}\n\n{process.stdout.read()}'
8787
)
8888

8989

src/simbids/tests/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def run_command(command, env=None):
131131

132132
if process.returncode != 0:
133133
raise Exception(
134-
f'Non zero return code: {process.returncode}\n' f'{command}\n\n{process.stdout.read()}'
134+
f'Non zero return code: {process.returncode}\n{command}\n\n{process.stdout.read()}'
135135
)
136136

137137

src/simbids/utils/bids.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626

2727
import json
2828
from collections import defaultdict
29+
from copy import deepcopy
2930
from pathlib import Path
3031

32+
import yaml
3133
from bids.layout import BIDSLayout
3234
from bids.utils import listify
3335
from niworkflows.utils.spaces import SpatialReferences
@@ -477,3 +479,97 @@ def validate_input_dir(exec_env, bids_dir, participant_label, need_T1w=True):
477479
subprocess.check_call(['bids-validator', str(bids_dir), '-c', temp.name]) # noqa: S607
478480
except FileNotFoundError:
479481
print('bids-validator does not appear to be installed', file=sys.stderr)
482+
483+
484+
def generate_bids_skeleton(target_path, bids_config):
485+
"""
486+
Converts a BIDS directory in dictionary form to a file structure.
487+
488+
The BIDS configuration can either be a YAML or JSON file, or :obj:dict: object.
489+
490+
Parameters
491+
----------
492+
target_path : str
493+
Path to generate BIDS directory at (must not exist)
494+
bids_config : dict or str
495+
Configuration on how to create the BIDS directory.
496+
"""
497+
498+
if isinstance(bids_config, dict):
499+
# ensure dictionary remains unaltered
500+
bids_dict = deepcopy(bids_config)
501+
elif isinstance(bids_config, str):
502+
bids_config = Path(bids_config).read_text()
503+
try:
504+
bids_dict = json.loads(bids_config)
505+
except json.JSONDecodeError:
506+
bids_dict = yaml.safe_load(bids_config)
507+
508+
_bids_dict = deepcopy(bids_dict)
509+
root = Path(target_path).absolute()
510+
root.mkdir(parents=True)
511+
512+
desc = bids_dict.pop('dataset_description', None)
513+
if desc is None:
514+
# default description
515+
desc = {'Name': 'Default', 'BIDSVersion': '1.6.0'}
516+
to_json(root / 'dataset_description.json', desc)
517+
518+
cached_subject_data = None
519+
for subject, sessions in bids_dict.items():
520+
bids_subject = subject if subject.startswith('sub-') else f'sub-{subject}'
521+
subj_path = root / bids_subject
522+
subj_path.mkdir(exist_ok=True)
523+
524+
if sessions == '*': # special case to copy previous subject data
525+
sessions = cached_subject_data.copy()
526+
527+
if isinstance(sessions, dict): # single session
528+
sessions.update({'session': None})
529+
sessions = [sessions]
530+
531+
cached_subject_data = deepcopy(sessions)
532+
for session in sessions:
533+
ses_name = session.pop('session', None)
534+
if ses_name is not None:
535+
bids_session = ses_name if ses_name.startswith('ses-') else f'ses-{ses_name}'
536+
bids_prefix = f'{bids_subject}_{bids_session}'
537+
curr_path = subj_path / bids_session
538+
curr_path.mkdir(exist_ok=True)
539+
else:
540+
bids_prefix = bids_subject
541+
curr_path = subj_path
542+
543+
# create modalities
544+
for modality, files in session.items():
545+
modality_path = curr_path / modality
546+
modality_path.mkdir(exist_ok=True)
547+
548+
if isinstance(files, dict): # single file / metadata combo
549+
files = [files]
550+
551+
for bids_file in files:
552+
metadata = bids_file.pop('metadata', None)
553+
extension = bids_file.pop('extension', '.nii.gz')
554+
suffix = bids_file.pop('suffix')
555+
entities = combine_entities(**bids_file)
556+
data_file = modality_path / f'{bids_prefix}{entities}_{suffix}{extension}'
557+
data_file.touch()
558+
559+
if metadata is not None:
560+
out_metadata = data_file.parent / data_file.name.replace(
561+
extension, '.json'
562+
)
563+
to_json(out_metadata, metadata)
564+
565+
return _bids_dict
566+
567+
568+
def to_json(filename, data):
569+
filename = Path(filename)
570+
filename.write_text(json.dumps(data))
571+
return filename
572+
573+
574+
def combine_entities(**entities):
575+
return f'_{"_".join([f"{lab}-{val}" for lab, val in entities.items()])}' if entities else ''

src/simbids/utils/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def _get_wf_name(bold_fname, prefix):
4343

4444
fname = split_filename(bold_fname)[1]
4545
fname_nosub = '_'.join(fname.split('_')[1:-1])
46-
return f"{prefix}_{fname_nosub.replace('-', '_')}_wf"
46+
return f'{prefix}_{fname_nosub.replace("-", "_")}_wf'
4747

4848

4949
def update_dict(orig_dict, new_dict):

0 commit comments

Comments
 (0)