diff --git a/src/smriprep/data/io_spec.json b/src/smriprep/data/io_spec.json index 057c8f634f7..89238d72616 100644 --- a/src/smriprep/data/io_spec.json +++ b/src/smriprep/data/io_spec.json @@ -134,7 +134,7 @@ "sphere_reg": { "datatype": "anat", "hemi": ["L", "R"], - "space": null, + "space": [null, "fsaverage"], "desc": "reg", "suffix": "sphere", "extension": ".surf.gii" diff --git a/src/smriprep/utils/bids.py b/src/smriprep/utils/bids.py index fc67828bf26..6b6f862dc40 100644 --- a/src/smriprep/utils/bids.py +++ b/src/smriprep/utils/bids.py @@ -22,6 +22,7 @@ # """Utilities to handle BIDS inputs.""" +import logging from json import loads from pathlib import Path @@ -30,6 +31,8 @@ import smriprep +LOGGER = logging.getLogger('nipype.workflow') + def collect_derivatives( derivatives_dir, @@ -92,6 +95,17 @@ def collect_derivatives( if not item or len(item) != 2: continue + # sphere_reg added ``space-fsaverage`` in sMRIPrep 0.16.0 + if key == 'sphere_reg': + legacy = [f for f in item if 'space' not in layout.parse_file_entities(f)] + if legacy: + LOGGER.warning( + f"Found legacy {key} derivative(s) that lack a 'space' entity; this " + 'naming is deprecated and may not be recognized in a future release. ' + 'Rename or regenerate these derivatives with sMRIPrep >= 0.16.0. Files: %s', + ', '.join(sorted(Path(f).name for f in legacy)), + ) + derivs_cache[key] = sorted(item) for key, qry in spec['masks'].items(): diff --git a/test/utils/derivatives.yml b/test/utils/derivatives.yml index 35330385abf..ccd79972fe4 100644 --- a/test/utils/derivatives.yml +++ b/test/utils/derivatives.yml @@ -61,10 +61,12 @@ dataset_description: extension: .surf.gii - suffix: sphere hemi: L + space: fsaverage desc: reg extension: .surf.gii - suffix: sphere hemi: R + space: fsaverage desc: reg extension: .surf.gii - suffix: sphere diff --git a/test/utils/test_bids.py b/test/utils/test_bids.py index 75a257a598f..10207f95f92 100644 --- a/test/utils/test_bids.py +++ b/test/utils/test_bids.py @@ -20,6 +20,8 @@ # # https://www.nipreps.org/community/licensing/ # +import logging + import pytest from niworkflows.utils.testing import generate_bids_skeleton @@ -59,6 +61,40 @@ def test_collect_derivatives(deriv_dset): assert len(collected[surface]) == 2 +@pytest.mark.parametrize( + ('sphere_reg_entities', 'warns'), + [ + pytest.param({'desc': 'reg'}, True, id='without-fsaverage'), + pytest.param({'space': 'fsaverage', 'desc': 'reg'}, False, id='with-fsaverage'), + ], +) +def test_collect_derivatives_reuses_sphere_reg(tmp_path, caplog, sphere_reg_entities, warns): + """The fsaverage registration sphere is reusable under both naming conventions.""" + skeleton = { + '01': [ + { + 'anat': [ + { + 'suffix': 'sphere', + 'hemi': hemi, + 'extension': '.surf.gii', + **sphere_reg_entities, + } + for hemi in ('L', 'R') + ] + } + ] + } + deriv_dir = tmp_path / 'derivatives' + generate_bids_skeleton(deriv_dir, skeleton) + + with caplog.at_level(logging.WARNING, logger='nipype.workflow'): + collected = collect_derivatives(deriv_dir, '01', []) + + assert len(collected['sphere_reg']) == 2 + assert any('legacy sphere_reg' in record.message for record in caplog.records) is warns + + def test_collect_derivatives_transforms(deriv_dset): """Ensure transforms are collected for the right spaces.""" output_spaces = ['MNI152NLin2009cAsym', 'MNIPediatricAsym:cohort-3']