diff --git a/CHANGES.md b/CHANGES.md index 4901df4c..f1fe5522 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,28 @@ +25.2.0 (September 25, 2025) +=========================== +The first release of the 25.2.x series. + +This release synchronizes with downstream dependencies, as well as +leverages TemplateFlow to retrieve intermediate transforms used during multi-step registration. + +If you are reusing a previous TemplateFlow cache (which may be the case if running with +Apptainer / Singularity), you will need to clear or update your cache to ensure these new files +are available. + +Thanks to @LuciMoore for the contribution! + +### Documentation + * DOC: MCRIBS and surf recon methods chosen based on age (#485) + +### Enhancements + * ENH: Retrieve transforms with templateflow (#486) + * ENH: Save cortex mask (#487) + * ENH: Add multiverse output layout (#481) + +### Bug Fixes + * FIX: Default to grid-constant when resampling BOLD to output spaces + * FIX: Propagate error code if pipeline run is unsuccessful + 25.1.2 (August 28, 2025) ======================== A patch release in the 25.1.x series. diff --git a/nibabies/cli/run.py b/nibabies/cli/run.py index b577b13f..22a08b93 100755 --- a/nibabies/cli/run.py +++ b/nibabies/cli/run.py @@ -104,6 +104,7 @@ def main(): nibabies_wf.run(**_plugin) except Exception as e: config.loggers.workflow.critical('nibabies failed: %s', e) + exitcode = 1 raise else: config.loggers.workflow.log(25, 'nibabies finished successfully!') @@ -147,7 +148,7 @@ def main(): add_hash = config.execution.output_layout == 'multiverse' # Generate reports phase - generate_reports( + failed_reports = generate_reports( config.execution.unique_labels, config.execution.nibabies_dir, config.execution.run_uuid, @@ -161,6 +162,16 @@ def main(): ) write_bidsignore(config.execution.nibabies_dir) + if failed_reports: + msg = ( + 'Report generation was not successful for the following participants ' + f': {", ".join(failed_reports)}.' + ) + config.loggers.cli.error(msg) + + if int(exitcode) or failed_reports: + sys.exit(1) + if __name__ == '__main__': raise RuntimeError( diff --git a/nibabies/interfaces/resampling.py b/nibabies/interfaces/resampling.py index 11b3742d..eb9f7998 100644 --- a/nibabies/interfaces/resampling.py +++ b/nibabies/interfaces/resampling.py @@ -62,8 +62,15 @@ class ResampleSeriesInputSpec(TraitedSpec): num_threads = traits.Int(1, usedefault=True, desc='Number of threads to use for resampling') output_data_type = traits.Str('float32', usedefault=True, desc='Data type of output image') order = traits.Int(3, usedefault=True, desc='Order of interpolation (0=nearest, 3=cubic)') - mode = traits.Str( + mode = traits.Enum( + 'grid-constant', + 'nearest', 'constant', + 'mirror', + 'reflect', + 'wrap', + 'grid-mirror', + 'grid-wrap', usedefault=True, desc='How data is extended beyond its boundaries. ' 'See scipy.ndimage.map_coordinates for more details.', @@ -561,7 +568,7 @@ def resample_image( hmc = [] # Retrieve the RAS coordinates of the target space - coordinates = nt.base.SpatialReference.factory(target).ndcoords.astype('f4').T + coordinates = nt.base.SpatialReference.factory(target).ndcoords.astype('f4') # We will operate in voxel space, so get the source affine vox2ras = source.affine diff --git a/nibabies/utils/transforms.py b/nibabies/utils/transforms.py index b1049ebd..2b6aac81 100644 --- a/nibabies/utils/transforms.py +++ b/nibabies/utils/transforms.py @@ -20,7 +20,7 @@ def load_transforms(xfm_paths: list[Path], inverse: list[bool]) -> nt.base.Trans path = Path(path) if path.suffix == '.h5': # Load as a TransformChain - xfm = nt.manip.load(path) + xfm = nt.manip.load(path, fmt='h5') else: xfm = nt.linear.load(path) if inv: diff --git a/nibabies/utils/viz.py b/nibabies/utils/viz.py index f593e42d..6ac7264b 100644 --- a/nibabies/utils/viz.py +++ b/nibabies/utils/viz.py @@ -211,11 +211,12 @@ def plot_carpet( legend = False else: # Volumetric NIfTI - from nilearn._utils import check_niimg_4d from nilearn._utils.niimg import _safe_get_data + from nilearn._utils.niimg_conversions import check_niimg - img_nii = check_niimg_4d( + img_nii = check_niimg( img, + ensure_ndim=4, dtype='auto', ) func_data = _safe_get_data(img_nii, ensure_finite=True) diff --git a/pyproject.toml b/pyproject.toml index e03c00ea..80281d50 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,22 +20,22 @@ license = {file = "LICENSE"} requires-python = ">=3.10" dependencies = [ "acres", - "nibabel >= 5.0.0", - "nipype >= 1.8.5", - "nireports >= 23.2.0", + "nibabel >= 5.1.0", + "nipype >= 1.9.0", + "nireports >= 25.3.0", "nitime", - "nitransforms >= 24.1.1", + "nitransforms >= 25.0.1", "niworkflows >= 1.14.1", - "numpy >= 1.21.0", + "numpy >= 2.0", "packaging", "pandas < 3", "psutil >= 5.4", "pybids >= 0.15.0", "requests", - "sdcflows >= 2.13.0", + "sdcflows >= 2.14.0", "smriprep >= 0.19.1", "tedana >= 23.0.2", - "templateflow >= 24.2.0", + "templateflow >= 25.0.3", "toml", "typing_extensions; python_version<'3.11'", ] diff --git a/requirements.txt b/requirements.txt index 2f785733..fd0b8257 100644 --- a/requirements.txt +++ b/requirements.txt @@ -204,18 +204,20 @@ nipype==1.10.0 # niworkflows # sdcflows # smriprep -nireports==25.2.0 +nireports==25.3.0 # via # nibabies (pyproject.toml) # sdcflows + # smriprep nitime==0.11 # via nibabies (pyproject.toml) -nitransforms==24.1.2 +nitransforms==25.0.1 # via # nibabies (pyproject.toml) # niworkflows # sdcflows -niworkflows==1.13.4 + # smriprep +niworkflows==1.14.1 # via # nibabies (pyproject.toml) # sdcflows @@ -265,7 +267,6 @@ packaging==25.0 # nilearn # nipype # niworkflows - # pooch # scikit-image # smriprep pandas==2.2.3 @@ -289,11 +290,7 @@ pillow==11.2.1 # matplotlib # scikit-image platformdirs==4.3.8 - # via - # datalad - # pooch -pooch==1.8.2 - # via nibabies (pyproject.toml) + # via datalad prov==2.0.2 # via nipype psutil==7.0.0 @@ -351,7 +348,6 @@ requests==2.32.4 # etelemetry # nilearn # osfclient - # pooch # python-gitlab # requests-toolbelt # templateflow @@ -386,7 +382,7 @@ scipy==1.15.2 # scikit-learn # sdcflows # tedana -sdcflows==2.13.1 +sdcflows==2.14.0 # via nibabies (pyproject.toml) seaborn==0.13.2 # via @@ -402,7 +398,7 @@ six==1.17.0 # osfclient # pybtex # python-dateutil -smriprep==0.18.0 +smriprep==0.19.1 # via nibabies (pyproject.toml) sqlalchemy==2.0.41 # via pybids @@ -410,7 +406,7 @@ svgutils==0.3.4 # via niworkflows tedana==25.0.1 # via nibabies (pyproject.toml) -templateflow==24.2.2 +templateflow==25.0.3 # via # nibabies (pyproject.toml) # nireports