Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions bin/nipype2boutiques
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env python
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
import sys
from nipype.utils.nipype2boutiques import main

if __name__ == '__main__':
main(sys.argv)
116 changes: 116 additions & 0 deletions nipype/utils/nipype2boutiques.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# This tool exports a Nipype interface in the Boutiques (https://github.com/boutiques) JSON format.
# Boutiques tools can be imported in CBRAIN (https://github.com/aces/cbrain) among other platforms.
#
# Limitations:
# * optional inputs are ignored because they are not supported in Boutiques.
# * inputs with cardinality "Multiple" (InputMultiPath in Nipype) are not supported. Same limitation for the outputs.
# * value-templates are wrong when output files are not created in the execution directory (e.g. when a sub-directory is created).

import os
import argparse
import inspect
import sys
import json
import tempfile

from nipype.interfaces.base import Interface

def create_tempfile():
fileTemp = tempfile.NamedTemporaryFile(delete = False)
fileTemp.write("hello")
fileTemp.close()
return fileTemp.name

def print_inputs(tool_name, module=None, function=None):
interface = None
if module and function:
__import__(module)
interface = getattr(sys.modules[module],function)()

inputs = interface.input_spec()
outputs = interface.output_spec()

command_line = "nipype_cmd "+str(module)+" "+tool_name+" "
tool_desc = {}
tool_desc['name'] = tool_name
tool_desc['description'] = "Tool description goes here"

tool_inputs = []
input_counter = 0
tool_outputs = []

for name, spec in sorted(interface.inputs.traits(transient=None).items()):

#FIXME: optional inputs are not supported yet
if not ( hasattr(spec, "mandatory") and spec.mandatory ):
continue

input = {}
input['name'] = name
type = spec.full_info(inputs, name, None)
if not "an existing file name" in type:
type = "String"
else:
type = "File"
input['type'] = type
input['description'] = "\n".join(interface._get_trait_desc(inputs, name, spec))[len(name)+2:].replace("\n\t\t",". ")
command_line_key = "["+str(input_counter)+"_"+name.upper()+"]"
input_counter += 1
input['command-line-key'] = command_line_key
input['cardinality'] = "Single"
tool_inputs.append(input)

if not ( hasattr(spec, "mandatory") and spec.mandatory ):
command_line+= "--%s"%name+" " # unreachable code as long as optional inputs are not supported

command_line+= command_line_key+" "

# add value to input so that output names can be generated
tempfile_name = create_tempfile()
input['tempfile_name'] = tempfile_name
if type == "File":
setattr(interface.inputs,name,os.path.abspath(tempfile_name))

for name,spec in sorted(outputs.traits(transient=None).items()):

output = {}
output['name'] = name
output['type'] = "File"
output['description'] = "No description provided"
output['command-line-key'] = ""
output['value-template'] = ""
output_value = interface._list_outputs()[name]
if output_value != "" and isinstance(output_value,str): # FIXME: this crashes when there are multiple output values.
# go find from which input file it was built
for input in tool_inputs:
base_file_name = os.path.splitext(os.path.basename(input['tempfile_name']))[0]
if base_file_name in output_value:
output_value = os.path.basename(output_value.replace(base_file_name,input['command-line-key'])) # FIXME: this only works if output is written in the current directory
output['value-template'] = os.path.basename(output_value)

output['cardinality'] = "Single"
if output['value-template'] != "": # outputs with no templates would certainly crash.
tool_outputs.append(output)

# remove all temporary file names from inputs
for input in tool_inputs:
del input['tempfile_name']

tool_desc['inputs'] = tool_inputs
tool_desc['outputs'] = tool_outputs
tool_desc['command-line'] = command_line
tool_desc['docker-image'] = 'docker.io/robdimsdale/nipype'
tool_desc['docker-index'] = 'http://index.docker.io'
tool_desc['schema-version'] = '0.1'
print json.dumps(tool_desc, indent=4, separators=(',', ': '))

def main(argv):

parser = argparse.ArgumentParser(description='Nipype Boutiques exporter', prog=argv[0])
parser.add_argument("module", type=str, help="Module name")
parser.add_argument("interface", type=str, help="Interface name")
parsed = parser.parse_args(args=argv[1:3])

_, prog = os.path.split(argv[0])
interface_parser = argparse.ArgumentParser(description="Run %s"%parsed.interface, prog=" ".join([prog] + argv[1:3]))
print_inputs(argv[2],parsed.module, parsed.interface)