Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/maint/1.5.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
effigies committed Aug 16, 2020
2 parents f2a2034 + 1d6b91e commit 97ce446
Show file tree
Hide file tree
Showing 23 changed files with 227 additions and 131 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ install:
script:
- |
if [ "$CHECK_TYPE" = "test" ]; then
py.test -v --cov nipype --cov-config .coveragerc --cov-report xml:cov.xml -c nipype/pytest.ini --doctest-modules nipype -n auto
py.test -sv --cov nipype --cov-config .coveragerc --cov-report xml:cov.xml -c nipype/pytest.ini --doctest-modules nipype -n 2
fi
- |
if [ "$CHECK_TYPE" = "specs" ]; then
Expand Down
20 changes: 10 additions & 10 deletions .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,16 @@
"name": "Hamalainen, Carlo",
"orcid": "0000-0001-7655-3830"
},
{
"affiliation": "Stanford University",
"name": "\u0106iri\u0107 , Rastko",
"orcid": "0000-0001-6347-7939"
},
{
"affiliation": "Institute for Biomedical Engineering, ETH and University of Zurich",
"name": "Christian, Horea",
"orcid": "0000-0001-7037-2449"
},
{
"affiliation": "Stanford University",
"name": "\u0106iri\u0107 , Rastko",
"orcid": "0000-0001-6347-7939"
},
{
"name": "Dubois, Mathieu"
},
Expand Down Expand Up @@ -225,6 +225,11 @@
{
"name": "Millman, Jarrod"
},
{
"affiliation": "University College London",
"name": "Mancini, Matteo",
"orcid": "0000-0001-7194-4568"
},
{
"affiliation": "National Institute of Mental Health",
"name": "Nielson, Dylan M.",
Expand All @@ -241,11 +246,6 @@
{
"name": "Mordom, David"
},
{
"affiliation": "University College London",
"name": "Mancini, Matteo",
"orcid": "0000-0001-7194-4568"
},
{
"affiliation": "ARAMIS LAB, Brain and Spine Institute (ICM), Paris, France.",
"name": "Guillon, Je\u0301re\u0301my",
Expand Down
18 changes: 17 additions & 1 deletion doc/changelog/1.X.X-changelog.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
1.5.1 (August 16, 2020)
=======================

Bug-fix release in the 1.5.x series.

This release includes small updates to ANTs utilities that lie somewhere
between bug fixes and enhancements.

(`Full changelog <https://github.com/nipy/nipype/milestone/1.5.1?closed=1>`__)

* FIX: Warn for min/max_ver traits when tool version can't be parsed (https://github.com/nipy/nipype/pull/3241)
* FIX: Serialize all interface arguments when exporting workflows (https://github.com/nipy/nipype/pull/3240)
* FIX: Permit identity transforms in list of transforms given to ants.ApplyTransforms (https://github.com/nipy/nipype/pull/3237)
* FIX: ANTs' utilities revision - bug fixes and add more operations to ``ants.ImageMath`` (https://github.com/nipy/nipype/pull/3236)
* DOC: Skip BIDSDataGrabber doctest if pybids is missing (https://github.com/nipy/nipype/pull/3224)

1.5.0 (June 03, 2020)
=========================
=====================

New feature release in the 1.5.x series.

Expand Down
2 changes: 1 addition & 1 deletion doc/interfaces.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Interfaces and Workflows
:Release: |version|
:Date: |today|

Previous versions: `1.4.2 <http://nipype.readthedocs.io/en/1.4.2/>`_ `1.4.1 <http://nipype.readthedocs.io/en/1.4.1/>`_
Previous versions: `1.5.1 <http://nipype.readthedocs.io/en/1.5.1/>`_ `1.5.0 <http://nipype.readthedocs.io/en/1.5.0/>`_

Workflows
---------
Expand Down
1 change: 1 addition & 0 deletions nipype/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
def add_np(doctest_namespace):
doctest_namespace["np"] = numpy
doctest_namespace["os"] = os
doctest_namespace["pytest"] = pytest
doctest_namespace["datadir"] = data_dir


Expand Down
6 changes: 4 additions & 2 deletions nipype/interfaces/ants/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,8 @@ class RegistrationOutputSpec(TraitedSpec):
File(exists=True), desc="List of output transforms for forward registration"
)
reverse_forward_transforms = traits.List(
File(exists=True), desc="List of output transforms for forward registration reversed for antsApplyTransform"
File(exists=True),
desc="List of output transforms for forward registration reversed for antsApplyTransform",
)
reverse_transforms = traits.List(
File(exists=True), desc="List of output transforms for reverse registration"
Expand All @@ -601,7 +602,8 @@ class RegistrationOutputSpec(TraitedSpec):
traits.Bool(), desc="List of flags corresponding to the forward transforms"
)
reverse_forward_invert_flags = traits.List(
traits.Bool(), desc="List of flags corresponding to the forward transforms reversed for antsApplyTransform"
traits.Bool(),
desc="List of flags corresponding to the forward transforms reversed for antsApplyTransform",
)
reverse_invert_flags = traits.List(
traits.Bool(), desc="List of flags corresponding to the reverse transforms"
Expand Down
70 changes: 39 additions & 31 deletions nipype/interfaces/ants/resampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os

from .base import ANTSCommand, ANTSCommandInputSpec
from ..base import TraitedSpec, File, traits, isdefined, InputMultiPath
from ..base import TraitedSpec, File, traits, isdefined, InputMultiObject
from ...utils.filemanip import split_filename


Expand Down Expand Up @@ -52,7 +52,7 @@ class WarpTimeSeriesImageMultiTransformInputSpec(ANTSCommandInputSpec):
use_bspline = traits.Bool(
argstr="--use-Bspline", desc="Use 3rd order B-Spline interpolation"
)
transformation_series = InputMultiPath(
transformation_series = InputMultiObject(
File(exists=True),
argstr="%s",
desc="transformation file(s) to be applied",
Expand Down Expand Up @@ -204,7 +204,7 @@ class WarpImageMultiTransformInputSpec(ANTSCommandInputSpec):
use_bspline = traits.Bool(
argstr="--use-BSpline", desc="Use 3rd order B-Spline interpolation"
)
transformation_series = InputMultiPath(
transformation_series = InputMultiObject(
File(exists=True),
argstr="%s",
desc="transformation file(s) to be applied",
Expand Down Expand Up @@ -369,15 +369,14 @@ class ApplyTransformsInputSpec(ANTSCommandInputSpec):
traits.Float(), traits.Float() # Gaussian/MultiLabel (sigma, alpha)
),
)
transforms = traits.Either(
InputMultiPath(File(exists=True)),
"identity",
transforms = InputMultiObject(
traits.Either(File(exists=True), "identity"),
argstr="%s",
mandatory=True,
desc="transform files: will be applied in reverse order. For "
"example, the last specified transform will be applied first.",
)
invert_transform_flags = InputMultiPath(traits.Bool())
invert_transform_flags = InputMultiObject(traits.Bool())
default_value = traits.Float(0.0, argstr="--default-value %g", usedefault=True)
print_out_composite_warp_file = traits.Bool(
False,
Expand Down Expand Up @@ -411,7 +410,7 @@ class ApplyTransforms(ANTSCommand):
>>> at.cmdline
'antsApplyTransforms --default-value 0 --float 0 --input moving1.nii \
--interpolation Linear --output moving1_trans.nii \
--reference-image fixed1.nii -t identity'
--reference-image fixed1.nii --transform identity'
>>> at = ApplyTransforms()
>>> at.inputs.dimension = 3
Expand All @@ -421,11 +420,11 @@ class ApplyTransforms(ANTSCommand):
>>> at.inputs.interpolation = 'Linear'
>>> at.inputs.default_value = 0
>>> at.inputs.transforms = ['ants_Warp.nii.gz', 'trans.mat']
>>> at.inputs.invert_transform_flags = [False, False]
>>> at.inputs.invert_transform_flags = [False, True]
>>> at.cmdline
'antsApplyTransforms --default-value 0 --dimensionality 3 --float 0 --input moving1.nii \
--interpolation Linear --output deformed_moving1.nii --reference-image fixed1.nii \
--transform [ ants_Warp.nii.gz, 0 ] --transform [ trans.mat, 0 ]'
--transform ants_Warp.nii.gz --transform [ trans.mat, 1 ]'
>>> at1 = ApplyTransforms()
>>> at1.inputs.dimension = 3
Expand All @@ -440,7 +439,23 @@ class ApplyTransforms(ANTSCommand):
>>> at1.cmdline
'antsApplyTransforms --default-value 0 --dimensionality 3 --float 0 --input moving1.nii \
--interpolation BSpline[ 5 ] --output deformed_moving1.nii --reference-image fixed1.nii \
--transform [ ants_Warp.nii.gz, 0 ] --transform [ trans.mat, 0 ]'
--transform ants_Warp.nii.gz --transform trans.mat'
Identity transforms may be used as part of a chain:
>>> at2 = ApplyTransforms()
>>> at2.inputs.dimension = 3
>>> at2.inputs.input_image = 'moving1.nii'
>>> at2.inputs.reference_image = 'fixed1.nii'
>>> at2.inputs.output_image = 'deformed_moving1.nii'
>>> at2.inputs.interpolation = 'BSpline'
>>> at2.inputs.interpolation_parameters = (5,)
>>> at2.inputs.default_value = 0
>>> at2.inputs.transforms = ['identity', 'ants_Warp.nii.gz', 'trans.mat']
>>> at2.cmdline
'antsApplyTransforms --default-value 0 --dimensionality 3 --float 0 --input moving1.nii \
--interpolation BSpline[ 5 ] --output deformed_moving1.nii --reference-image fixed1.nii \
--transform identity --transform ants_Warp.nii.gz --transform trans.mat'
"""

_cmd = "antsApplyTransforms"
Expand All @@ -458,25 +473,20 @@ def _gen_filename(self, name):

def _get_transform_filenames(self):
retval = []
for ii in range(len(self.inputs.transforms)):
if isdefined(self.inputs.invert_transform_flags):
if len(self.inputs.transforms) == len(
self.inputs.invert_transform_flags
):
invert_code = 1 if self.inputs.invert_transform_flags[ii] else 0
retval.append(
"--transform [ %s, %d ]"
% (self.inputs.transforms[ii], invert_code)
)
else:
raise Exception(
(
"ERROR: The useInverse list must have the same number "
"of entries as the transformsFileName list."
)
)
invert_flags = self.inputs.invert_transform_flags
if not isdefined(invert_flags):
invert_flags = [False] * len(self.inputs.transforms)
elif len(self.inputs.transforms) != len(invert_flags):
raise ValueError(
"ERROR: The invert_transform_flags list must have the same number "
"of entries as the transforms list."
)

for transform, invert in zip(self.inputs.transforms, invert_flags):
if invert:
retval.append(f"--transform [ {transform}, 1 ]")
else:
retval.append("--transform %s" % self.inputs.transforms[ii])
retval.append(f"--transform {transform}")
return " ".join(retval)

def _get_output_warped_filename(self):
Expand All @@ -492,8 +502,6 @@ def _format_arg(self, opt, spec, val):
if opt == "output_image":
return self._get_output_warped_filename()
elif opt == "transforms":
if val == "identity":
return "-t identity"
return self._get_transform_filenames()
elif opt == "interpolation":
if self.inputs.interpolation in [
Expand Down
1 change: 1 addition & 0 deletions nipype/interfaces/ants/segmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ def _list_outputs(self):
outputs["bias_image"] = os.path.abspath(self._out_bias_file)
return outputs


class CorticalThicknessInputSpec(ANTSCommandInputSpec):
dimension = traits.Enum(
3, 2, argstr="-d %d", usedefault=True, desc="image dimension (2 or 3)"
Expand Down
6 changes: 3 additions & 3 deletions nipype/interfaces/ants/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,18 @@ class ImageMath(ANTSCommand, CopyHeaderInterface):

def __init__(self, **inputs):
super(ImageMath, self).__init__(**inputs)
if self.inputs.operation in ("PadImage", ):
if self.inputs.operation in ("PadImage",):
self.inputs.copy_header = False

self.inputs.on_trait_change(self._operation_update, "operation")
self.inputs.on_trait_change(self._copyheader_update, "copy_header")

def _operation_update(self):
if self.inputs.operation in ("PadImage", ):
if self.inputs.operation in ("PadImage",):
self.inputs.copy_header = False

def _copyheader_update(self):
if self.inputs.copy_header and self.inputs.operation in ("PadImage", ):
if self.inputs.copy_header and self.inputs.operation in ("PadImage",):
warn("copy_header cannot be updated to True with PadImage as operation.")
self.inputs.copy_header = False

Expand Down
26 changes: 24 additions & 2 deletions nipype/interfaces/base/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,18 @@ def _check_version_requirements(self, trait_object, raise_exception=True):
version = LooseVersion(str(self.version))
for name in names:
min_ver = LooseVersion(str(trait_object.traits()[name].min_ver))
if min_ver > version:
try:
too_old = min_ver > version
except TypeError as err:
msg = (
f"Nipype cannot validate the package version {version!r} for "
f"{self.__class__.__name__}. Trait {name} requires version >={min_ver}."
)
iflogger.warning(f"{msg}. Please verify validity.")
if config.getboolean("execution", "stop_on_unknown_version"):
raise ValueError(msg) from err
continue
if too_old:
unavailable_traits.append(name)
if not isdefined(getattr(trait_object, name)):
continue
Expand All @@ -293,7 +304,18 @@ def _check_version_requirements(self, trait_object, raise_exception=True):
version = LooseVersion(str(self.version))
for name in names:
max_ver = LooseVersion(str(trait_object.traits()[name].max_ver))
if max_ver < version:
try:
too_new = max_ver < version
except TypeError as err:
msg = (
f"Nipype cannot validate the package version {version!r} for "
f"{self.__class__.__name__}. Trait {name} requires version <={max_ver}."
)
iflogger.warning(f"{msg}. Please verify validity.")
if config.getboolean("execution", "stop_on_unknown_version"):
raise ValueError(msg) from err
continue
if too_new:
unavailable_traits.append(name)
if not isdefined(getattr(trait_object, name)):
continue
Expand Down
38 changes: 37 additions & 1 deletion nipype/interfaces/base/tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# vi: set ft=python sts=4 ts=4 sw=4 et:
import os
import simplejson as json
import logging

import pytest
from unittest import mock
Expand Down Expand Up @@ -236,6 +237,41 @@ class DerivedInterface1(nib.BaseInterface):
obj._check_version_requirements(obj.inputs)


def test_input_version_missing(caplog):
class DerivedInterface(nib.BaseInterface):
class input_spec(nib.TraitedSpec):
foo = nib.traits.Int(min_ver="0.9")
bar = nib.traits.Int(max_ver="0.9")

_version = "misparsed-garbage"

obj = DerivedInterface()
obj.inputs.foo = 1
obj.inputs.bar = 1
with caplog.at_level(logging.WARNING, logger="nipype.interface"):
obj._check_version_requirements(obj.inputs)
assert len(caplog.records) == 2


def test_input_version_missing_error():
from nipype import config

class DerivedInterface(nib.BaseInterface):
class input_spec(nib.TraitedSpec):
foo = nib.traits.Int(min_ver="0.9")
bar = nib.traits.Int(max_ver="0.9")

_version = "misparsed-garbage"

with mock.patch.object(config, "getboolean", return_value=True):
obj = DerivedInterface(foo=1)
with pytest.raises(ValueError):
obj._check_version_requirements(obj.inputs)
obj = DerivedInterface(bar=1)
with pytest.raises(ValueError):
obj._check_version_requirements(obj.inputs)


def test_output_version():
class InputSpec(nib.TraitedSpec):
foo = nib.traits.Int(desc="a random int")
Expand Down Expand Up @@ -457,7 +493,7 @@ def test_global_CommandLine_output(tmpdir):
ci = BET()
assert ci.terminal_output == "stream" # default case

with mock.patch.object(nib.CommandLine, '_terminal_output'):
with mock.patch.object(nib.CommandLine, "_terminal_output"):
nib.CommandLine.set_default_terminal_output("allatonce")
ci = nib.CommandLine(command="ls -l")
assert ci.terminal_output == "allatonce"
Expand Down
2 changes: 1 addition & 1 deletion nipype/interfaces/freesurfer/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def looseversion(cls):
vstr = "6.0.0-dev" + githash
elif vinfo[5][0] == "v":
vstr = vinfo[5][1:]
elif len([1 for val in vinfo[3] if val == '.']) == 2:
elif len([1 for val in vinfo[3] if val == "."]) == 2:
"version string: freesurfer-linux-centos7_x86_64-7.1.0-20200511-813297b"
vstr = vinfo[3]
else:
Expand Down
Loading

0 comments on commit 97ce446

Please sign in to comment.