Skip to content

Commit 8e20d2d

Browse files
committed
added logic to handle multioutputs and inputs where value choices are numbers, some other minor fixes
1 parent 1110b4f commit 8e20d2d

File tree

1 file changed

+43
-10
lines changed

1 file changed

+43
-10
lines changed

nipype/utils/nipype2boutiques.py

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import sys
2121
import tempfile
2222
import simplejson as json
23+
import copy
24+
import six
2325

2426
from ..scripts.instance import import_module
2527

@@ -83,9 +85,9 @@ def generate_boutiques_descriptor(
8385
# Handle compound inputs (inputs that can be of multiple types and are mutually exclusive)
8486
if isinstance(input, list):
8587
mutex_group_members = []
88+
tool_desc['command-line'] += input[0]['value-key'] + " "
8689
for i in input:
8790
tool_desc['inputs'].append(i)
88-
tool_desc['command-line'] += i['value-key'] + " "
8991
mutex_group_members.append(i['id'])
9092
if verbose:
9193
print("-> Adding input " + i['name'])
@@ -100,6 +102,9 @@ def generate_boutiques_descriptor(
100102
if verbose:
101103
print("-> Adding input " + input['name'])
102104

105+
# Remove the extra space at the end of the command line
106+
tool_desc['command-line'] = tool_desc['command-line'].strip()
107+
103108
# Generates input groups
104109
tool_desc['groups'] += get_boutiques_groups(interface.inputs.traits(transient=None).items())
105110
if len(tool_desc['groups']) == 0:
@@ -141,14 +146,20 @@ def generate_tool_outputs(outputs, interface, tool_desc, verbose, first_run):
141146
# If this is the first time we are generating outputs, add the full output to the descriptor.
142147
# Otherwise, find the existing output and update its path template if it's still undefined.
143148
if first_run:
144-
tool_desc['output-files'].append(output)
149+
if isinstance(output, list):
150+
tool_desc['output-files'].extend(output)
151+
if verbose:
152+
print("-> Adding output " + output[0]['name'])
153+
else:
154+
tool_desc['output-files'].append(output)
155+
if verbose:
156+
print("-> Adding output " + output['name'])
145157
else:
146158
for existing_output in tool_desc['output-files']:
147-
if output['id'] == existing_output['id'] and existing_output['path-template'] == "":
159+
if not isinstance(output, list) and output['id'] == existing_output['id'] \
160+
and existing_output['path-template'] == "":
148161
existing_output['path-template'] = output['path-template']
149162
break
150-
if verbose:
151-
print("-> Adding output " + output['name'])
152163

153164
if len(tool_desc['output-files']) == 0:
154165
raise Exception("Tool has no output.")
@@ -197,9 +208,11 @@ def get_boutiques_input(inputs, interface, input_name, spec,
197208
input_list = []
198209
# Recursively create an input for each trait
199210
for i in range(0, len(trait_handler.handlers)):
200-
input_list.append(get_boutiques_input(inputs, interface, input_name, spec,
201-
ignored_template_inputs, verbose,
202-
ignore_template_numbers, trait_handler.handlers[i], i))
211+
inp = get_boutiques_input(inputs, interface, input_name, spec,
212+
ignored_template_inputs, verbose,
213+
ignore_template_numbers, trait_handler.handlers[i], i)
214+
inp['optional'] = True
215+
input_list.append(inp)
203216
return input_list
204217

205218
if handler_type == "File" or handler_type == "Directory":
@@ -227,6 +240,7 @@ def get_boutiques_input(inputs, interface, input_name, spec,
227240
input['exclusive-maximum'] = trait_handler.exclude_high
228241

229242
# Deal with list inputs
243+
# TODO handle lists of lists (e.g. FSL ProbTrackX seed input)
230244
if handler_type == "List":
231245
input['list'] = True
232246
trait_type = type(trait_handler.item_trait.trait_type).__name__
@@ -235,11 +249,13 @@ def get_boutiques_input(inputs, interface, input_name, spec,
235249
input['type'] = "Number"
236250
elif trait_type == "Float":
237251
input['type'] = "Number"
252+
elif trait_type == "File":
253+
input['type'] = "File"
238254
else:
239255
input['type'] = "String"
240-
if trait_handler.minlen is not None:
256+
if trait_handler.minlen != 0:
241257
input['min-list-entries'] = trait_handler.minlen
242-
if trait_handler.maxlen is not None:
258+
if trait_handler.maxlen != six.MAXSIZE:
243259
input['max-list-entries'] = trait_handler.maxlen
244260

245261
input['value-key'] = "[" + input_name.upper(
@@ -266,6 +282,11 @@ def get_boutiques_input(inputs, interface, input_name, spec,
266282
pass
267283
else:
268284
if value_choices is not None:
285+
if all(isinstance(n, int) for n in value_choices):
286+
input['type'] = "Number"
287+
input['integer'] = True
288+
elif all(isinstance(n, float) for n in value_choices):
289+
input['type'] = "Number"
269290
input['value-choices'] = value_choices
270291

271292
# Set Boolean types to Flag (there is no Boolean type in Boutiques)
@@ -316,6 +337,18 @@ def get_boutiques_output(outputs, name, spec, interface, tool_inputs, verbose=Fa
316337
output_value = interface._list_outputs()[name]
317338
except TypeError:
318339
output_value = None
340+
except AttributeError:
341+
output_value = None
342+
343+
# Handle multi-outputs
344+
if isinstance(output_value, list):
345+
output_list = []
346+
for i in range(0, len(output_value)):
347+
output_copy = copy.deepcopy(output)
348+
output_copy['path-template'] = os.path.relpath(output_value[i])
349+
output_copy['id'] += ("_" + str(i+1)) if i > 0 else ""
350+
output_list.append(output_copy)
351+
return output_list
319352

320353
# If an output value is defined, use its relative path
321354
# Otherwise, put blank string and try to fill it on another iteration

0 commit comments

Comments
 (0)