Skip to content

Commit bdd7861

Browse files
DimitriPapadopoulosbpinsard
authored andcommitted
STY: Apply ruff/flake8-implicit-str-concat rule ISC001 (#436)
ISC001 Implicitly concatenated string literals on one line This rule is currently disabled because it conflicts with the formatter: astral-sh/ruff#8272
1 parent 4ed9c9f commit bdd7861

File tree

6 files changed

+103
-10
lines changed

6 files changed

+103
-10
lines changed

smriprep/__main__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@
2727

2828
# `python -m smriprep` typically displays the command as __main__.py
2929
if '__main__.py' in sys.argv[0]:
30-
sys.argv[0] = '%s -m smriprep' % sys.executable
30+
sys.argv[0] = f'{sys.executable} -m smriprep'
3131
main()

smriprep/cli/run.py

+6
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ def get_parser():
173173
action='store_true',
174174
help='treat dataset as longitudinal - may increase runtime',
175175
)
176+
g_conf.add_argument(
177+
'--gradunwarp-file',
178+
metavar='PATH',
179+
type=Path,
180+
help='Path to vendor file for gradunwarp gradient distortion ' 'correction.',
181+
)
176182

177183
# ANTs options
178184
g_ants = parser.add_argument_group('Specific options for ANTs registrations')

smriprep/workflows/anatomical.py

+69-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import typing as ty
2626

27+
import bids
2728
from nipype import logging
2829
from nipype.interfaces import (
2930
freesurfer as fs,
@@ -47,12 +48,14 @@
4748
from niworkflows.interfaces.freesurfer import (
4849
StructuralReference,
4950
)
51+
from niworkflows.interfaces.gradunwarp import GradUnwarp
5052
from niworkflows.interfaces.header import ValidateImage
5153
from niworkflows.interfaces.images import Conform, TemplateDimensions
5254
from niworkflows.interfaces.nibabel import ApplyMask, Binarize
5355
from niworkflows.interfaces.nitransforms import ConcatenateXFMs
5456
from niworkflows.utils.misc import add_suffix
5557
from niworkflows.utils.spaces import Reference, SpatialReferences
58+
from niworkflows.workflows.gradunwarp import init_gradunwarp_wf
5659

5760
from ..data import load_resource
5861
from ..interfaces import DerivativesDataSink
@@ -94,6 +97,7 @@
9497
def init_anat_preproc_wf(
9598
*,
9699
bids_root: str,
100+
layout: bids.BIDSLayout,
97101
output_dir: str,
98102
freesurfer: bool,
99103
hires: bool,
@@ -113,6 +117,7 @@ def init_anat_preproc_wf(
113117
name: str = 'anat_preproc_wf',
114118
skull_strip_fixed_seed: bool = False,
115119
fs_no_resume: bool = False,
120+
gradunwarp_file: str | None = None,
116121
):
117122
"""
118123
Stage the anatomical preprocessing steps of *sMRIPrep*.
@@ -150,6 +155,8 @@ def init_anat_preproc_wf(
150155
----------
151156
bids_root : :obj:`str`
152157
Path of the input BIDS dataset root
158+
layout : BIDSLayout object
159+
BIDS dataset layout
153160
output_dir : :obj:`str`
154161
Directory in which to save derivatives
155162
freesurfer : :obj:`bool`
@@ -189,6 +196,8 @@ def init_anat_preproc_wf(
189196
EXPERT: Import pre-computed FreeSurfer reconstruction without resuming.
190197
The user is responsible for ensuring that all necessary files are present.
191198
(default: ``False``).
199+
gradunwarp_file : :obj:`str`, optional
200+
Gradient unwarping filename (default: None)
192201
193202
Inputs
194203
------
@@ -265,6 +274,7 @@ def init_anat_preproc_wf(
265274

266275
anat_fit_wf = init_anat_fit_wf(
267276
bids_root=bids_root,
277+
layout=layout,
268278
output_dir=output_dir,
269279
freesurfer=freesurfer,
270280
hires=hires,
@@ -282,6 +292,7 @@ def init_anat_preproc_wf(
282292
omp_nthreads=omp_nthreads,
283293
skull_strip_fixed_seed=skull_strip_fixed_seed,
284294
fs_no_resume=fs_no_resume,
295+
gradunwarp_file=gradunwarp_file,
285296
)
286297
template_iterator_wf = init_template_iterator_wf(spaces=spaces, sloppy=sloppy)
287298
ds_std_volumes_wf = init_ds_anat_volumes_wf(
@@ -448,6 +459,7 @@ def init_anat_preproc_wf(
448459
def init_anat_fit_wf(
449460
*,
450461
bids_root: str,
462+
layout: bids.BIDSLayout,
451463
output_dir: str,
452464
freesurfer: bool,
453465
hires: bool,
@@ -466,6 +478,7 @@ def init_anat_fit_wf(
466478
name='anat_fit_wf',
467479
skull_strip_fixed_seed: bool = False,
468480
fs_no_resume: bool = False,
481+
gradunwarp_file: str | None = None,
469482
):
470483
"""
471484
Stage the anatomical preprocessing steps of *sMRIPrep*.
@@ -511,6 +524,8 @@ def init_anat_fit_wf(
511524
----------
512525
bids_root : :obj:`str`
513526
Path of the input BIDS dataset root
527+
layout : BIDSLayout object
528+
BIDS dataset layout
514529
output_dir : :obj:`str`
515530
Directory in which to save derivatives
516531
freesurfer : :obj:`bool`
@@ -546,6 +561,12 @@ def init_anat_fit_wf(
546561
Do not use a random seed for skull-stripping - will ensure
547562
run-to-run replicability when used with --omp-nthreads 1
548563
(default: ``False``).
564+
fs_no_resume : bool
565+
EXPERT: Import pre-computed FreeSurfer reconstruction without resuming.
566+
The user is responsible for ensuring that all necessary files are present.
567+
(default: ``False``).
568+
gradunwarp_file : :obj:`str`, optional
569+
Gradient unwarping filename (default: None)
549570
550571
Inputs
551572
------
@@ -760,12 +781,14 @@ def init_anat_fit_wf(
760781
non-uniformity (INU) with `N4BiasFieldCorrection` [@n4], distributed with ANTs {ants_ver}
761782
[@ants, RRID:SCR_004757]"""
762783
desc += '.\n' if num_t1w > 1 else ', and used as T1w-reference throughout the workflow.\n'
763-
784+
t1w_metas = [layout.get_file(t).get_metadata() for t in t1w]
764785
anat_template_wf = init_anat_template_wf(
765786
longitudinal=longitudinal,
766787
omp_nthreads=omp_nthreads,
767788
num_files=num_t1w,
768789
contrast='T1w',
790+
gradunwarp_file=gradunwarp_file,
791+
metadata=t1w_metas,
769792
name='anat_template_wf',
770793
)
771794
ds_template_wf = init_ds_template_wf(output_dir=output_dir, num_t1w=num_t1w)
@@ -1131,11 +1154,14 @@ def init_anat_fit_wf(
11311154

11321155
if t2w and not have_t2w:
11331156
LOGGER.info('ANAT Stage 7: Creating T2w template')
1157+
t2w_metas = [layout.get_file(t).get_metadata() for t in t1w]
11341158
t2w_template_wf = init_anat_template_wf(
11351159
longitudinal=longitudinal,
11361160
omp_nthreads=omp_nthreads,
11371161
num_files=len(t2w),
11381162
contrast='T2w',
1163+
metadata=t2w_metas,
1164+
gradunwarp_file=gradunwarp_file,
11391165
name='t2w_template_wf',
11401166
)
11411167
bbreg = pe.Node(
@@ -1376,6 +1402,8 @@ def init_anat_template_wf(
13761402
omp_nthreads: int,
13771403
num_files: int,
13781404
contrast: str,
1405+
metadata: dict,
1406+
gradunwarp_file: str | None = None,
13791407
name: str = 'anat_template_wf',
13801408
):
13811409
"""
@@ -1388,7 +1416,8 @@ def init_anat_template_wf(
13881416
13891417
from smriprep.workflows.anatomical import init_anat_template_wf
13901418
wf = init_anat_template_wf(
1391-
longitudinal=False, omp_nthreads=1, num_files=1, contrast="T1w"
1419+
longitudinal=False, omp_nthreads=1, num_files=1, contrast="T1w",
1420+
gradunwarp_file=None,
13921421
)
13931422
13941423
Parameters
@@ -1402,6 +1431,8 @@ def init_anat_template_wf(
14021431
Number of images
14031432
contrast : :obj:`str`
14041433
Name of contrast, for reporting purposes, e.g., T1w, T2w, PDw
1434+
gradunwarp_file : :obj:`str`, optional
1435+
Gradient unwarping filename (default: None)
14051436
name : :obj:`str`, optional
14061437
Workflow name (default: anat_template_wf)
14071438
@@ -1449,9 +1480,44 @@ def init_anat_template_wf(
14491480
)
14501481
anat_conform = pe.MapNode(Conform(), iterfield='in_file', name='anat_conform')
14511482

1483+
# -1 Gradient unwarping (optional)
1484+
if gradunwarp_file:
1485+
nds = [
1486+
(
1487+
meta.get('NonlinearGradientCorrection', None)
1488+
or 'ND' in meta.get('ImageType', [])
1489+
or False
1490+
)
1491+
for meta in metadata
1492+
]
1493+
if any(nds) and not all(nds):
1494+
raise RuntimeError(
1495+
f'Inconsistent distortion correction metadata across {contrast} images.'
1496+
)
1497+
if not any(nds):
1498+
gradunwarp_file = None
1499+
if gradunwarp_file:
1500+
gradunwarp_ver = GradUnwarp.version()
1501+
workflow.__desc__ += f"""\
1502+
{"Each" if num_files > 1 else "The"} {contrast} image was corrected for gradient
1503+
non-linearity with `gradunwarp` [@gradunwarp] {gradunwarp_ver} [@gradunwarp]\n"""
1504+
gradunwarp_wf = init_gradunwarp_wf('gradunward_T1w')
1505+
gradunwarp_wf.inputs.inputnode.grad_file = gradunwarp_file
1506+
# fmt:off
1507+
workflow.connect([
1508+
(inputnode, gradunwarp_wf, [('anat_files', 'inputnode.input_file')]),
1509+
(gradunwarp_wf, anat_ref_dimensions, [('outputnode.corrected_file', 't1w_list')]),
1510+
])
1511+
else:
1512+
workflow.connect(
1513+
[
1514+
(inputnode, anat_ref_dimensions, [('anat_files', 't1w_list')]),
1515+
]
1516+
)
1517+
# fmt:on
1518+
14521519
# fmt:off
14531520
workflow.connect([
1454-
(inputnode, anat_ref_dimensions, [('anat_files', 't1w_list')]),
14551521
(anat_ref_dimensions, denoise, [('t1w_valid_list', 'input_image')]),
14561522
(anat_ref_dimensions, anat_conform, [
14571523
('target_zooms', 'target_zooms'),

smriprep/workflows/base.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ def init_smriprep_wf(
168168
freesurfer_home=os.getenv('FREESURFER_HOME'),
169169
spaces=spaces.get_fs_spaces(),
170170
),
171-
name='fsdir_run_%s' % run_uuid.replace('-', '_'),
171+
name='fsdir_run_{}'.format(run_uuid.replace('-', '_')),
172172
run_without_submitting=True,
173173
)
174174
if fs_subjects_dir is not None:
@@ -186,7 +186,7 @@ def init_smriprep_wf(
186186
longitudinal=longitudinal,
187187
low_mem=low_mem,
188188
msm_sulc=msm_sulc,
189-
name='single_subject_%s_wf' % subject_id,
189+
name=f'single_subject_{subject_id}_wf',
190190
omp_nthreads=omp_nthreads,
191191
output_dir=output_dir,
192192
skull_strip_fixed_seed=skull_strip_fixed_seed,
@@ -422,6 +422,7 @@ def init_single_subject_wf(
422422
# Preprocessing of T1w (includes registration to MNI)
423423
anat_preproc_wf = init_anat_preproc_wf(
424424
bids_root=layout.root,
425+
layout=layout,
425426
sloppy=sloppy,
426427
debug=debug,
427428
precomputed=deriv_cache,

smriprep/workflows/fit/registration.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,10 @@ def init_register_template_wf(
128128
# Append template citations to description
129129
for template in templates:
130130
template_meta = get_metadata(template.split(':')[0])
131-
template_refs = ['@%s' % template.split(':')[0].lower()]
131+
template_refs = ['@{}'.format(template.split(':')[0].lower())]
132132

133133
if template_meta.get('RRID', None):
134-
template_refs += ['RRID:%s' % template_meta['RRID']]
134+
template_refs += [f'RRID:{template_meta["RRID"]}']
135135

136136
workflow.__desc__ += """\
137137
*{template_name}* [{template_refs}; TemplateFlow ID: {template}]""".format(

smriprep/workflows/tests/test_anatomical.py

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
from pathlib import Path
22

3+
import bids
34
import nibabel as nb
45
import numpy as np
56
import pytest
67
from nipype.pipeline.engine.utils import generate_expanded_graph
8+
from niworkflows.interfaces import gradunwarp
79
from niworkflows.utils.spaces import Reference, SpatialReferences
810
from niworkflows.utils.testing import generate_bids_skeleton
911

1012
from ..anatomical import init_anat_fit_wf, init_anat_preproc_wf
1113

14+
gradunwarp_file_params = [None]
15+
if gradunwarp.GradUnwarp.version():
16+
from gradunwarp.core.tests.test_regression import siemens_gradfile
17+
18+
gradunwarp_file_params.append(siemens_gradfile)
19+
1220
BASE_LAYOUT = {
1321
'01': {
1422
'anat': [
@@ -73,14 +81,17 @@ def test_init_anat_preproc_wf(
7381
output_dir = tmp_path / 'output'
7482
output_dir.mkdir()
7583

84+
bids_layout = bids.BIDSLayout(bids_root)
85+
7686
init_anat_preproc_wf(
7787
bids_root=str(bids_root),
88+
layout=bids_layout,
7889
output_dir=str(output_dir),
7990
freesurfer=freesurfer,
8091
hires=False,
8192
longitudinal=False,
8293
msm_sulc=False,
83-
t1w=[str(bids_root / 'sub-01' / 'anat' / 'sub-01_T1w.nii.gz')],
94+
t1w=[str(bids_root / 'sub-01' / 'anat' / 'sub-01_run-1_T1w.nii.gz')],
8495
t2w=[str(bids_root / 'sub-01' / 'anat' / 'sub-01_T2w.nii.gz')],
8596
skull_strip_mode='force',
8697
skull_strip_template=Reference('OASIS30ANTs'),
@@ -96,23 +107,28 @@ def test_init_anat_preproc_wf(
96107

97108
@pytest.mark.parametrize('msm_sulc', [True, False])
98109
@pytest.mark.parametrize('skull_strip_mode', ['skip', 'force'])
110+
@pytest.mark.parametrize('gradunwarp_file', gradunwarp_file_params)
99111
def test_anat_fit_wf(
100112
bids_root: Path,
101113
tmp_path: Path,
102114
msm_sulc: bool,
103115
skull_strip_mode: str,
116+
gradunwarp_file: str,
104117
):
105118
output_dir = tmp_path / 'output'
106119
output_dir.mkdir()
107120

121+
bids_layout = bids.BIDSLayout(bids_root)
122+
108123
init_anat_fit_wf(
109124
bids_root=str(bids_root),
125+
layout=bids_layout,
110126
output_dir=str(output_dir),
111127
freesurfer=True,
112128
hires=False,
113129
longitudinal=False,
114130
msm_sulc=msm_sulc,
115-
t1w=[str(bids_root / 'sub-01' / 'anat' / 'sub-01_T1w.nii.gz')],
131+
t1w=[str(bids_root / 'sub-01' / 'anat' / 'sub-01_run-1_T1w.nii.gz')],
116132
t2w=[str(bids_root / 'sub-01' / 'anat' / 'sub-01_T2w.nii.gz')],
117133
skull_strip_mode=skull_strip_mode,
118134
skull_strip_template=Reference('OASIS30ANTs'),
@@ -122,6 +138,7 @@ def test_anat_fit_wf(
122138
),
123139
precomputed={},
124140
omp_nthreads=1,
141+
gradunwarp_file=gradunwarp_file,
125142
)
126143

127144

@@ -200,9 +217,12 @@ def test_anat_fit_precomputes(
200217
for path in xfm.values():
201218
Path(path).touch()
202219

220+
bids_layout = bids.BIDSLayout(bids_root)
221+
203222
# Create workflow
204223
wf = init_anat_fit_wf(
205224
bids_root=str(bids_root),
225+
layout=bids_layout,
206226
output_dir=str(output_dir),
207227
freesurfer=True,
208228
hires=False,

0 commit comments

Comments
 (0)