Skip to content
Snippets Groups Projects
Commit 111c77a0 authored by Paul McCarthy's avatar Paul McCarthy :mountain_bicyclist:
Browse files

Merge branch 'enh/wrapper_cmdonly' into 'master'

Enh/wrapper cmdonly

See merge request fsl/fslpy!257
parents cb3fd7f2 4c777562
No related branches found
No related tags found
No related merge requests found
This document contains the ``fslpy`` release history in reverse chronological This document contains the ``fslpy`` release history in reverse chronological
order. order.
3.3.2 (Tuesday 12th October 2020)
---------------------------------
Changed
^^^^^^^
* Most :func:`.wrapper` functions now accept an argument called ``cmdonly``
which, if ``True``, will cause the generated command-line call to be
returned, instead of executed.
3.3.1 (Thursday 8th October 2020) 3.3.1 (Thursday 8th October 2020)
--------------------------------- ---------------------------------
......
...@@ -151,6 +151,10 @@ def run(*args, **kwargs): ...@@ -151,6 +151,10 @@ def run(*args, **kwargs):
the :func:`.fslsub.submit` function. May also be a the :func:`.fslsub.submit` function. May also be a
dictionary containing arguments to that function. dictionary containing arguments to that function.
:arg cmdonly: Defaults to ``False``. If ``True``, the command is not
executed, but rather is returned directly, as a list of
arguments.
:arg log: Must be passed as a keyword argument. An optional ``dict`` :arg log: Must be passed as a keyword argument. An optional ``dict``
which may be used to redirect the command's standard output which may be used to redirect the command's standard output
and error. The following keys are recognised: and error. The following keys are recognised:
...@@ -181,6 +185,7 @@ def run(*args, **kwargs): ...@@ -181,6 +185,7 @@ def run(*args, **kwargs):
returnStderr = kwargs.pop('stderr', False) returnStderr = kwargs.pop('stderr', False)
returnExitcode = kwargs.pop('exitcode', False) returnExitcode = kwargs.pop('exitcode', False)
submit = kwargs.pop('submit', {}) submit = kwargs.pop('submit', {})
cmdonly = kwargs.pop('cmdonly', False)
log = kwargs.pop('log', None) log = kwargs.pop('log', None)
args = prepareArgs(args) args = prepareArgs(args)
...@@ -207,6 +212,9 @@ def run(*args, **kwargs): ...@@ -207,6 +212,9 @@ def run(*args, **kwargs):
raise ValueError('submit must be a mapping containing ' raise ValueError('submit must be a mapping containing '
'options for fsl.utils.fslsub.submit') 'options for fsl.utils.fslsub.submit')
if cmdonly:
return args
if DRY_RUN: if DRY_RUN:
return _dryrun( return _dryrun(
submit, returnStdout, returnStderr, returnExitcode, *args) submit, returnStdout, returnStderr, returnExitcode, *args)
......
...@@ -149,46 +149,73 @@ def _unwrap(func): ...@@ -149,46 +149,73 @@ def _unwrap(func):
return func return func
def cmdwrapper(func): def genxwrapper(func, runner):
"""This decorator can be used on functions which generate a command line. """This function is used by :func:`cmdwrapper` and :func:`fslwrapper`.
It will pass the return value of the function to the It is not intended to be used in any other circumstances.
:func:`fsl.utils.run.run` function in a standardised manner.
This function generates a wrapper function which calls ``func`` to
generate a command-line call, and then uses ``runner`` to invoke that
command.
``func`` is assumed to be a wrapper function which generates a command-
line. ``runner`` is assumed to be Either :func:`.run.run` or
:func:`.run.runfsl`.
The generated wrapper function will pass all of its arguments to ``func``,
and will then pass the generated command-line to ``runner``, returning
whatever is returned.
The following keyword arguments will be intercepted by the wrapper
function, and will *not* be passed to ``func``:
- ``stdout``: Passed to ``runner``. Defaults to ``True``.
- ``stderr``: Passed to ``runner``. Defaults to ``True``.
- ``exitcode``: Passed to ``runner``. Defaults to ``False``.
- ``submit``: Passed to ``runner``. Defaults to ``None``.
- ``log``: Passed to ``runner``. Defaults to ``{'tee':True}``.
- ``cmdonly``: Passed to ``runner``. Defaults to ``False``.
:arg func: A function which generates a command line.
:arg runner: Either :func:`.run.run` or :func:`.run.runfsl`.
""" """
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
stdout = kwargs.pop('stdout', True) stdout = kwargs.pop('stdout', True)
stderr = kwargs.pop('stderr', True) stderr = kwargs.pop('stderr', True)
exitcode = kwargs.pop('exitcode', False) exitcode = kwargs.pop('exitcode', False)
submit = kwargs.pop('submit', None) submit = kwargs.pop('submit', None)
cmdonly = kwargs.pop('cmdonly', False)
log = kwargs.pop('log', {'tee' : True}) log = kwargs.pop('log', {'tee' : True})
cmd = func(*args, **kwargs) cmd = func(*args, **kwargs)
return run.run(cmd,
stderr=stderr, return runner(cmd,
log=log, stderr=stderr,
submit=submit, log=log,
stdout=stdout, submit=submit,
exitcode=exitcode) cmdonly=cmdonly,
stdout=stdout,
exitcode=exitcode)
return _update_wrapper(wrapper, func) return _update_wrapper(wrapper, func)
def cmdwrapper(func):
"""This decorator can be used on functions which generate a command line.
It will pass the return value of the function to the
:func:`fsl.utils.run.run` function in a standardised manner.
See the :func:`genxwrapper` function for details.
"""
return genxwrapper(func, run.run)
def fslwrapper(func): def fslwrapper(func):
"""This decorator can be used on functions which generate a FSL command """This decorator can be used on functions which generate a FSL command
line. It will pass the return value of the function to the line. It will pass the return value of the function to the
:func:`fsl.utils.run.runfsl` function in a standardised manner. :func:`fsl.utils.run.runfsl` function in a standardised manner.
See the :func:`genxwrapper` function for details.
""" """
def wrapper(*args, **kwargs): return genxwrapper(func, run.runfsl)
stdout = kwargs.pop('stdout', True)
stderr = kwargs.pop('stderr', True)
exitcode = kwargs.pop('exitcode', False)
submit = kwargs.pop('submit', None)
log = kwargs.pop('log', {'tee' : True})
cmd = func(*args, **kwargs)
return run.runfsl(cmd,
stderr=stderr,
log=log,
submit=submit,
stdout=stdout,
exitcode=exitcode)
return _update_wrapper(wrapper, func)
SHOW_IF_TRUE = object() SHOW_IF_TRUE = object()
......
...@@ -179,6 +179,13 @@ def test_run_passthrough(): ...@@ -179,6 +179,13 @@ def test_run_passthrough():
assert run.run('./script.sh', env=env) == expstdout assert run.run('./script.sh', env=env) == expstdout
def test_cmdonly():
assert run.run('script.sh', cmdonly=True) == ['script.sh']
assert run.run('script.sh 1 2 3', cmdonly=True) == ['script.sh', '1', '2', '3']
assert run.run(['script.sh'], cmdonly=True) == ['script.sh']
assert run.run(['script.sh', '1'], cmdonly=True) == ['script.sh', '1']
def test_dryrun(): def test_dryrun():
test_script = textwrap.dedent(""" test_script = textwrap.dedent("""
......
...@@ -753,15 +753,20 @@ def test_cmdwrapper(): ...@@ -753,15 +753,20 @@ def test_cmdwrapper():
with run.dryrun(): with run.dryrun():
assert func(1, 2)[0] == 'func 1 2' assert func(1, 2)[0] == 'func 1 2'
assert func(1, 2, cmdonly=True) == ['func', '1', '2']
def test_fslwrapper(): def test_fslwrapper():
@wutils.fslwrapper @wutils.fslwrapper
def func(a, b): def func(a, b):
return ['func', str(a), str(b)] return ['func', str(a), str(b)]
with run.dryrun(), mockFSLDIR(bin=('func',)) as fsldir: with mockFSLDIR(bin=('func',)) as fsldir:
expected = '{} 1 2'.format(op.join(fsldir, 'bin', 'func')) expected = '{} 1 2'.format(op.join(fsldir, 'bin', 'func'))
assert func(1, 2)[0] == expected with run.dryrun():
assert func(1, 2)[0] == expected
func(1, 2, cmdonly=True)[0] == list(shlex.split(expected))
_test_script = textwrap.dedent(""" _test_script = textwrap.dedent("""
......
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