Skip to content

nipype_cmd - run any Interface from a command line #795

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

Merged
merged 21 commits into from
Mar 19, 2015
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
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Next release
============
* ENH: Dropped support for now 7 years old Python 2.6 (https://github.com/nipy/nipype/pull/1069)
* FIX: terminal_output is not mandatory anymore (https://github.com/nipy/nipype/pull/1070)
* ENH: Added "nipype_cmd" tool for running interfaces from the command line (https://github.com/nipy/nipype/pull/795)
* FIX: Fixed Camino output naming (https://github.com/nipy/nipype/pull/1061)
* ENH: Add the average distance to ErrorMap (https://github.com/nipy/nipype/pull/1039)
* ENH: Inputs with name_source can be now chained in cascade (https://github.com/nipy/nipype/pull/938)
Expand Down
8 changes: 8 additions & 0 deletions bin/nipype_cmd
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.nipype_cmd import main

if __name__ == '__main__':
main(sys.argv)
1 change: 1 addition & 0 deletions doc/users/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
saving_workflows
spmmcr
mipav
nipypecmd
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file is missing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

On Wed, Mar 18, 2015 at 3:49 PM, Satrajit Ghosh notifications@github.com
wrote:

In doc/users/index.rst
#795 (comment):

@@ -37,6 +37,7 @@
saving_workflows
spmmcr
mipav

  • nipypecmd

this file is missing.


Reply to this email directly or view it on GitHub
https://github.com/nipy/nipype/pull/795/files#r26715700.




Expand Down
68 changes: 68 additions & 0 deletions doc/users/nipypecmd.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.. _nipypecmd:

============================================================
Running Nipype Interfaces from the command line (nipype_cmd)
============================================================

The primary use of Nipype_ is to build automated non-interactive pipelines.
However, sometimes there is a need to run some interfaces quickly from the command line.
This is especially useful when running Interfaces wrapping code that does not have
command line equivalents (nipy or SPM). Being able to run Nipype interfaces opens new
possibilities such as inclusion of SPM processing steps in bash scripts.

To run Nipype Interafces you need to use the nipype_cmd tool that should already be installed.
The tool allows you to list Interfaces available in a certain package:

.. testcode::


$nipype_cmd nipype.interfaces.nipy

Available Interfaces:
SpaceTimeRealigner
Similarity
ComputeMask
FitGLM
EstimateContrast
FmriRealign4d

After selecting a particular Interface you can learn what inputs it requires:

.. testcode::


$nipype_cmd nipype.interfaces.nipy ComputeMask --help

usage:nipype_cmd nipype.interfaces.nipy ComputeMask [-h] [--M M] [--cc CC]
[--ignore_exception IGNORE_EXCEPTION]
[--m M]
[--reference_volume REFERENCE_VOLUME]
mean_volume

Run ComputeMask

positional arguments:
mean_volume mean EPI image, used to compute the threshold for the
mask

optional arguments:
-h, --help show this help message and exit
--M M upper fraction of the histogram to be discarded
--cc CC Keep only the largest connected component
--ignore_exception IGNORE_EXCEPTION
Print an error message instead of throwing an
exception in case the interface fails to run
--m M lower fraction of the histogram to be discarded
--reference_volume REFERENCE_VOLUME
reference volume used to compute the mask. If none is
give, the mean volume is used.

Finally you can run run the Interface:

.. testcode::

$nipype_cmd nipype.interfaces.nipy ComputeMask mean.nii.gz

All that from the command line without having to start python interpreter manually.

.. include:: ../links_names.txt
72 changes: 72 additions & 0 deletions nipype/utils/nipype_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import os
import argparse
import inspect
import sys
from nipype.interfaces.base import Interface


def listClasses(module=None):
if module:
__import__(module)
pkg = sys.modules[module]
print "Available Interfaces:"
for k,v in pkg.__dict__.items():
if inspect.isclass(v) and issubclass(v, Interface):
print "\t%s"%k

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

inputs = interface.input_spec()
for name, spec in sorted(interface.inputs.traits(transient=None).items()):
desc = "\n".join(interface._get_trait_desc(inputs, name, spec))[len(name)+2:]
if hasattr(spec, "mandatory") and spec.mandatory:
parser.add_argument(name, help=desc)
else:
parser.add_argument("--%s"%name, dest=name,
help=desc)
return parser, interface

def run_instance(interface, options):
if interface:
print "setting function inputs"

for input_name, _ in interface.inputs.items():
if getattr(options, input_name) != None:
value = getattr(options, input_name)
#traits cannot cast from string to float or int
try:
value = float(value)
except:
pass

try:
setattr(interface.inputs, input_name,
value)
except ValueError, e:
print "Error when setting the value of %s: '%s'"%(input_name, str(e))

print interface.inputs
res = interface.run()
print res.outputs


def main(argv):

if len(argv) == 2 and not argv[1].startswith("-"):
listClasses(argv[1])
sys.exit(0)

parser = argparse.ArgumentParser(description='Nipype interface runner', 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]))
interface_parser, interface = add_options(interface_parser, parsed.module, parsed.interface)
args = interface_parser.parse_args(args=argv[3:])
run_instance(interface, args)
111 changes: 111 additions & 0 deletions nipype/utils/tests/test_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/usr/bin/env python

from StringIO import StringIO
import unittest, sys
from nipype.utils import nipype_cmd
from contextlib import contextmanager

@contextmanager
def capture_sys_output():
caputure_out, capture_err = StringIO(), StringIO()
current_out, current_err = sys.stdout, sys.stderr
try:
sys.stdout, sys.stderr = caputure_out, capture_err
yield caputure_out, capture_err
finally:
sys.stdout, sys.stderr = current_out, current_err


class TestNipypeCMD(unittest.TestCase):

def test_main_returns_2_on_empty(self):
with self.assertRaises(SystemExit) as cm:
with capture_sys_output() as (stdout, stderr):
nipype_cmd.main(['nipype_cmd'])

exit_exception = cm.exception
self.assertEqual(exit_exception.code, 2)

self.assertEqual(stderr.getvalue(),
"""usage: nipype_cmd [-h] module interface
nipype_cmd: error: too few arguments
""")
self.assertEqual(stdout.getvalue(), '')

def test_main_returns_0_on_help(self):
with self.assertRaises(SystemExit) as cm:
with capture_sys_output() as (stdout, stderr):
nipype_cmd.main(['nipype_cmd', '-h'])

exit_exception = cm.exception
self.assertEqual(exit_exception.code, 0)

self.assertEqual(stderr.getvalue(), '')
self.assertEqual(stdout.getvalue(),
"""usage: nipype_cmd [-h] module interface

Nipype interface runner

positional arguments:
module Module name
interface Interface name

optional arguments:
-h, --help show this help message and exit
""")

def test_list_nipy_interfacesp(self):
with self.assertRaises(SystemExit) as cm:
with capture_sys_output() as (stdout, stderr):
nipype_cmd.main(['nipype_cmd', 'nipype.interfaces.nipy'])

exit_exception = cm.exception
self.assertEqual(exit_exception.code, 0)

self.assertEqual(stderr.getvalue(), '')
self.assertEqual(stdout.getvalue(),
"""Available Interfaces:
SpaceTimeRealigner
Similarity
ComputeMask
FitGLM
EstimateContrast
FmriRealign4d
""")

def test_run_4d_realign_without_arguments(self):
with self.assertRaises(SystemExit) as cm:
with capture_sys_output() as (stdout, stderr):
nipype_cmd.main(['nipype_cmd', 'nipype.interfaces.nipy', 'FmriRealign4d'])

exit_exception = cm.exception
self.assertEqual(exit_exception.code, 2)

self.assertEqual(stderr.getvalue(),
"""usage: nipype_cmd nipype.interfaces.nipy FmriRealign4d [-h]
[--between_loops BETWEEN_LOOPS]
[--ignore_exception IGNORE_EXCEPTION]
[--loops LOOPS]
[--slice_order SLICE_ORDER]
[--speedup SPEEDUP]
[--start START]
[--time_interp TIME_INTERP]
[--tr_slices TR_SLICES]
in_file tr
nipype_cmd nipype.interfaces.nipy FmriRealign4d: error: too few arguments
""")
self.assertEqual(stdout.getvalue(), '')

def test_run_4d_realign_help(self):
with self.assertRaises(SystemExit) as cm:
with capture_sys_output() as (stdout, stderr):
nipype_cmd.main(['nipype_cmd', 'nipype.interfaces.nipy', 'FmriRealign4d', '-h'])

exit_exception = cm.exception
self.assertEqual(exit_exception.code, 0)

self.assertEqual(stderr.getvalue(), '')
self.assertTrue("Run FmriRealign4d" in stdout.getvalue())

if __name__ == '__main__':
unittest.main()
88 changes: 0 additions & 88 deletions tools/run_interface.py

This file was deleted.