Repository: nipy/nipype

Issue:
FIRST fails generating segmentation_file output path
A FileNotFoundError is thrown when executed with default parameters, it looks for segmented_all_fast_firstseg.nii.gz but segmented_all_none_firstseg.nii.gz was generated.

Conversely, if `method` is set, FIRST fails when formatting the argument



Discussion:

Resolving patch:
diff --git a/nipype/interfaces/fsl/preprocess.py b/nipype/interfaces/fsl/preprocess.py
--- a/nipype/interfaces/fsl/preprocess.py
+++ b/nipype/interfaces/fsl/preprocess.py
@@ -14,6 +14,7 @@
 import os
 import os.path as op
 import warnings
+import glob
 
 import numpy as np
 
@@ -1475,52 +1476,59 @@ def _gen_filename(self, name):
 
 
 class FIRSTInputSpec(FSLCommandInputSpec):
-    in_file = File(exists=True, mandatory=True, position=-2, copyfile=False,
-                  argstr='-i %s',
-                  desc='input data file')
-    out_file = File('segmented', usedefault=True, mandatory=True, position=-1,
-                  argstr='-o %s',
-                  desc='output data file', hash_files=False)
+    in_file = File(
+        exists=True, mandatory=True, position=-2, copyfile=False,
+        argstr='-i %s', desc='input data file')
+    out_file = File(
+        'segmented', usedefault=True, mandatory=True, position=-1,
+        argstr='-o %s', desc='output data file', hash_files=False)
     verbose = traits.Bool(argstr='-v', position=1,
-        desc="Use verbose logging.")
-    brain_extracted = traits.Bool(argstr='-b', position=2,
+                          desc="Use verbose logging.")
+    brain_extracted = traits.Bool(
+        argstr='-b', position=2,
         desc="Input structural image is already brain-extracted")
-    no_cleanup = traits.Bool(argstr='-d', position=3,
+    no_cleanup = traits.Bool(
+        argstr='-d', position=3,
         desc="Input structural image is already brain-extracted")
-    method = traits.Enum('auto', 'fast', 'none',
-                         xor=['method_as_numerical_threshold'],
-                         argstr='-m', position=4,
+    method = traits.Enum(
+        'auto', 'fast', 'none', xor=['method_as_numerical_threshold'],
+        argstr='-m %s', position=4, usedefault=True,
         desc=("Method must be one of auto, fast, none, or it can be entered "
               "using the 'method_as_numerical_threshold' input"))
-    method_as_numerical_threshold = traits.Float(argstr='-m', position=4,
+    method_as_numerical_threshold = traits.Float(
+        argstr='-m %.4f', position=4,
         desc=("Specify a numerical threshold value or use the 'method' input "
               "to choose auto, fast, or none"))
-    list_of_specific_structures = traits.List(traits.Str, argstr='-s %s',
-                                              sep=',', position=5, minlen=1,
+    list_of_specific_structures = traits.List(
+        traits.Str, argstr='-s %s', sep=',', position=5, minlen=1,
         desc='Runs only on the specified structures (e.g. L_Hipp, R_Hipp'
-                          'L_Accu, R_Accu, L_Amyg, R_Amyg'
-                          'L_Caud, R_Caud, L_Pall, R_Pall'
-                          'L_Puta, R_Puta, L_Thal, R_Thal, BrStem')
-    affine_file = File(exists=True, position=6,
-                  argstr='-a %s',
-                  desc=('Affine matrix to use (e.g. img2std.mat) (does not '
-                        're-run registration)'))
+             'L_Accu, R_Accu, L_Amyg, R_Amyg'
+             'L_Caud, R_Caud, L_Pall, R_Pall'
+             'L_Puta, R_Puta, L_Thal, R_Thal, BrStem')
+    affine_file = File(
+        exists=True, position=6, argstr='-a %s',
+        desc=('Affine matrix to use (e.g. img2std.mat) (does not '
+              're-run registration)'))
 
 
 class FIRSTOutputSpec(TraitedSpec):
-    vtk_surfaces = OutputMultiPath(File(exists=True),
-          desc='VTK format meshes for each subcortical region')
-    bvars = OutputMultiPath(File(exists=True),
-          desc='bvars for each subcortical region')
-    original_segmentations = File(exists=True,
-          desc=('3D image file containing the segmented regions as integer '
-                'values. Uses CMA labelling'))
-    segmentation_file = File(exists=True,
-          desc='4D image file containing a single volume per segmented region')
+    vtk_surfaces = OutputMultiPath(
+        File(exists=True),
+        desc='VTK format meshes for each subcortical region')
+    bvars = OutputMultiPath(
+        File(exists=True),
+        desc='bvars for each subcortical region')
+    original_segmentations = File(
+        exists=True, desc=('3D image file containing the segmented regions '
+                           'as integer values. Uses CMA labelling'))
+    segmentation_file = File(
+        exists=True, desc=('4D image file containing a single volume per '
+                           'segmented region'))
 
 
 class FIRST(FSLCommand):
-    """Use FSL's run_first_all command to segment subcortical volumes
+    """
+    Use FSL's run_first_all command to segment subcortical volumes
 
     http://www.fmrib.ox.ac.uk/fsl/first/index.html
 
@@ -1554,7 +1562,7 @@ def _list_outputs(self):
                           'L_Thal', 'R_Thal',
                           'BrStem']
         outputs['original_segmentations'] = \
-                                      self._gen_fname('original_segmentations')
+            self._gen_fname('original_segmentations')
         outputs['segmentation_file'] = self._gen_fname('segmentation_file')
         outputs['vtk_surfaces'] = self._gen_mesh_names('vtk_surfaces',
                                                        structures)
@@ -1563,10 +1571,20 @@ def _list_outputs(self):
 
     def _gen_fname(self, name):
         path, outname, ext = split_filename(self.inputs.out_file)
+
+        method = 'none'
+        if isdefined(self.inputs.method) and self.inputs.method == 'fast':
+            method = 'fast'
+
+        if isdefined(self.inputs.method_as_numerical_threshold):
+            thres = '%.4f' % self.inputs.method_as_numerical_threshold
+            method = thres.replace('.', '')
+
         if name == 'original_segmentations':
-            return op.abspath(outname + '_all_fast_origsegs.nii.gz')
+            return op.abspath('%s_all_%s_origsegs.nii.gz' % (outname, method))
         if name == 'segmentation_file':
-            return op.abspath(outname + '_all_fast_firstseg.nii.gz')
+            return op.abspath('%s_all_%s_firstseg.nii.gz' % (outname, method))
+
         return None
 
     def _gen_mesh_names(self, name, structures):
@@ -1583,4 +1601,4 @@ def _gen_mesh_names(self, name, structures):
                 bvar = prefix + '-' + struct + '_first.bvars'
                 bvars.append(op.abspath(bvar))
             return bvars
-        return None
+        return None
\ No newline at end of file


Test patch:
diff --git a/nipype/interfaces/fsl/tests/test_auto_FIRST.py b/nipype/interfaces/fsl/tests/test_auto_FIRST.py
--- a/nipype/interfaces/fsl/tests/test_auto_FIRST.py
+++ b/nipype/interfaces/fsl/tests/test_auto_FIRST.py
@@ -26,11 +26,12 @@ def test_FIRST_inputs():
     position=5,
     sep=',',
     ),
-    method=dict(argstr='-m',
+    method=dict(argstr='-m %s',
     position=4,
+    usedefault=True,
     xor=['method_as_numerical_threshold'],
     ),
-    method_as_numerical_threshold=dict(argstr='-m',
+    method_as_numerical_threshold=dict(argstr='-m %.4f',
     position=4,
     ),
     no_cleanup=dict(argstr='-d',