Skip to content

Commit 63d96be

Browse files
committed
added option to supply descriptor tags, changed default tool version to 1.0.0, added logic to deal with 0/1 booleans and tuples, added list separator and flag separator checks
1 parent d009a88 commit 63d96be

File tree

1 file changed

+50
-9
lines changed

1 file changed

+50
-9
lines changed

nipype/utils/nipype2boutiques.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
def generate_boutiques_descriptor(
2222
module, interface_name, container_image, container_type, container_index=None,
23-
verbose=False, save=False, save_path=None, author=None, ignore_inputs=None):
23+
verbose=False, save=False, save_path=None, author=None, ignore_inputs=None, tags=None):
2424
'''
2525
Returns a JSON string containing a JSON Boutiques description of a Nipype interface.
2626
Arguments:
@@ -34,6 +34,8 @@ def generate_boutiques_descriptor(
3434
* save_path: file path for the saved descriptor (defaults to name of the interface in current directory)
3535
* author: author of the tool (required for publishing)
3636
* ignore_inputs: list of interface inputs to not include in the descriptor
37+
* tags: JSON object containing tags to include in the descriptor, e.g. "{/"key1/": /"value1/"}"
38+
(note: the tags 'domain:neuroinformatics' and 'interface-type:nipype' are included by default)
3739
'''
3840

3941
if not module:
@@ -64,7 +66,7 @@ def generate_boutiques_descriptor(
6466
tool_desc['inputs'] = []
6567
tool_desc['output-files'] = []
6668
tool_desc['groups'] = []
67-
tool_desc['tool-version'] = interface.version if interface.version is not None else "No version provided."
69+
tool_desc['tool-version'] = interface.version if interface.version is not None else "1.0.0"
6870
tool_desc['schema-version'] = '0.5'
6971
if container_image:
7072
tool_desc['container-image'] = {}
@@ -120,6 +122,24 @@ def generate_boutiques_descriptor(
120122
if output['path-template'] == "":
121123
fill_in_missing_output_path(output, output['name'], tool_desc['inputs'])
122124

125+
# Add tags
126+
desc_tags = {
127+
'domain': 'neuroinformatics',
128+
'source': 'nipype-interface'
129+
}
130+
131+
if tags is not None:
132+
tags_dict = json.loads(tags)
133+
for k, v in tags_dict.items():
134+
if k in desc_tags:
135+
if not isinstance(desc_tags[k], list):
136+
desc_tags[k] = [desc_tags[k]]
137+
desc_tags[k].append(v)
138+
else:
139+
desc_tags[k] = v
140+
141+
tool_desc['tags'] = desc_tags
142+
123143
# Remove the extra space at the end of the command line
124144
tool_desc['command-line'] = tool_desc['command-line'].strip()
125145

@@ -219,7 +239,13 @@ def get_boutiques_input(inputs, interface, input_name, spec, verbose, handler=No
219239
elif handler_type == "Float":
220240
inp['type'] = "Number"
221241
elif handler_type == "Bool":
222-
inp['type'] = "Flag"
242+
if spec.argstr and len(spec.argstr.split("=")) > 1 and (spec.argstr.split("=")[1] == '0' or spec.argstr.split("=")[1] == '1'):
243+
inp['type'] = "Number"
244+
inp['integer'] = True
245+
inp['minimum'] = 0
246+
inp['maximum'] = 1
247+
else:
248+
inp['type'] = "Flag"
223249
else:
224250
inp['type'] = "String"
225251

@@ -253,6 +279,21 @@ def get_boutiques_input(inputs, interface, input_name, spec, verbose, handler=No
253279
inp['min-list-entries'] = trait_handler.minlen
254280
if trait_handler.maxlen != six.MAXSIZE:
255281
inp['max-list-entries'] = trait_handler.maxlen
282+
if spec.sep:
283+
inp['list-separator'] = spec.sep
284+
285+
if handler_type == "Tuple":
286+
inp['list'] = True
287+
inp['min-list-entries'] = len(spec.default)
288+
inp['max-list-entries'] = len(spec.default)
289+
input_type = type(spec.default[0]).__name__
290+
if input_type == 'int':
291+
inp['type'] = "Number"
292+
inp['integer'] = True
293+
elif input_type == 'float':
294+
inp['type'] = "Number"
295+
else:
296+
inp['type'] = "String"
256297

257298
# Deal with multi-input
258299
if handler_type == "InputMultiObject":
@@ -264,8 +305,12 @@ def get_boutiques_input(inputs, interface, input_name, spec, verbose, handler=No
264305

265306
# Add the command line flag specified by argstr
266307
# If no argstr is provided and input type is Flag, create a flag from the name
267-
if spec.argstr and spec.argstr.split("%")[0]:
268-
inp['command-line-flag'] = spec.argstr.split("%")[0].strip()
308+
if spec.argstr:
309+
if "=" in spec.argstr:
310+
inp['command-line-flag'] = spec.argstr.split("=")[0].strip()
311+
inp['command-line-flag-separator'] = "="
312+
elif spec.argstr.split("%")[0]:
313+
inp['command-line-flag'] = spec.argstr.split("%")[0].strip()
269314
elif inp['type'] == "Flag":
270315
inp['command-line-flag'] = ("--%s" % input_name + " ").strip()
271316

@@ -290,10 +335,6 @@ def get_boutiques_input(inputs, interface, input_name, spec, verbose, handler=No
290335
inp['type'] = "Number"
291336
inp['value-choices'] = value_choices
292337

293-
# Set Boolean types to Flag (there is no Boolean type in Boutiques)
294-
if inp['type'] == "Boolean":
295-
inp['type'] = "Flag"
296-
297338
return inp
298339

299340

0 commit comments

Comments
 (0)