Repository: nipy/nipype

Issue:
Circle CI taking the unit-tests for passed when failed (again)
Only for the unittests, not for the smoketests.

Even though some tests fail (and it is correctly reported by the tests summary thanks to having the junit xml files in place), the build is taken for passing. Example: https://circleci.com/gh/nipy/nipype/2095?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link

When I refactored this, CircleCI was showing these builds as failed (or I may have been tripping out). Now it seems it requires an explicit non-zero exit code.


Discussion:

Resolving patch:
diff --git a/nipype/scripts/utils.py b/nipype/scripts/utils.py
--- a/nipype/scripts/utils.py
+++ b/nipype/scripts/utils.py
@@ -3,9 +3,12 @@
 Utilities for the CLI functions.
 """
 from __future__ import print_function, division, unicode_literals, absolute_import
-import re
 
+from builtins import bytes, str
+
+import re
 import click
+import json
 
 from .instance import import_module
 from ..interfaces.base import InputMultiPath, traits
@@ -16,7 +19,6 @@
 UNKNOWN_OPTIONS = dict(allow_extra_args=True,
                        ignore_unknown_options=True)
 
-
 # specification of existing ParamTypes
 ExistingDirPath  = click.Path(exists=True, file_okay=False, resolve_path=True)
 ExistingFilePath = click.Path(exists=True,  dir_okay=False, resolve_path=True)
@@ -63,18 +65,62 @@ def add_args_options(arg_parser, interface):
         # Escape any % signs with a %
         desc = desc.replace('%', '%%')
         args = {}
+        has_multiple_inner_traits = False
 
         if spec.is_trait_type(traits.Bool):
             args["default"] = getattr(inputs, name)
             args["action"] = 'store_true'
 
-        if hasattr(spec, "mandatory") and spec.mandatory:
+        print(name, spec.trait_type)
+        # current support is for simple trait types
+        if not spec.inner_traits:
+            if not spec.is_trait_type(traits.TraitCompound):
+                trait_type = type(spec.trait_type.default_value)
+            if trait_type in (bytes, str, int, float):
+                if trait_type == bytes:
+                    trait_type = str
+                args["type"] = trait_type
+        elif len(spec.inner_traits) == 1:
+            trait_type = type(spec.inner_traits[0].trait_type.default_value)
+            if trait_type == bytes:
+                trait_type = str
+            if trait_type in (bytes, bool, str, int, float):
+                args["type"] = trait_type
+        else:
+            if len(spec.inner_traits) > 1:
+                if not spec.is_trait_type(traits.Dict):
+                    has_multiple_inner_traits = True
+
+        if getattr(spec, "mandatory", False):
             if spec.is_trait_type(InputMultiPath):
                 args["nargs"] = "+"
+            elif spec.is_trait_type(traits.List):
+                if (spec.trait_type.minlen == spec.trait_type.maxlen) and \
+                        spec.trait_type.maxlen:
+                    args["nargs"] = spec.trait_type.maxlen
+                else:
+                    args["nargs"] = "+"
+            elif spec.is_trait_type(traits.Dict):
+                args["type"] = json.loads
+
+            if has_multiple_inner_traits:
+                raise NotImplementedError(
+                    ('This interface cannot be used. via the'
+                     ' command line as multiple inner traits'
+                     ' are currently not supported for mandatory'
+                     ' argument: {}.'.format(name)))
             arg_parser.add_argument(name, help=desc, **args)
         else:
             if spec.is_trait_type(InputMultiPath):
                 args["nargs"] = "*"
-            arg_parser.add_argument("--%s" % name, dest=name,
-                                    help=desc, **args)
+            elif spec.is_trait_type(traits.List):
+                if (spec.trait_type.minlen == spec.trait_type.maxlen) and \
+                        spec.trait_type.maxlen:
+                    args["nargs"] = spec.trait_type.maxlen
+                else:
+                    args["nargs"] = "*"
+            if not has_multiple_inner_traits:
+                arg_parser.add_argument("--%s" % name, dest=name,
+                                        help=desc, **args)
+
     return arg_parser
diff --git a/nipype/utils/nipype_cmd.py b/nipype/utils/nipype_cmd.py
--- a/nipype/utils/nipype_cmd.py
+++ b/nipype/utils/nipype_cmd.py
@@ -50,19 +50,8 @@ def run_instance(interface, options):
     print("setting function inputs")
 
     for input_name, _ in list(interface.inputs.items()):
-        if getattr(options, input_name) != None:
+        if getattr(options, input_name) is not None:
             value = getattr(options, input_name)
-            if not isinstance(value, bool):
-                # traits cannot cast from string to float or int
-                try:
-                    value = float(value)
-                except:
-                    pass
-                # try to cast string input to boolean
-                try:
-                    value = str2bool(value)
-                except:
-                    pass
             try:
                 setattr(interface.inputs, input_name,
                         value)


Test patch: