Repository: nipy/nipype

Issue:
[TST] [CircleCI] BBRegister autotest failing if make specs run with no FS/FS<6
### Summary
After running `make specs`, `test_auto_BBRegister.py` adds in argument `init` as mandatory, probably due to the inputspec for FS6. This causes circleci to fail when running `nipype.test()`
### Actual behavior
```
        for key, metadata in list(input_map.items()):

            for metakey, value in list(metadata.items()):

>               assert getattr(inputs.traits()[key], metakey) == value

E               assert None == True

E                +  where None = getattr(<traits.traits.CTrait object at 0x7f5cf44d4310>, 'mandatory')



../../interfaces/freesurfer/tests/test_auto_BBRegister.py:60: AssertionError
```
### Expected behavior
Passing
### How to replicate the behavior
- make specs, run circle tests (was happening in #1875)
However, working fine when I run `nipype.test()` local with py3.5.2 with no version of FS installed.

related #1817 


Discussion:
Running `make specs` on a machine without FS or with FS6 should both result in no `mandatory` flag. The test to use the FS5.3 (with mandatory `--init-*`) is [`FSVersion and LooseVersion(FSVersion) < LooseVersion("6.0.0")`](https://github.com/nipy/nipype/blob/master/nipype/interfaces/freesurfer/preprocess.py#L1069-L1070).

So it looks like it's being run on a system with FS5.3 installed, which is odd, since the Dockerfile indicates FS6 is being installed.
@effigies perhaps a non-auto test would be better for this interface, and we can skip the auto test generation. Otherwise, not having Freesurfer6 installed would cause conflicting tests every time `make specs` is run. Let me know what you think? @satra 
What sort of functionality should be tested in order to make a regular test as valuable as the auto tests?
Essentially, it will be very similar to the auto-test (mandatory args, defaults, xor, args with dependencies, etc), there are already some manual tests included [here](https://github.com/mgxd/nipype/blob/da1bd763078770f0850c7d50cb26fb45eb70a408/nipype/interfaces/freesurfer/tests/test_preprocess.py).

Resolving patch:
diff --git a/nipype/interfaces/freesurfer/preprocess.py b/nipype/interfaces/freesurfer/preprocess.py
--- a/nipype/interfaces/freesurfer/preprocess.py
+++ b/nipype/interfaces/freesurfer/preprocess.py
@@ -1038,6 +1038,9 @@ class BBRegisterInputSpec6(BBRegisterInputSpec):
     init = traits.Enum('coreg', 'rr', 'spm', 'fsl', 'header', 'best', argstr='--init-%s',
                        xor=['init_reg_file'],
                        desc='initialize registration with mri_coreg, spm, fsl, or header')
+    init_reg_file = File(exists=True, argstr='--init-reg %s',
+                         desc='existing registration file',
+                         xor=['init'])
 
 
 class BBRegisterOutputSpec(TraitedSpec):


Test patch:
diff --git a/nipype/interfaces/freesurfer/tests/test_BBRegister.py b/nipype/interfaces/freesurfer/tests/test_BBRegister.py
new file mode 100644
--- /dev/null
+++ b/nipype/interfaces/freesurfer/tests/test_BBRegister.py
@@ -0,0 +1,68 @@
+from __future__ import unicode_literals
+from ..preprocess import BBRegister, BBRegisterInputSpec6
+
+
+def test_BBRegister_inputs():
+    input_map_5_3 = dict(
+        args=dict(argstr='%s',),
+        contrast_type=dict(argstr='--%s', mandatory=True,),
+        environ=dict(nohash=True, usedefault=True,),
+        epi_mask=dict(argstr='--epi-mask',),
+        ignore_exception=dict(nohash=True, usedefault=True,),
+        init=dict(argstr='--init-%s', mandatory=True, xor=['init_reg_file'],),
+        init_reg_file=dict(argstr='--init-reg %s', mandatory=True, xor=['init'],),
+        intermediate_file=dict(argstr='--int %s',),
+        out_fsl_file=dict(argstr='--fslmat %s',),
+        out_reg_file=dict(argstr='--reg %s', genfile=True,),
+        reg_frame=dict(argstr='--frame %d', xor=['reg_middle_frame'],),
+        reg_middle_frame=dict(argstr='--mid-frame', xor=['reg_frame'],),
+        registered_file=dict(argstr='--o %s',),
+        source_file=dict(argstr='--mov %s', copyfile=False, mandatory=True,),
+        spm_nifti=dict(argstr='--spm-nii',),
+        subject_id=dict(argstr='--s %s', mandatory=True,),
+        subjects_dir=dict(),
+        terminal_output=dict(nohash=True,),
+        )
+    input_map_6_0 = dict(
+        args=dict(argstr='%s',),
+        contrast_type=dict(argstr='--%s', mandatory=True,),
+        environ=dict(nohash=True, usedefault=True,),
+        epi_mask=dict(argstr='--epi-mask',),
+        ignore_exception=dict(nohash=True, usedefault=True,),
+        init=dict(argstr='--init-%s', xor=['init_reg_file'],),
+        init_reg_file=dict(argstr='--init-reg %s', xor=['init'],),
+        intermediate_file=dict(argstr='--int %s',),
+        out_fsl_file=dict(argstr='--fslmat %s',),
+        out_reg_file=dict(argstr='--reg %s', genfile=True,),
+        reg_frame=dict(argstr='--frame %d', xor=['reg_middle_frame'],),
+        reg_middle_frame=dict(argstr='--mid-frame', xor=['reg_frame'],),
+        registered_file=dict(argstr='--o %s',),
+        source_file=dict(argstr='--mov %s', copyfile=False, mandatory=True,),
+        spm_nifti=dict(argstr='--spm-nii',),
+        subject_id=dict(argstr='--s %s', mandatory=True,),
+        subjects_dir=dict(),
+        terminal_output=dict(nohash=True,),
+        )
+
+    instance = BBRegister()
+    if isinstance(instance.inputs, BBRegisterInputSpec6):
+        input_map = input_map_6_0
+    else:
+        input_map = input_map_5_3
+
+    for key, metadata in list(input_map.items()):
+        for metakey, value in list(metadata.items()):
+            assert getattr(instance.inputs.traits()[key], metakey) == value
+
+
+def test_BBRegister_outputs():
+    output_map = dict(min_cost_file=dict(),
+                      out_fsl_file=dict(),
+                      out_reg_file=dict(),
+                      registered_file=dict(),
+                      )
+    outputs = BBRegister.output_spec()
+
+    for key, metadata in list(output_map.items()):
+        for metakey, value in list(metadata.items()):
+            assert getattr(outputs.traits()[key], metakey) == value
diff --git a/nipype/interfaces/freesurfer/tests/test_auto_BBRegister.py b/nipype/interfaces/freesurfer/tests/test_auto_BBRegister.py
deleted file mode 100644
--- a/nipype/interfaces/freesurfer/tests/test_auto_BBRegister.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
-from __future__ import unicode_literals
-from ..preprocess import BBRegister
-
-
-def test_BBRegister_inputs():
-    input_map = dict(args=dict(argstr='%s',
-    ),
-    contrast_type=dict(argstr='--%s',
-    mandatory=True,
-    ),
-    environ=dict(nohash=True,
-    usedefault=True,
-    ),
-    epi_mask=dict(argstr='--epi-mask',
-    ),
-    ignore_exception=dict(nohash=True,
-    usedefault=True,
-    ),
-    init=dict(argstr='--init-%s',
-    xor=['init_reg_file'],
-    ),
-    init_reg_file=dict(argstr='--init-reg %s',
-    mandatory=True,
-    xor=['init'],
-    ),
-    intermediate_file=dict(argstr='--int %s',
-    ),
-    out_fsl_file=dict(argstr='--fslmat %s',
-    ),
-    out_reg_file=dict(argstr='--reg %s',
-    genfile=True,
-    ),
-    reg_frame=dict(argstr='--frame %d',
-    xor=['reg_middle_frame'],
-    ),
-    reg_middle_frame=dict(argstr='--mid-frame',
-    xor=['reg_frame'],
-    ),
-    registered_file=dict(argstr='--o %s',
-    ),
-    source_file=dict(argstr='--mov %s',
-    copyfile=False,
-    mandatory=True,
-    ),
-    spm_nifti=dict(argstr='--spm-nii',
-    ),
-    subject_id=dict(argstr='--s %s',
-    mandatory=True,
-    ),
-    subjects_dir=dict(),
-    terminal_output=dict(nohash=True,
-    ),
-    )
-    inputs = BBRegister.input_spec()
-
-    for key, metadata in list(input_map.items()):
-        for metakey, value in list(metadata.items()):
-            assert getattr(inputs.traits()[key], metakey) == value
-
-
-def test_BBRegister_outputs():
-    output_map = dict(min_cost_file=dict(),
-    out_fsl_file=dict(),
-    out_reg_file=dict(),
-    registered_file=dict(),
-    )
-    outputs = BBRegister.output_spec()
-
-    for key, metadata in list(output_map.items()):
-        for metakey, value in list(metadata.items()):
-            assert getattr(outputs.traits()[key], metakey) == value
diff --git a/nipype/interfaces/freesurfer/tests/test_preprocess.py b/nipype/interfaces/freesurfer/tests/test_preprocess.py
--- a/nipype/interfaces/freesurfer/tests/test_preprocess.py
+++ b/nipype/interfaces/freesurfer/tests/test_preprocess.py
@@ -6,7 +6,9 @@
 import pytest
 from nipype.testing.fixtures import create_files_in_directory
 
-import nipype.interfaces.freesurfer as freesurfer
+from nipype.interfaces import freesurfer
+from nipype.interfaces.freesurfer.preprocess import FSVersion
+from nipype import LooseVersion
 
 
 @pytest.mark.skipif(freesurfer.no_freesurfer(), reason="freesurfer is not installed")
@@ -118,3 +120,37 @@ def test_mandatory_outvol(create_files_in_directory):
                                         iterations=4)
     assert mni2.cmdline == ('mri_nu_correct.mni --i %s --n 4 --o bias_corrected_output'
                              % filelist[0])
+
+@pytest.mark.skipif(freesurfer.no_freesurfer(), reason="freesurfer is not installed")
+def test_bbregister(create_files_in_directory):
+    filelist, outdir = create_files_in_directory
+    bbr = freesurfer.BBRegister()
+
+    # make sure command gets called
+    assert bbr.cmd == "bbregister"
+
+    # test raising error with mandatory args absent
+    with pytest.raises(ValueError):
+        bbr.cmdline
+
+    bbr.inputs.subject_id = 'fsaverage'
+    bbr.inputs.source_file = filelist[0]
+    bbr.inputs.contrast_type = 't2'
+
+    # Check that 'init' is mandatory in FS < 6, but not in 6+
+    if LooseVersion(FSVersion) < LooseVersion("6.0.0"):
+        with pytest.raises(ValueError):
+            bbr.cmdline
+    else:
+        bbr.cmdline
+
+    bbr.inputs.init = 'fsl'
+
+    base, ext = os.path.splitext(os.path.basename(filelist[0]))
+    if ext == '.gz':
+        base, _ = os.path.splitext(base)
+
+    assert bbr.cmdline == ('bbregister --t2 --init-fsl '
+                           '--reg {base}_bbreg_fsaverage.dat '
+                           '--mov {full} --s fsaverage'.format(
+                            full=filelist[0], base=base))