diff --git a/nipype/interfaces/base/core.py b/nipype/interfaces/base/core.py index 82da393a84..54c4302c7f 100644 --- a/nipype/interfaces/base/core.py +++ b/nipype/interfaces/base/core.py @@ -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 @@ -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 diff --git a/nipype/interfaces/base/tests/test_core.py b/nipype/interfaces/base/tests/test_core.py index e97a5bab79..165b3532ab 100644 --- a/nipype/interfaces/base/tests/test_core.py +++ b/nipype/interfaces/base/tests/test_core.py @@ -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 @@ -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") @@ -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"