Skip to content

FIX/TEST: Fixes minor bugs in BoutiqueInterface #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions nipype/interfaces/base/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
This module defines the API of all nipype interfaces.

"""
from .boutiques import (BoutiqueInterface)

from .core import (Interface, BaseInterface, SimpleInterface, CommandLine,
StdOutCommandLine, MpiCommandLine, SEMLikeCommandLine,
LibraryBaseInterface, PackageInfo)
Expand Down
17 changes: 9 additions & 8 deletions nipype/interfaces/base/boutiques.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from itertools import chain
import json
import os
import re

from .core import CommandLine
from .specs import DynamicTraitedSpec
Expand Down Expand Up @@ -187,7 +188,6 @@ def _populate_input_spec(self, input_list):
(self.input_spec,),
input_spec)

# TODO: value-keys aren't necessarily mutually exclusive; use id as key
self.value_keys = value_keys

def _populate_output_spec(self, output_list):
Expand Down Expand Up @@ -243,8 +243,10 @@ def _list_outputs(self):

# replace all value-keys in output name
for name, valkey in self.value_keys.items():
if valkey not in output_filename:
continue
repl = self.inputs.trait_get().get(name)
# if input is specified, strip extensions + replace in output
# if input is specified, strip ext + replace value in output
if repl is not None and isdefined(repl):
for ext in strip:
repl = repl[:-len(ext)] if repl.endswith(ext) else repl
Expand All @@ -271,14 +273,13 @@ def aggregate_outputs(self, runtime=None, needed_outputs=None):
if len(val) == 0:
val = Undefined
setattr(outputs, key, val)
else:
if isdefined(val):
if not os.path.exists(val):
val = Undefined
if not os.path.exists(val):
setattr(outputs, key, Undefined)
setattr(outputs, key, Undefined)

return outputs

@property
def cmdline(self):
""" Prints command line with all specified arguments
"""
Expand All @@ -295,12 +296,12 @@ def cmdline(self):
elif spec.argstr:
value = self._format_arg(name, spec, value)
args = args.replace(valkey, value)
return self._cmd + ' ' + args
# normalize excessive whitespace before returning
return re.sub(r'\s\s+', ' ', self._cmd + ' ' + args).strip()

def help(self, returnhelp=False):
""" Prints interface help
"""

docs = self.boutique_spec.get('description')
if docs is not None:
docstring = trim(docs).split('\n') + ['']
Expand Down
44 changes: 44 additions & 0 deletions nipype/interfaces/base/tests/test_boutiques.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:

from ...base import BoutiqueInterface
from ....testing import example_data


EXAMPLE_SPECS = [
dict(
spec=example_data('boutiques_fslbet.json'),
inputs=[
'additional_surfaces_flag', 'additional_surfaces_t2',
'approx_skull_flag', 'binary_mask_flag', 'center_of_gravity',
'debug_flag', 'fractional_intensity', 'head_radius', 'in_file',
'no_seg_output_flag', 'out_file', 'overlay_flag',
'reduce_bias_flag', 'residual_optic_cleanup_flag',
'robust_iters_flag', 'slice_padding_flag', 'thresholding_flag',
'verbose_flag', 'vg_fractional_intensity', 'vtk_mesh',
'whole_set_mask_flag'
],
outputs=[
'approx_skull_img_file', 'binary_skull_file', 'inskull_mask_file',
'inskull_mesh_file', 'inskull_off_file', 'output_file',
'outskin_mask_file', 'outskin_mesh_file', 'outskin_off_file',
'outskull_mask_file', 'outskull_mesh_file', 'outskull_off_file',
'overlay_file', 'skull_mask_file', 'vtk_mesh_file'
]
)
]


def test_BoutiqueInterface():
for example in EXAMPLE_SPECS:
interface = BoutiqueInterface(example['spec'])

# check interface input/output spec generation
inputs = list(interface.input_spec().get())
outputs = list(interface.output_spec().get())
assert all([f in inputs for f in example['inputs']])
assert all([f in outputs for f in example['outputs']])

# confirm help works
assert isinstance(interface.help(True), str)
32 changes: 16 additions & 16 deletions nipype/testing/data/boutiques_fslbet.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
{
"description": "Name of generated, skulltripped image (e.g. img_bet.nii.gz)",
"value-key": "[OUT_FILE]",
"type": "File",
"type": "String",
"optional": false,
"id": "out_file",
"name": "Output file"
Expand Down Expand Up @@ -249,15 +249,15 @@
"path-template": "[OUT_FILE].nii.gz",
"description": "Default skullstripped image generated by BET",
"optional": true,
"id": "outfile",
"name": "Output mask file",
"id": "output_file",
"name": "Output skullstripped file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_mask.nii.gz",
"description": "Binary mask file (from -m option)",
"optional": true,
"id": "binary_mask",
"id": "binary_skull_file",
"name": "Output binary mask file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
Expand All @@ -273,95 +273,95 @@
"path-template": "[OUT_FILE]_skull.nii.gz",
"description": "Approximate skull image file",
"optional": true,
"id": "approx_skull_img",
"id": "approx_skull_img_file",
"name": "Approximate skull file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_mesh.vtk",
"description": "Mesh in VTK format",
"optional": true,
"id": "output_vtk_mesh",
"id": "vtk_mesh_file",
"name": "VTK mesh",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_skull_mask.nii.gz",
"description": "Output mask for skull image",
"optional": true,
"id": "skull_mask",
"id": "skull_mask_file",
"name": "Skull mask image",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_inskull_mask.nii.gz",
"description": "The in-skull mask file from betsurf (from -A or -A2)",
"optional": true,
"id": "out_inskull_mask",
"id": "inskull_mask_file",
"name": "Output in-skull mask file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_inskull_mesh.nii.gz",
"description": "The in-skull mesh file from betsurf (from -A or -A2)",
"optional": true,
"id": "out_inskull_mesh",
"id": "inskull_mesh_file",
"name": "Output in-skull mesh file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_inskull_mesh.off",
"description": "The in-skull mesh .off file from betsurf (from -A or -A2)",
"optional": true,
"id": "out_inskull_off",
"id": "inskull_off_file",
"name": "Output in-skull mesh off file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_outskin_mask.nii.gz",
"description": "The out-skin mask file from betsurf (from -A or -A2)",
"optional": true,
"id": "out_outskin_mask",
"id": "outskin_mask_file",
"name": "Output out-skin mask file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_outskin_mesh.nii.gz",
"description": "The out-skin mesh file from betsurf (from -A or -A2)",
"optional": true,
"id": "out_outskin_mesh",
"id": "outskin_mesh_file",
"name": "Output out-skin mesh file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_outskin_mesh.off",
"description": "The out-skin mesh .off file from betsurf (from -A or -A2)",
"optional": true,
"id": "out_outskin_off",
"id": "outskin_off_file",
"name": "Output out-skin mesh off file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_outskull_mask.nii.gz",
"description": "The out-skull mask file from betsurf (from -A or -A2)",
"optional": true,
"id": "out_outskull_mask",
"id": "outskull_mask_file",
"name": "Output out-skull mask file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_outskull_mesh.nii.gz",
"description": "The out-skull mesh file from betsurf (from -A or -A2)",
"optional": true,
"id": "out_outskull_mesh",
"id": "outskull_mesh_file",
"name": "Output out-skull mesh file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
},
{
"path-template": "[OUT_FILE]_outskull_mesh.off",
"description": "The out-skull mesh .off file from betsurf (from -A or -A2)",
"optional": true,
"id": "out_outskull_off",
"id": "outskull_off_file",
"name": "Output out-skull mesh off file",
"path-template-stripped-extensions": [".nii.gz", ".nii"]
}
Expand Down