-
Notifications
You must be signed in to change notification settings - Fork 533
REF: Update nipype2boutiques script #2894
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…value for tool-version when interface version is null
…s the same as an input name
…ices extraction, added method to get input type from handler type
… added check for integer types, added method to get description from spec
…flag to take argstr from input spec, added requires-inputs and disables-inputs
…k to deal with undefined output values
…puts don't disable themselves, made default output path template the output id
…with various different inputs to try and generate as many outputs as possible
… numbers, some other minor fixes
…ly custom path for saved file
…aused too many failures)
Codecov Report
@@ Coverage Diff @@
## master #2894 +/- ##
=========================================
Coverage ? 64.06%
=========================================
Files ? 342
Lines ? 43835
Branches ? 5507
=========================================
Hits ? 28084
Misses ? 14639
Partials ? 1112
Continue to review full report at Codecov.
|
Thanks for doing this @erinb90, it looks great to me! |
…nd line, added logic to deal with inputs containing name_source and name_template metadata
…to 1.0.0, added logic to deal with 0/1 booleans and tuples, added list separator and flag separator checks
…ipype2boutiques
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @erinb90, thanks for the patch - it's a big jump from the previous version supported! I left a few comments (mostly style) - you'll also have to update the nipypecli call
Lines 243 to 254 in 232ac23
def boutiques(interface, module, output, ignored_template_inputs, docker_image, | |
docker_index, ignore_template_numbers, verbose): | |
"""Nipype to Boutiques exporter. | |
See Boutiques specification at https://github.com/boutiques/schema. | |
""" | |
from nipype.utils.nipype2boutiques import generate_boutiques_descriptor | |
# Generates JSON string | |
json_string = generate_boutiques_descriptor( | |
module, interface, ignored_template_inputs, docker_image, docker_index, | |
verbose, ignore_template_numbers) |
nipype/utils/nipype2boutiques.py
Outdated
tool_desc['tags'] = desc_tags | ||
|
||
# Check for positional arguments and reorder command line args if necessary | ||
tool_desc['command-line'] = reorder_cmd_line_args(tool_desc['command-line'], interface, ignore_inputs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rf: line length
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mgxd What should be the max line length?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should follow pep8 conventions, so 79 characters
nipype/utils/nipype2boutiques.py
Outdated
if verbose: | ||
print("-> Descriptor saved to file " + outfile.name) | ||
|
||
print("NOTE: Descriptors produced by this script may not entirely conform to the Nipype interface " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rf: line length
nipype/utils/nipype2boutiques.py
Outdated
|
||
inp = {} | ||
|
||
if input_number is not None and input_number != 0: # No need to append a number to the first of a list of compound inputs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if input_number is not None and input_number != 0: # No need to append a number to the first of a list of compound inputs | |
if input_number: # No need to append a number to the first of a list of compound inputs |
nipype/utils/nipype2boutiques.py
Outdated
elif handler_type == "Float": | ||
inp['type'] = "Number" | ||
elif handler_type == "Bool": | ||
if spec.argstr and len(spec.argstr.split("=")) > 1 and (spec.argstr.split("=")[1] == '0' or spec.argstr.split("=")[1] == '1'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rf: line length
nipype/utils/nipype2boutiques.py
Outdated
source = inp_spec.name_source[0] | ||
else: | ||
source = inp_spec.name_source | ||
output['path-template'] = inp_spec.name_template.replace("%s", "[" + source.upper() + "]") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rf: line length
nipype/utils/nipype2boutiques.py
Outdated
def get_type_from_spec_info(spec_info): | ||
def get_boutiques_groups(input_traits): | ||
""" | ||
Returns a list of dictionaries containing Boutiques groups for the mutually exclusive and all-or-none Nipype inputs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rf: line length
nipype/utils/nipype2boutiques.py
Outdated
continue | ||
positional_args.append(item[1]) | ||
|
||
return interface_name + " " + " ".join(positional_args) + " " + ((last_arg + " ") if last_arg else "") + " ".join(non_positional_args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rf: line length
nipype/utils/nipype2boutiques.py
Outdated
tool_desc['docker-index'] = docker_index | ||
tool_desc['output-files'] = [] | ||
tool_desc['groups'] = [] | ||
tool_desc['tool-version'] = interface.version if interface.version is not None else "1.0.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be better to state no version was provided rather than assume this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nipype/utils/nipype2boutiques.py
Outdated
|
||
# Save descriptor to a file | ||
if save: | ||
path = save_path if save_path is not None else os.path.join(os.getcwd(), interface_name + '.json') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
path = save_path if save_path is not None else os.path.join(os.getcwd(), interface_name + '.json') | |
path = save_path or os.path.join(os.getcwd(), interface_name + '.json') |
…output from a Nipype input spec, code style fixes, some refactoring and improvements
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great - thanks! To get the tests passing, you'll need to merge with master.
Only other thing I would suggest before merging this in is supplementing / adding a test that checks the boutique output, if you're up to it.
author=("Oxford Centre for Functional" | ||
" MRI of the Brain (FMRIB)")) | ||
|
||
with open('utils/nipype2boutiques_example.json', 'r', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @mgxd, I want to use this example output file in my test case but am not sure how to reference it (what I have above doesn't work). What should the path be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some suggestions to get stuff working again
@@ -0,0 +1,549 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file should go in nipype/testing/data
. You can then import the data with
from nipype.testing import example_data
example_data('relative/path/from/testing/directory')
" MRI of the Brain (FMRIB)")) | ||
|
||
with open('utils/nipype2boutiques_example.json', 'r', | ||
encoding='utf-8') as desc_file: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
encoding
will not work on Py2 - though if replace open
with from io import open
, it should fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll just remove encoding
, it's not necessary here.
So my test is failing because on CircleCI the descriptor produced has interface version 5.0.9, while the example file has version 1.0.0 (placeholder when version is not found). When I run |
@erinb90 the Circle build has FSL 5.0.9 installed, so the good thing is it's outputting what's expected. To avoid having to constantly reconfigure this test though, I would recommend checking only a subset of fields that will be consistent across environments. |
8976e35
to
0eae216
Compare
@erinb90 if you sync with current master it'll fix the travis tests |
…ipype2boutiques
…se when command line flag includes a 0 or 1 (seen in FNIRT)
nipype/utils/nipype2boutiques.py
Outdated
inp['type'] = "String" | ||
if trait_handler.minlen != 0: | ||
inp['min-list-entries'] = trait_handler.minlen | ||
if trait_handler.maxlen != six.MAXSIZE: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if trait_handler.maxlen != six.MAXSIZE: | |
if trait_handler.maxlen != sys.maxsize: |
nipype/utils/nipype2boutiques.py
Outdated
import simplejson as json | ||
import six |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't use six as a dependency of nipype. this bit should use the relevant pieces from future
import six |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I seem to have broken something in the build in removing this import. It fails with:
UnsatisfiableError: The following specifications were found to be in conflict:
- matplotlib
Use "conda search <package> --info" to see the dependencies for each package.
Do you know where this could come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@erinb90 the error is unrelated, and should be fixed if you fetch current master
Sorry for all these CI build inconveniences - it seems everything waited on your PR to break
…ipype2boutiques
Summary
boutiques/boutiques#135
Refactored and improved the
nipype2boutiques
script that converts Nipype interfaces into Boutiques descriptors. It's still not perfect, and doesn't cover every edge case (might even crash for some interfaces), but it does a lot more than it did before. May update this or make another PR in the future if I find ways to improve it more.Examples of script output
@glatard @gkiar
Acknowledgment