Commit 9d8fb91a authored by Paul McCarthy's avatar Paul McCarthy 🚵
Browse files

Merge branch 'enh/tbss_wrappers' into 'master'

Enh/tbss wrappers

See merge request fsl/fslpy!260
parents ded1c5af 2e878669
Pipeline #5687 canceled with stages
in 7 seconds
......@@ -3,4 +3,5 @@ Michiel Cottaar <michiel.cottaar@ndcn.ox.ac.uk>
Matthew Webster <matthew.webster@ndcn.ox.ac.uk>
Sean Fitzgibbon <sean.fitzgibbon@ndcn.ox.ac.uk>
Martin Craig <martin.craig@eng.ox.ac.uk>
Taylor Hanayik <taylor.hanayik@ndcn.ox.ac.uk>
\ No newline at end of file
Taylor Hanayik <taylor.hanayik@ndcn.ox.ac.uk>
Evan Edmond <evan.edmond@ndcn.ox.ac.uk>
\ No newline at end of file
......@@ -2,6 +2,26 @@ This document contains the ``fslpy`` release history in reverse chronological
order.
3.4.0 (Tuesday 20th October 2020)
---------------------------------
Added
^^^^^
* New :mod:`.tbss` wrapper functions for `TBSS
<https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/TBSS>`_ commands.
Changed
^^^^^^^
* Calls to functions in the :mod:`.assertions` module are disabled when a
wrapper function is called with ``cmdonly=True``.
3.3.3 (Wednesday 13th October 2020)
-----------------------------------
......
......@@ -15,6 +15,7 @@
fsl.wrappers.fugue
fsl.wrappers.melodic
fsl.wrappers.misc
fsl.wrappers.tbss
fsl.wrappers.wrapperutils
.. automodule:: fsl.wrappers
......
``fsl.wrappers.tbss``
=====================
.. automodule:: fsl.wrappers.tbss
:members:
:undoc-members:
:show-inheritance:
......@@ -33,25 +33,32 @@ import fsl.utils.ensure as ensure
import fsl.data.melodicanalysis as fslma
_DISABLE_ASSERTIONS = False
"""
"""
_DISABLE_ASSERTIONS = 0
"""Semaphore used by the :func:`disabled` context manager. """
@contextlib.contextmanager
def disabled():
def disabled(disable=True):
"""Context manager which allows assertion checks to be temporarily
disabled.
If calls to this function are nested, only one of the calls need to be made
with ``disable=True`` for assertions to be disabled; any other calls which
are part of the call stack which set ``disable=False`` will have no effect.
:arg disable: Set to ``True`` (the default) to disable assertions,
or ``False`` to enable them.
"""
global _DISABLE_ASSERTIONS
oldval = _DISABLE_ASSERTIONS
_DISABLE_ASSERTIONS = True
if disable:
_DISABLE_ASSERTIONS += 1
try:
yield
finally:
_DISABLE_ASSERTIONS = oldval
if disable:
_DISABLE_ASSERTIONS -= 1
def _canDisable(func):
......@@ -59,7 +66,7 @@ def _canDisable(func):
via the :func:`disabled` context manager.
"""
def wrapper(*args, **kwargs):
if not _DISABLE_ASSERTIONS:
if _DISABLE_ASSERTIONS == 0:
return func(*args, **kwargs)
return wrapper
......
......@@ -47,7 +47,7 @@ import re
import string
__version__ = '3.4.0.dev0'
__version__ = '3.5.0.dev0'
"""Current version number, as a string. """
......
......@@ -109,3 +109,4 @@ from .misc import (fslreorient2std, # noqa
slicer,
cluster,
gps)
from . import tbss # noqa
#!/usr/bin/env python3
#
# tbss.py - Wrappers for FSL command-line tools for tract based spatial
# statistics (TBSS).
#
# Author: Evan Edmond <eedmond@gmail.com>
#
"""This module contains wrapper functions for various `TBSS
<https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/TBSS/>`_ command-line tools.
"""
import fsl.utils.assertions as asrt
from . import wrapperutils as wutils
@wutils.fslwrapper
def preproc(*images):
"""Wrapper for the ``tbss_1_preproc`` command.
Usage: ``tbss_1_preproc(<image1>, <image2>, ...)``
"""
for img in images:
asrt.assertIsNifti(img)
return ["tbss_1_preproc"] + list(images)
@wutils.fslwrapper
def reg(**kwargs):
"""Wrapper for the ``tbss_2_reg`` command.
Refer to the ``tbss_2_reg`` command-line help for details on all arguments.
"""
valmap = {
'T' : wutils.SHOW_IF_TRUE,
'n' : wutils.SHOW_IF_TRUE,
}
cmd = ["tbss_2_reg"]
cmd += wutils.applyArgStyle("-", valmap=valmap, valsep=" ", **kwargs)
return cmd
@wutils.fslwrapper
def postreg(**kwargs):
"""Wrapper for the ``tbss_3_postreg`` command.
Refer to the ``tbss_3_postreg`` command-line help for details on all
arguments.
"""
valmap = {
'T' : wutils.SHOW_IF_TRUE,
'S' : wutils.SHOW_IF_TRUE,
}
cmd = ["tbss_3_postreg"]
cmd += wutils.applyArgStyle("-", valmap=valmap, **kwargs)
return cmd
@wutils.fslwrapper
def prestats(threshold):
"""Wrapper for the ``tbss_4_prestats`` command.
The normal recommendation for <threshold> is 0.2
"""
return ["tbss_4_prestats", f'{threshold}']
@wutils.fslwrapper
def non_FA(alt_img_root):
"""Wrapper for the ``tbss_non_FA`` command.
e.g.: ``tbss_non_FA("L2")``
"""
return ["tbss_non_FA", alt_img_root]
@wutils.fileOrImage("stats_image", "mean_FA", "output")
@wutils.fslwrapper
def fill(stats_image, threshold, mean_FA, output, **kwargs):
"""Wrapper for the ``tbss_fill`` command.
Refer to the ``tbss_fill`` command-line help for details on all arguments.
"""
valmap = {
'n' : wutils.SHOW_IF_TRUE,
}
cmd = ["tbss_fill", stats_image, f'{threshold}', mean_FA, output]
cmd += wutils.applyArgStyle("-", valmap=valmap, **kwargs)
return cmd
......@@ -108,10 +108,11 @@ import six
import nibabel as nib
import numpy as np
import fsl.utils.run as run
import fsl.utils.path as fslpath
import fsl.utils.tempdir as tempdir
import fsl.data.image as fslimage
import fsl.utils.run as run
import fsl.utils.assertions as asrt
import fsl.utils.path as fslpath
import fsl.utils.tempdir as tempdir
import fsl.data.image as fslimage
log = logging.getLogger(__name__)
......@@ -185,7 +186,14 @@ def genxwrapper(func, runner):
submit = kwargs.pop('submit', None)
cmdonly = kwargs.pop('cmdonly', False)
log = kwargs.pop('log', {'tee' : True})
cmd = func(*args, **kwargs)
# many wrapper functions use fsl.utils.assertions
# statements to check that input arguments are
# valid. Disable these if the cmdonly argument is
# being used to generate a command without running
# it.
with asrt.disabled(cmdonly):
cmd = func(*args, **kwargs)
return runner(cmd,
stderr=stderr,
......
......@@ -357,3 +357,31 @@ def test_gps():
expected = (gps + ' --ndir=128 --out=bvecs',
('--optws', '--ranseed=123'))
assert checkResult(result.stdout[0], *expected)
def test_tbss():
exes = {
'preproc' : 'tbss_1_preproc',
'reg' : 'tbss_2_reg',
'postreg' : 'tbss_3_postreg',
'prestats' : 'tbss_4_prestats',
'non_FA' : 'tbss_non_FA',
'fill' : 'tbss_fill'
}
with asrt.disabled(), \
run.dryrun(), \
mockFSLDIR(bin=exes.values()) as fsldir:
for k in exes:
exes[k] = op.join(fsldir, 'bin', exes[k])
assert fw.tbss.preproc('1', '2')[0] == ' '.join([exes['preproc'], '1', '2'])
assert fw.tbss.reg(T=True)[0] == ' '.join([exes['reg'], '-T'])
assert fw.tbss.reg(n=True)[0] == ' '.join([exes['reg'], '-n'])
assert fw.tbss.reg(t='target')[0] == ' '.join([exes['reg'], '-t', 'target'])
assert fw.tbss.postreg(S=True)[0] == ' '.join([exes['postreg'], '-S'])
assert fw.tbss.postreg(T=True)[0] == ' '.join([exes['postreg'], '-T'])
assert fw.tbss.prestats(0.3)[0] == ' '.join([exes['prestats'], '0.3'])
assert fw.tbss.non_FA('alt')[0] == ' '.join([exes['non_FA'], 'alt'])
assert fw.tbss.fill('stat', 0.4, 'mean_fa', 'output', n=True).stdout[0] == \
' '.join([exes['fill'], 'stat', '0.4', 'mean_fa', 'output', '-n'])
......@@ -22,12 +22,13 @@ import nibabel as nib
import fsl.utils.tempdir as tempdir
import fsl.utils.run as run
import fsl.utils.assertions as asrt
import fsl.utils.fslsub as fslsub
import fsl.data.image as fslimage
import fsl.wrappers.wrapperutils as wutils
from .. import mockFSLDIR, cleardir, checkdir, testdir
from .. import mockFSLDIR, cleardir, checkdir, testdir, touch
from ..test_run import mock_submit
......@@ -861,3 +862,19 @@ def test_cmdwrapper_fileorthing_cmdonly():
cmd = test_func('1', '2', cmdonly=True)
assert ran.stdout[0].strip() == 'test_script running: 1 2'
assert cmd == ['test_script', '1', '2']
def test_cmdwrapper_cmdonly_assert():
@wutils.cmdwrapper
def func():
asrt.assertFileExists('file')
return ['echo', 'hello']
with tempdir.tempdir():
with pytest.raises(AssertionError):
func()
touch('file')
assert func()[0].strip() == 'hello'
os.remove('file')
assert func(cmdonly=True) == ['echo', 'hello']
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment