7
7
# Boutiques tools can be imported in CBRAIN (https://github.com/aces/cbrain) among other platforms.
8
8
#
9
9
# Limitations:
10
- # * List outputs are not supported.
11
- # * Default values are not extracted from the documentation of the Nipype interface.
12
- # * The following input types must be ignored for the output path template creation (see option -t):
13
- # ** String restrictions, i.e. String inputs that accept only a restricted set of values.
14
- # ** mutually exclusive inputs.
15
- # * Path-templates are wrong when output files are not created in the execution directory (e.g. when a sub-directory is created).
16
- # * Optional outputs, i.e. outputs that not always produced, may not be detected.
10
+ # * Optional outputs, i.e. outputs that not always produced, may not be detected. They will, however, still be listed
11
+ # with a placeholder for the path template (either a value key or the output ID) that should be verified and corrected.
17
12
18
13
import os
19
- import argparse
20
14
import sys
21
- import tempfile
22
15
import simplejson as json
23
- import copy
24
16
import six
25
17
26
18
from ..scripts .instance import import_module
27
19
28
20
29
21
def generate_boutiques_descriptor (
30
22
module , interface_name , container_image , container_type , container_index = None ,
31
- ignored_template_inputs = (), ignore_template_numbers = False , verbose = False , save = False , save_path = None ):
23
+ verbose = False , save = False , save_path = None ):
32
24
'''
33
25
Returns a JSON string containing a JSON Boutiques description of a Nipype interface.
34
26
Arguments:
@@ -37,8 +29,6 @@ def generate_boutiques_descriptor(
37
29
* container_image: name of the container image where the tool is installed
38
30
* container_type: type of container image (Docker or Singularity)
39
31
* container_index: optional index where the image is available
40
- * ignored_template_inputs: a list of input names that should be ignored in the generation of output path templates.
41
- * ignore_template_numbers: True if numbers must be ignored in output path creations.
42
32
* verbose: print information messages
43
33
* save: True if you want to save descriptor to a file
44
34
* save_path: file path for the saved descriptor (defaults to name of the interface in current directory)
@@ -80,9 +70,7 @@ def generate_boutiques_descriptor(
80
70
81
71
# Generates tool inputs
82
72
for name , spec in sorted (interface .inputs .traits (transient = None ).items ()):
83
- input = get_boutiques_input (inputs , interface , name , spec ,
84
- ignored_template_inputs , verbose ,
85
- ignore_template_numbers )
73
+ input = get_boutiques_input (inputs , interface , name , spec , verbose )
86
74
# Handle compound inputs (inputs that can be of multiple types and are mutually exclusive)
87
75
if isinstance (input , list ):
88
76
mutex_group_members = []
@@ -162,9 +150,7 @@ def generate_tool_outputs(outputs, interface, tool_desc, verbose, first_run):
162
150
163
151
164
152
def get_boutiques_input (inputs , interface , input_name , spec ,
165
- ignored_template_inputs , verbose ,
166
- ignore_template_numbers , handler = None ,
167
- input_number = None ):
153
+ verbose , handler = None , input_number = None ):
168
154
"""
169
155
Returns a dictionary containing the Boutiques input corresponding to a Nipype intput.
170
156
@@ -173,8 +159,7 @@ def get_boutiques_input(inputs, interface, input_name, spec,
173
159
* interface: Nipype interface.
174
160
* input_name: name of the Nipype input.
175
161
* spec: Nipype input spec.
176
- * ignored_template_inputs: input names for which no temporary value must be generated.
177
- * ignore_template_numbers: True if numbers must be ignored in output path creations.
162
+ * verbose: print information messages.
178
163
* handler: used when handling compound inputs, which don't have their own input spec
179
164
* input_number: used when handling compound inputs to assign each a unique ID
180
165
@@ -205,8 +190,7 @@ def get_boutiques_input(inputs, interface, input_name, spec,
205
190
# Recursively create an input for each trait
206
191
for i in range (0 , len (trait_handler .handlers )):
207
192
inp = get_boutiques_input (inputs , interface , input_name , spec ,
208
- ignored_template_inputs , verbose ,
209
- ignore_template_numbers , trait_handler .handlers [i ], i )
193
+ verbose , trait_handler .handlers [i ], i )
210
194
inp ['optional' ] = True
211
195
input_list .append (inp )
212
196
return input_list
@@ -297,7 +281,7 @@ def get_boutiques_input(inputs, interface, input_name, spec,
297
281
return input
298
282
299
283
300
- def get_boutiques_output (outputs , name , spec , interface , tool_inputs , verbose = False ):
284
+ def get_boutiques_output (outputs , name , spec , interface , tool_inputs ):
301
285
"""
302
286
Returns a dictionary containing the Boutiques output corresponding to a Nipype output.
303
287
@@ -367,6 +351,9 @@ def get_boutiques_output(outputs, name, spec, interface, tool_inputs, verbose=Fa
367
351
368
352
369
353
def get_boutiques_groups (input_traits ):
354
+ """
355
+ Returns a list of dictionaries containing Boutiques groups for the mutually exclusive and all-or-none Nipype inputs.
356
+ """
370
357
desc_groups = []
371
358
all_or_none_input_sets = []
372
359
mutex_input_sets = []
@@ -398,65 +385,6 @@ def get_boutiques_groups(input_traits):
398
385
return desc_groups
399
386
400
387
401
- def get_unique_value (type , id ):
402
- '''
403
- Returns a unique value of type 'type', for input with id 'id',
404
- assuming id is unique.
405
- '''
406
- return {
407
- "File" : os .path .abspath (create_tempfile ()),
408
- "Boolean" : True ,
409
- "Number" : abs (hash (id )), # abs in case input param must be positive...
410
- "String" : id
411
- }[type ]
412
-
413
-
414
- def create_tempfile ():
415
- '''
416
- Creates a temp file and returns its name.
417
- '''
418
- fileTemp = tempfile .NamedTemporaryFile (delete = False )
419
- fileTemp .write (b"hello" )
420
- fileTemp .close ()
421
- return fileTemp .name
422
-
423
-
424
- def must_generate_value (name , type , ignored_template_inputs , spec_info , spec ,
425
- ignore_template_numbers ):
426
- '''
427
- Return True if a temporary value must be generated for this input.
428
- Arguments:
429
- * name: input name.
430
- * type: input_type.
431
- * ignored_template_inputs: a list of inputs names for which no value must be generated.
432
- * spec_info: spec info of the Nipype input
433
- * ignore_template_numbers: True if numbers must be ignored.
434
- '''
435
- # Return false when type is number and numbers must be ignored.
436
- if ignore_template_numbers and type == "Number" :
437
- return False
438
- # Only generate value for the first element of mutually exclusive inputs.
439
- if spec .xor and spec .xor [0 ] != name :
440
- return False
441
- # Directory types are not supported
442
- if "an existing directory name" in spec_info :
443
- return False
444
- # Don't know how to generate a list.
445
- if "a list" in spec_info or "a tuple" in spec_info :
446
- return False
447
- # Don't know how to generate a dictionary.
448
- if "a dictionary" in spec_info :
449
- return False
450
- # Best guess to detect string restrictions...
451
- if "' or '" in spec_info :
452
- return False
453
- if spec .default or spec .default_value ():
454
- return False
455
- if not ignored_template_inputs :
456
- return True
457
- return not (name in ignored_template_inputs )
458
-
459
-
460
388
def get_description_from_spec (object , name , spec ):
461
389
'''
462
390
Generates a description based on the input or output spec.
@@ -506,21 +434,3 @@ def generate_custom_inputs(desc_inputs):
506
434
for value in desc_input ['value-choices' ]:
507
435
custom_input_dicts .append ({desc_input ['id' ]: value })
508
436
return custom_input_dicts
509
-
510
-
511
- def generate_random_number_input (desc_input ):
512
- '''
513
- Generates a random number input based on the input spec
514
- '''
515
- if not desc_input .get ('minimum' ) and not desc_input .get ('maximum' ):
516
- return 1
517
-
518
- if desc_input .get ('integer' ):
519
- offset = 1
520
- else :
521
- offset = 0.1
522
-
523
- if desc_input .get ('minimum' ):
524
- return desc_input ['minimum' ] if desc_input .get ('exclusive-minimum' ) else desc_input ['minimum' ] + offset
525
- if desc_input .get ('maximum' ):
526
- return desc_input ['maximum' ] if desc_input .get ('exclusive-maximum' ) else desc_input ['maximum' ] - offset
0 commit comments