Skip to content

Commit a17e977

Browse files
committed
Merge pull request #637 from mwaskom/enh/selectfiles_forcelist
Enhance flexibiliy of SelectFiles output list coercion
2 parents 95c74e6 + 8b30127 commit a17e977

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

nipype/interfaces/io.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,12 @@ class SelectFilesInputSpec(DynamicTraitedSpec, BaseInterfaceInputSpec):
562562
desc="When matching mutliple files, return them in sorted order.")
563563
raise_on_empty = traits.Bool(True, usedefault=True,
564564
desc="Raise an exception if a template pattern matches no files.")
565-
force_lists = traits.Bool(False, usedefault=True,
566-
desc="Return all values as lists even when matching a single file.")
565+
force_lists = traits.Either(traits.Bool(), traits.List(traits.Str()),
566+
default=False, usedefault=True,
567+
desc=("Whether to return outputs as a list even when only one file "
568+
"matches the template. Either a boolean that applies to all "
569+
"output fields or a list of output field names to coerce to "
570+
" a list"))
567571

568572

569573
class SelectFiles(IOBase):
@@ -646,6 +650,18 @@ def _list_outputs(self):
646650
info = dict([(k, v) for k, v in self.inputs.__dict__.items()
647651
if k in self._infields])
648652

653+
force_lists = self.inputs.force_lists
654+
if isinstance(force_lists, bool):
655+
force_lists = self._outfields if force_lists else []
656+
bad_fields = set(force_lists) - set(self._outfields)
657+
if bad_fields:
658+
bad_fields = ", ".join(list(bad_fields))
659+
plural = "s" if len(bad_fields) > 1 else ""
660+
verb = "were" if len(bad_fields) > 1 else "was"
661+
msg = ("The field%s '%s' %s set in 'force_lists' and not in "
662+
"'templates'.") % (plural, bad_fields, verb)
663+
raise ValueError(msg)
664+
649665
for field, template in self._templates.iteritems():
650666

651667
# Build the full template path
@@ -673,7 +689,7 @@ def _list_outputs(self):
673689
filelist.sort()
674690

675691
# Handle whether this must be a list or not
676-
if not self.inputs.force_lists:
692+
if field not in force_lists:
677693
filelist = list_to_filename(filelist)
678694

679695
outputs[field] = filelist

nipype/interfaces/tests/test_io.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import os.path as op
77
from tempfile import mkstemp, mkdtemp
88

9+
from nose.tools import assert_raises
910
import nipype
1011
from nipype.testing import assert_equal, assert_true, assert_false
1112
import nipype.interfaces.io as nio
@@ -43,6 +44,16 @@ def test_selectfiles():
4344
"interfaces/spm/preprocess.py")
4445
yield assert_equal, res.outputs.preprocess, [wanted]
4546

47+
dg.inputs.package = "fsl"
48+
dg.inputs.force_lists = ["model"]
49+
res = dg.run()
50+
preproc = op.join(op.dirname(nipype.__file__),
51+
"interfaces/fsl/preprocess.py")
52+
model = [op.join(op.dirname(nipype.__file__),
53+
"interfaces/fsl/model.py")]
54+
yield assert_equal, res.outputs.preprocess, preproc
55+
yield assert_equal, res.outputs.model, model
56+
4657
templates = {"converter": "interfaces/dcm{to!s}nii.py"}
4758
dg = nio.SelectFiles(templates, base_directory=base_dir)
4859
dg.inputs.to = 2
@@ -51,6 +62,17 @@ def test_selectfiles():
5162
yield assert_equal, res.outputs.converter, wanted
5263

5364

65+
def test_selectfiles_valueerror():
66+
"""Test ValueError when force_lists has field that isn't in template."""
67+
base_dir = op.dirname(nipype.__file__)
68+
templates = {"model": "interfaces/{package}/model.py",
69+
"preprocess": "interfaces/{package}/pre*.py"}
70+
force_lists = ["model", "preprocess", "registration"]
71+
sf = nio.SelectFiles(templates, base_directory=base_dir,
72+
force_lists=force_lists)
73+
yield assert_raises, ValueError, sf.run
74+
75+
5476
def test_datagrabber_order():
5577
tempdir = mkdtemp()
5678
file1 = mkstemp(prefix='sub002_L1_R1.q', dir=tempdir)

0 commit comments

Comments
 (0)