Skip to content
Snippets Groups Projects
Commit 55d57e02 authored by Martin Craig's avatar Martin Craig
Browse files

Merge branch 'msc' of https://git.fmrib.ox.ac.uk/paulmc/fslpy into msc

parents 0384e0b4 b1a428d7
No related branches found
No related tags found
No related merge requests found
......@@ -166,8 +166,8 @@ def run(*args, **kwargs):
- stderr: Optional file-like object to which the command's
standard error stream can be forwarded.
- cmd: If ``True``, the command itself is logged to the
standard output stream(s).
- cmd: Optional file-like object to which the command itself
is logged.
:returns: If ``submit`` is provided, the return value of
:func:`.fslsub` is returned. Otherwise returns a single
......@@ -194,7 +194,7 @@ def run(*args, **kwargs):
tee = log .get('tee', False)
logStdout = log .get('stdout', None)
logStderr = log .get('stderr', None)
logCmd = log .get('cmd', False)
logCmd = log .get('cmd', None)
args = _prepareArgs(args)
if not bool(submit):
......@@ -272,8 +272,8 @@ def _realrun(tee, logStdout, logStderr, logCmd, *args):
:arg logStderr: Optional file-like object to which the command's standard
error stream can be forwarded.
:arg logCmd: If ``True``, the command itself is logged to the standard
output stream(s).
:arg logCmd: Optional file-like object to which the command itself is
logged.
:arg args: Command to run
......@@ -308,15 +308,13 @@ def _realrun(tee, logStdout, logStderr, logCmd, *args):
if logStdout is not None: outstreams.append(logStdout)
if logStderr is not None: errstreams.append(logStderr)
# log the command to
# stdout if requested
if logCmd:
# log the command if requested
if logCmd is not None:
cmd = ' '.join(args) + '\n'
for o in outstreams:
if 'b' in getattr(o, 'mode', 'w'):
o.write(cmd.encode('utf-8'))
else:
o.write(cmd)
if 'b' in getattr(logCmd, 'mode', 'w'):
logCmd.write(cmd.encode('utf-8'))
else:
logCmd.write(cmd)
stdoutt = _forwardStream(proc.stdout, *outstreams)
stderrt = _forwardStream(proc.stderr, *errstreams)
......@@ -340,23 +338,35 @@ def _realrun(tee, logStdout, logStderr, logCmd, *args):
def runfsl(*args, **kwargs):
"""Call a FSL command and return its output. This function simply prepends
``$FSLDIR/bin/`` to the command before passing it to :func:`run`.
"""Call a FSL command and return its output.
This function searches for the command in the following
locations (ordered by priority):
1. ``FSL_PREFIX``
2. ``$FSLDEVDIR/bin``
3. ``$FSLDIR/bin``
If found, the full path to the command is then passed to :func:`run`.
"""
prefix = None
prefixes = []
if FSL_PREFIX is not None:
prefix = FSL_PREFIX
elif fslplatform.fsldevdir is not None:
prefix = op.join(fslplatform.fsldevdir, 'bin')
elif fslplatform.fsldir is not None:
prefix = op.join(fslplatform.fsldir, 'bin')
else:
prefixes.append(FSL_PREFIX)
if fslplatform.fsldevdir is not None:
prefixes.append(op.join(fslplatform.fsldevdir, 'bin'))
if fslplatform.fsldir is not None:
prefixes.append(op.join(fslplatform.fsldir, 'bin'))
if not prefixes:
raise FSLNotPresent('$FSLDIR is not set - FSL cannot be found!')
args = _prepareArgs(args)
args[0] = op.join(prefix, args[0])
args = _prepareArgs(args)
for prefix in prefixes:
cmdpath = op.join(prefix, args[0])
if op.isfile(cmdpath):
args[0] = cmdpath
break
return run(*args, **kwargs)
......
......@@ -80,8 +80,10 @@ from .wrapperutils import (LOAD,) # noqa
from .bet import (bet, # noqa
robustfov)
from .eddy import (eddy_cuda, # noqa
topup)
topup,
applytopup)
from .fast import (fast,) # noqa
from .fsl_anat import (fsl_anat,) # noqa
from .flirt import (flirt, # noqa
invxfm,
applyxfm,
......
......@@ -35,6 +35,7 @@ def bet(input, output, **kwargs):
'robust' : 'R',
'fracintensity' : 'f',
'seg' : 'n',
'centre' : 'c',
}
valmap = {
......@@ -55,6 +56,14 @@ def bet(input, output, **kwargs):
}
cmd = ['bet', input, output]
# The 'centre' argument requires three co-ordinates and can't be passed
# as a single value, so needs to be handled separately. Assume it is
# passed as a Python sequence
centre = kwargs.pop("c", None)
if centre is not None:
cmd += ['c', ] + list(centre)
cmd += wutils.applyArgStyle('-', argmap=argmap, valmap=valmap, **kwargs)
return cmd
......
......@@ -61,8 +61,8 @@ def eddy_cuda(imain, mask, index, acqp, bvecs, bvals, out, **kwargs):
return cmd
@wutils.fileOrImage('imain', 'fout', 'iout')
@wutils.fileOrArray('datain')
@wutils.fileOrImage('imain', 'fout', 'iout', outprefix='out')
@wutils.fileOrArray('datain', outprefix='out')
@wutils.fslwrapper
def topup(imain, datain, **kwargs):
"""Wrapper for the ``topup`` command."""
......@@ -78,3 +78,25 @@ def topup(imain, datain, **kwargs):
cmd += wutils.applyArgStyle('--=', valmap=valmap, **kwargs)
return cmd
@wutils.fileOrImage('imain', 'out')
@wutils.fileOrArray('datain')
@wutils.fslwrapper
def applytopup(imain, datain, index, **kwargs):
"""Wrapper for the ``applytopup`` command."""
valmap = {
'verbose' : wutils.SHOW_IF_TRUE
}
asrt.assertFileExists(datain)
asrt.assertIsNifti(imain)
cmd = [
'applytopup', '--imain={}'.format(imain),
'--inindex={}'.format(index),
'--datain={}'.format(datain),
]
cmd += wutils.applyArgStyle('--=', valmap=valmap, **kwargs)
return cmd
......@@ -33,12 +33,19 @@ def fast(imgs, out='fast', **kwargs):
asrt.assertIsNifti(*imgs)
valmap = {
'nobias' : wutils.SHOW_IF_TRUE,
'verbose' : wutils.SHOW_IF_TRUE,
'Prior' : wutils.SHOW_IF_TRUE,
'segments' : wutils.SHOW_IF_TRUE,
}
argmap = {
'n_classes' : 'class',
}
cmd = ['fast', '-v', '--out=%s' % out]
cmd += wutils.applyArgStyle('--=', argmap=argmap, **kwargs)
cmd += wutils.applyArgStyle('--=', valmap=valmap, argmap=argmap, singlechar_args=True, **kwargs)
cmd += imgs
return cmd
......@@ -59,14 +59,15 @@ def flirt(src, ref, **kwargs):
return cmd
def applyxfm(src, ref, mat, out, interp='spline'):
def applyxfm(src, ref, mat, out, interp='spline', **kwargs):
"""Convenience function which runs ``flirt -applyxfm ...``."""
return flirt(src,
ref,
out=out,
applyxfm=True,
init=mat,
interp=interp)
interp=interp,
**kwargs)
@wutils.fileOrArray()
......
......@@ -27,12 +27,12 @@ from . import wrapperutils as wutils
'refout', 'refmask', 'inmask')
@wutils.fileOrArray('aff')
@wutils.fslwrapper
def fnirt(src, ref, **kwargs):
def fnirt(src, **kwargs):
"""Wrapper for the ``fnirt`` command."""
asrt.assertIsNifti(src, ref)
asrt.assertIsNifti(src)
cmd = ['fnirt', '--in={}'.format(src), '--ref={}'.format(ref)]
cmd = ['fnirt', '--in={}'.format(src)]
cmd += wutils.applyArgStyle('--=', **kwargs)
return cmd
......@@ -41,7 +41,7 @@ def fnirt(src, ref, **kwargs):
@wutils.fileOrImage('src', 'ref', 'out', 'warp', 'mask')
@wutils.fileOrArray('premat', 'postmat')
@wutils.fslwrapper
def applywarp(src, ref, out, warp, **kwargs):
def applywarp(src, ref, out, **kwargs):
"""Wrapper for the ``applywarp`` command. """
valmap = {
......@@ -55,8 +55,7 @@ def applywarp(src, ref, out, warp, **kwargs):
cmd = ['applywarp',
'--in={}'.format(src),
'--ref={}'.format(ref),
'--out={}'.format(out),
'--warp={}'.format(warp)]
'--out={}'.format(out)]
cmd += wutils.applyArgStyle('--=', valmap=valmap, **kwargs)
......@@ -76,7 +75,7 @@ def invwarp(warp, ref, out, **kwargs):
'verbose' : wutils.SHOW_IF_TRUE,
}
asrt.assertIsNifti(warp, ref, out)
asrt.assertIsNifti(warp, ref)
cmd = ['invwarp',
'--warp={}'.format(warp),
......@@ -88,7 +87,7 @@ def invwarp(warp, ref, out, **kwargs):
return cmd
@wutils.fileOrImage('out', 'ref', 'warp1', 'warp2', 'shiftmap')
@wutils.fileOrImage('out', 'ref', 'warp1', 'warp2', 'shiftmap', 'jacobian')
@wutils.fileOrArray('premat', 'midmat', 'postmat')
@wutils.fslwrapper
def convertwarp(out, ref, **kwargs):
......@@ -99,7 +98,6 @@ def convertwarp(out, ref, **kwargs):
'rel' : wutils.SHOW_IF_TRUE,
'absout' : wutils.SHOW_IF_TRUE,
'relout' : wutils.SHOW_IF_TRUE,
'jacobian' : wutils.SHOW_IF_TRUE,
'jstats' : wutils.SHOW_IF_TRUE,
'constrainj' : wutils.SHOW_IF_TRUE,
'verbose' : wutils.SHOW_IF_TRUE,
......@@ -107,5 +105,4 @@ def convertwarp(out, ref, **kwargs):
cmd = ['convertwarp', '--ref={}'.format(ref), '--out={}'.format(out)]
cmd += wutils.applyArgStyle('--=', valmap=valmap, **kwargs)
return cmd
#!/usr/bin/env python
#
# fsl_anat.py - Wrapper for the FSL_ANAT command.
#
# Author: Martin Craig <martin.craig@eng.ox.ac.uk>
#
"""This module provides the :func:`fsl_anat` function, a wrapper for the FSL
`FSL_ANAT <https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/fsl_anat>`_ command.
"""
import six
import fsl.utils.assertions as asrt
from . import wrapperutils as wutils
@wutils.fileOrImage('img', outprefix='out')
@wutils.fslwrapper
def fsl_anat(img, out='fsl_anat', **kwargs):
"""Wrapper for the ``fsl_anat`` command.
:arg img: Input structural image
:arg out: Output directory name
"""
asrt.assertIsNifti(img)
valmap = {
'strongbias' : wutils.SHOW_IF_TRUE,
'weakbias' : wutils.SHOW_IF_TRUE,
'noreorient' : wutils.SHOW_IF_TRUE,
'nocrop' : wutils.SHOW_IF_TRUE,
'nobias' : wutils.SHOW_IF_TRUE,
'noreg' : wutils.SHOW_IF_TRUE,
'nononlinreg' : wutils.SHOW_IF_TRUE,
'noseg' : wutils.SHOW_IF_TRUE,
'nosubcortseg' : wutils.SHOW_IF_TRUE,
'nosearch' : wutils.SHOW_IF_TRUE,
'nocleanup' : wutils.SHOW_IF_TRUE,
}
argmap = {
}
img_type = kwargs.pop("img_type", "T1")
cmd = ['fsl_anat', '-i', img, '-o', out, '-t', img_type]
smoothing = kwargs.pop("bias_smoothing", None)
if smoothing is not None:
cmd += ['-s', str(smoothing)]
cmd += wutils.applyArgStyle('--=', valmap=valmap, argmap=argmap, singlechar_args=True, **kwargs)
return cmd
......@@ -152,11 +152,13 @@ def cmdwrapper(func):
:func:`fsl.utils.run.run` function in a standardised manner.
"""
def wrapper(*args, **kwargs):
stdout = kwargs.pop('stdout', True)
stderr = kwargs.pop('stderr', False)
exitcode = kwargs.pop('exitcode', False)
submit = kwargs.pop('submit', None)
stderr = kwargs.pop('stderr', True)
log = kwargs.pop('log', {'tee' : True})
cmd = func(*args, **kwargs)
return run.run(cmd, stderr=stderr, log=log, submit=submit)
return run.run(cmd, stderr=stderr, log=log, submit=submit, stdout=stdout, exitcode=exitcode)
return _update_wrapper(wrapper, func)
......@@ -166,11 +168,13 @@ def fslwrapper(func):
:func:`fsl.utils.run.runfsl` function in a standardised manner.
"""
def wrapper(*args, **kwargs):
stdout = kwargs.pop('stdout', True)
stderr = kwargs.pop('stderr', False)
exitcode = kwargs.pop('exitcode', False)
submit = kwargs.pop('submit', None)
stderr = kwargs.pop('stderr', True)
log = kwargs.pop('log', {'tee' : True})
cmd = func(*args, **kwargs)
return run.runfsl(cmd, stderr=stderr, log=log, submit=submit)
return run.runfsl(cmd, stderr=stderr, log=log, submit=submit, stdout=stdout, exitcode=exitcode)
return _update_wrapper(wrapper, func)
......@@ -192,7 +196,7 @@ generated command line arguments.
"""
def applyArgStyle(style, valsep=None, argmap=None, valmap=None, **kwargs):
def applyArgStyle(style, valsep=None, argmap=None, valmap=None, singlechar_args=False, **kwargs):
"""Turns the given ``kwargs`` into command line options. This function
is intended to be used to automatically generate command line options
from arguments passed into a Python function.
......@@ -251,6 +255,9 @@ def applyArgStyle(style, valsep=None, argmap=None, valmap=None, **kwargs):
The argument for any options not specified in the ``valmap``
will be converted into strings.
:arg singlechar_args: If True, single character arguments always take a single
hyphen prefix (e.g. -h) regardless of the style
:arg kwargs: Arguments to be converted into command-line options.
:returns: A list containing the generated command-line options.
......@@ -276,7 +283,7 @@ def applyArgStyle(style, valsep=None, argmap=None, valmap=None, **kwargs):
if valmap is None: valmap = {}
def fmtarg(arg):
if style in ('-', '-='): arg = '-{}'.format(arg)
if style in ('-', '-=') or (singlechar_args and len(arg) == 1): arg = '-{}'.format(arg)
elif style in ('--', '--='): arg = '--{}'.format(arg)
return arg
......@@ -303,11 +310,12 @@ def applyArgStyle(style, valsep=None, argmap=None, valmap=None, **kwargs):
for k, v in kwargs.items():
if v is None: continue
k = argmap.get(k, k)
mapv = valmap.get(k, fmtval(v))
k = fmtarg(k)
if mapv in (SHOW_IF_TRUE, HIDE_IF_TRUE):
if (mapv is SHOW_IF_TRUE and v) or \
(mapv is HIDE_IF_TRUE and not v):
......@@ -849,7 +857,6 @@ class _FileOrThing(object):
for prefixed in it.chain(*allPrefixed):
fullpath = prefixed
prefixed = op.relpath(prefixed, workdir)
for prefPat, prefName in prefixes.items():
if not fnmatch.fnmatch(prefixed, '{}*'.format(prefPat)):
continue
......@@ -862,10 +869,17 @@ class _FileOrThing(object):
# not of the correct type.
fval = self.__load(fullpath)
if fval is not None:
prefixed = self.__removeExt(prefixed)
noext = self.__removeExt(prefixed)
prefPat = prefPat.replace('\\', '\\\\')
prefixed = re.sub('^' + prefPat, prefName, prefixed)
result[prefixed] = fval
noext = re.sub('^' + prefPat, prefName, noext)
# If there is already an item in result with the
# name (stripped of prefix), then instead store
# the result with the full prefixed name
if noext not in result:
result[noext] = fval
else:
withext = re.sub('^' + prefPat, prefName, prefixed)
result[withext] = fval
break
return result
......@@ -887,8 +901,11 @@ def fileOrImage(*args, **kwargs):
infile = None
if isinstance(val, (fslimage.Image, nib.nifti1.Nifti1Image)):
intypes.append(type(val))
if isinstance(val, fslimage.Image):
intypes.append(fslimage.Image)
elif isinstance(val, nib.nifti1.Nifti1Image):
intypes.append(nib.nifti1.Nifti1Image)
if isinstance(val, fslimage.Image):
val = val.nibImage
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment