77# Boutiques tools can be imported in CBRAIN (https://github.com/aces/cbrain) among other platforms.
88#
99# 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.
1712
1813import os
19- import argparse
2014import sys
21- import tempfile
2215import simplejson as json
23- import copy
2416import six
2517
2618from ..scripts .instance import import_module
2719
2820
2921def generate_boutiques_descriptor (
3022 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 ):
3224 '''
3325 Returns a JSON string containing a JSON Boutiques description of a Nipype interface.
3426 Arguments:
@@ -37,8 +29,6 @@ def generate_boutiques_descriptor(
3729 * container_image: name of the container image where the tool is installed
3830 * container_type: type of container image (Docker or Singularity)
3931 * 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.
4232 * verbose: print information messages
4333 * save: True if you want to save descriptor to a file
4434 * 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(
8070
8171 # Generates tool inputs
8272 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 )
8674 # Handle compound inputs (inputs that can be of multiple types and are mutually exclusive)
8775 if isinstance (input , list ):
8876 mutex_group_members = []
@@ -162,9 +150,7 @@ def generate_tool_outputs(outputs, interface, tool_desc, verbose, first_run):
162150
163151
164152def 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 ):
168154 """
169155 Returns a dictionary containing the Boutiques input corresponding to a Nipype intput.
170156
@@ -173,8 +159,7 @@ def get_boutiques_input(inputs, interface, input_name, spec,
173159 * interface: Nipype interface.
174160 * input_name: name of the Nipype input.
175161 * 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.
178163 * handler: used when handling compound inputs, which don't have their own input spec
179164 * input_number: used when handling compound inputs to assign each a unique ID
180165
@@ -205,8 +190,7 @@ def get_boutiques_input(inputs, interface, input_name, spec,
205190 # Recursively create an input for each trait
206191 for i in range (0 , len (trait_handler .handlers )):
207192 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 )
210194 inp ['optional' ] = True
211195 input_list .append (inp )
212196 return input_list
@@ -297,7 +281,7 @@ def get_boutiques_input(inputs, interface, input_name, spec,
297281 return input
298282
299283
300- def get_boutiques_output (outputs , name , spec , interface , tool_inputs , verbose = False ):
284+ def get_boutiques_output (outputs , name , spec , interface , tool_inputs ):
301285 """
302286 Returns a dictionary containing the Boutiques output corresponding to a Nipype output.
303287
@@ -367,6 +351,9 @@ def get_boutiques_output(outputs, name, spec, interface, tool_inputs, verbose=Fa
367351
368352
369353def 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+ """
370357 desc_groups = []
371358 all_or_none_input_sets = []
372359 mutex_input_sets = []
@@ -398,65 +385,6 @@ def get_boutiques_groups(input_traits):
398385 return desc_groups
399386
400387
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-
460388def get_description_from_spec (object , name , spec ):
461389 '''
462390 Generates a description based on the input or output spec.
@@ -506,21 +434,3 @@ def generate_custom_inputs(desc_inputs):
506434 for value in desc_input ['value-choices' ]:
507435 custom_input_dicts .append ({desc_input ['id' ]: value })
508436 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