@@ -63,7 +63,7 @@ def generate_boutiques_descriptor(
63
63
'description' ] = interface_name + ", as implemented in Nipype (module: " + module_name + ", interface: " + interface_name + ")."
64
64
tool_desc ['inputs' ] = []
65
65
tool_desc ['output-files' ] = []
66
- tool_desc ['tool-version' ] = interface .version if interface .version is not None else 'undefined'
66
+ tool_desc ['tool-version' ] = interface .version if interface .version is not None else "No version provided."
67
67
tool_desc ['schema-version' ] = '0.5'
68
68
if container_image :
69
69
tool_desc ['container-image' ] = {}
@@ -84,7 +84,7 @@ def generate_boutiques_descriptor(
84
84
85
85
# Generates tool outputs
86
86
for name , spec in sorted (outputs .traits (transient = None ).items ()):
87
- output = get_boutiques_output (name , interface , tool_desc ['inputs' ],
87
+ output = get_boutiques_output (outputs , name , spec , interface , tool_desc ['inputs' ],
88
88
verbose )
89
89
if output ['path-template' ] != "" :
90
90
tool_desc ['output-files' ].append (output )
@@ -105,6 +105,8 @@ def generate_boutiques_descriptor(
105
105
with open (interface_name + '.json' , 'w' ) as outfile :
106
106
json .dump (tool_desc , outfile )
107
107
108
+ print ("NOTE: Descriptors produced by this script may not entirely conform to the Nipype interface "
109
+ "specs. Please check that the descriptor is correct before using it." )
108
110
return json .dumps (tool_desc , indent = 4 , separators = (',' , ': ' ))
109
111
110
112
@@ -125,26 +127,24 @@ def get_boutiques_input(inputs, interface, input_name, spec,
125
127
Assumes that:
126
128
* Input names are unique.
127
129
"""
128
- if not spec .desc :
129
- spec .desc = "No description provided."
130
130
spec_info = spec .full_info (inputs , input_name , None )
131
131
132
132
input = {}
133
133
input ['id' ] = input_name
134
134
input ['name' ] = input_name .replace ('_' , ' ' ).capitalize ()
135
135
136
136
# Figure out the input type from its handler type
137
- input ['type' ] = get_type_from_handler_type (spec .handler )
137
+ input_type = get_type_from_handler_type (spec .handler )
138
+ input ['type' ] = input_type [0 ]
139
+ if input_type [1 ]:
140
+ input ['integer' ] = True
138
141
139
142
input ['list' ] = is_list (spec_info )
140
143
input ['value-key' ] = "[" + input_name .upper (
141
144
) + "]" # assumes that input names are unique
142
145
input ['command-line-flag' ] = ("--%s" % input_name + " " ).strip ()
143
146
input ['tempvalue' ] = None
144
- input ['description' ] = spec_info .capitalize (
145
- ) + ". " + spec .desc .capitalize ()
146
- if not input ['description' ].endswith ('.' ):
147
- input ['description' ] += '.'
147
+ input ['description' ] = get_description_from_spec (inputs , input_name , spec )
148
148
if not (hasattr (spec , "mandatory" ) and spec .mandatory ):
149
149
input ['optional' ] = True
150
150
else :
@@ -180,12 +180,14 @@ def get_boutiques_input(inputs, interface, input_name, spec,
180
180
return input
181
181
182
182
183
- def get_boutiques_output (name , interface , tool_inputs , verbose = False ):
183
+ def get_boutiques_output (outputs , name , spec , interface , tool_inputs , verbose = False ):
184
184
"""
185
185
Returns a dictionary containing the Boutiques output corresponding to a Nipype output.
186
186
187
187
Args:
188
+ * outputs: outputs of the Nipype interface.
188
189
* name: name of the Nipype output.
190
+ * spec: Nipype output spec.
189
191
* interface: Nipype interface.
190
192
* tool_inputs: list of tool inputs (as produced by method get_boutiques_input).
191
193
@@ -211,9 +213,13 @@ def get_boutiques_output(name, interface, tool_inputs, verbose=False):
211
213
output [
212
214
'optional' ] = True # no real way to determine if an output is always produced, regardless of the input values.
213
215
216
+ output ['description' ] = get_description_from_spec (outputs , name , spec )
217
+
214
218
# Path template creation.
215
219
216
220
output_value = interface ._list_outputs ()[name ]
221
+
222
+ # If output value is defined, use its basename
217
223
if output_value != "" and isinstance (
218
224
output_value ,
219
225
str ): # FIXME: this crashes when there are multiple output values.
@@ -233,11 +239,20 @@ def get_boutiques_output(name, interface, tool_inputs, verbose=False):
233
239
) # FIXME: this only works if output is written in the current directory
234
240
output ['path-template' ] = os .path .basename (output_value )
235
241
242
+ # If output value is undefined, create a placeholder for the path template
236
243
if not output_value :
237
244
# Look for an input with the same name and use this as the path template
245
+ found = False
238
246
for input in tool_inputs :
239
247
if input ['id' ] == name :
240
248
output ['path-template' ] = input ['value-key' ]
249
+ found = True
250
+ break
251
+ # If no input with the same name was found, warn the user they should provide it manually
252
+ if not found :
253
+ print ("WARNING: Could not determine path template for output %s. Please provide one for the "
254
+ "descriptor manually." % name )
255
+ output ['path-template' ] = "WARNING: No path template provided."
241
256
return output
242
257
243
258
@@ -258,15 +273,21 @@ def get_type_from_spec_info(spec_info):
258
273
259
274
260
275
def get_type_from_handler_type (handler ):
276
+ '''
277
+ Gets the input type from the spec handler type.
278
+ Returns a tuple containing the type and a boolean to specify
279
+ if the type is an integer.
280
+ '''
261
281
handler_type = type (handler ).__name__
282
+ print ("TYPE" , handler_type )
262
283
if handler_type == "File" or handler_type == "Directory" :
263
- return "File"
284
+ return "File" , False
264
285
elif handler_type == "Int" or handler_type == "Float" :
265
- return "Number"
286
+ return "Number" , handler_type == "Int"
266
287
elif handler_type == "Bool" :
267
- return "Flag"
288
+ return "Flag" , False
268
289
else :
269
- return "String"
290
+ return "String" , False
270
291
271
292
def is_list (spec_info ):
272
293
'''
@@ -336,3 +357,20 @@ def must_generate_value(name, type, ignored_template_inputs, spec_info, spec,
336
357
if not ignored_template_inputs :
337
358
return True
338
359
return not (name in ignored_template_inputs )
360
+
361
+
362
+ def get_description_from_spec (object , name , spec ):
363
+ '''
364
+ Generates a description based on the input or output spec.
365
+ '''
366
+ if not spec .desc :
367
+ spec .desc = "No description provided."
368
+ spec_info = spec .full_info (object , name , None )
369
+
370
+ boutiques_description = (spec_info .capitalize (
371
+ ) + ". " + spec .desc .capitalize ()).replace ("\n " , '' )
372
+
373
+ if not boutiques_description .endswith ('.' ):
374
+ boutiques_description += '.'
375
+
376
+ return boutiques_description
0 commit comments