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

Merge branch 'mnt/run-silent' into 'main'

MNT: New 'silent' option to run function

See merge request fsl/fslpy!428
parents a5260424 b04a7ee8
No related branches found
No related tags found
No related merge requests found
...@@ -2,6 +2,17 @@ This document contains the ``fslpy`` release history in reverse chronological ...@@ -2,6 +2,17 @@ This document contains the ``fslpy`` release history in reverse chronological
order. order.
3.16.0 (Under development)
--------------------------
Added
^^^^^
* New `silent` option to the :func:`.run` function = passing ``silent=True`` is
equivalent to passing ``log={'tee':False}`` (!428).
3.15.3 (Thursday 16th November 2023) 3.15.3 (Thursday 16th November 2023)
------------------------------------ ------------------------------------
......
...@@ -20,7 +20,6 @@ import pytest ...@@ -20,7 +20,6 @@ import pytest
import fsl.utils.tempdir as tempdir import fsl.utils.tempdir as tempdir
from fsl.utils.platform import platform as fslplatform from fsl.utils.platform import platform as fslplatform
import fsl.utils.run as run import fsl.utils.run as run
import fsl.utils.fslsub as fslsub
from . import make_random_image, mockFSLDIR, CaptureStdout, touch from . import make_random_image, mockFSLDIR, CaptureStdout, touch
...@@ -138,6 +137,13 @@ def test_run_tee(): ...@@ -138,6 +137,13 @@ def test_run_tee():
assert stdout == expstdout assert stdout == expstdout
assert capture.stdout == '' assert capture.stdout == ''
# disable forwarding via silent=True
with capture.reset():
stdout = run.run('./script.sh 1 2 3', silent=True)
assert stdout == expstdout
assert capture.stdout == ''
with capture.reset(): with capture.reset():
stdout, stderr = run.run('./script.sh 1 2 3', stderr=True, stdout, stderr = run.run('./script.sh 1 2 3', stderr=True,
log={'tee' : True}) log={'tee' : True})
...@@ -289,6 +295,8 @@ def mock_fsl_sub(*cmd, **kwargs): ...@@ -289,6 +295,8 @@ def mock_fsl_sub(*cmd, **kwargs):
name = op.basename(name) name = op.basename(name)
kwargs.pop('log', None)
jid = '12345' jid = '12345'
output = run.run(cmd) output = run.run(cmd)
...@@ -323,7 +331,7 @@ def test_run_submit(): ...@@ -323,7 +331,7 @@ def test_run_submit():
jid = run.run('fsltest', submit=True) jid = run.run('fsltest', submit=True)
assert jid == '12345' assert jid == '12345'
stdout, stderr = fslsub.output(jid) stdout, stderr = run.job_output(jid)
assert stdout == 'test_script running\n' assert stdout == 'test_script running\n'
assert stderr == '' assert stderr == ''
...@@ -331,7 +339,7 @@ def test_run_submit(): ...@@ -331,7 +339,7 @@ def test_run_submit():
kwargs = {'name' : 'abcde', 'ram' : '4GB'} kwargs = {'name' : 'abcde', 'ram' : '4GB'}
jid = run.run('fsltest', submit=kwargs) jid = run.run('fsltest', submit=kwargs)
assert jid == '12345' assert jid == '12345'
stdout, stderr = fslsub.output(jid) stdout, stderr = run.job_output(jid)
experr = '\n'.join(['{}: {}'.format(k, kwargs[k]) experr = '\n'.join(['{}: {}'.format(k, kwargs[k])
for k in sorted(kwargs.keys())]) + '\n' for k in sorted(kwargs.keys())]) + '\n'
assert stdout == 'test_script running\n' assert stdout == 'test_script running\n'
...@@ -341,7 +349,7 @@ def test_run_submit(): ...@@ -341,7 +349,7 @@ def test_run_submit():
kwargs = {'name' : 'abcde', 'ram' : '4GB'} kwargs = {'name' : 'abcde', 'ram' : '4GB'}
jid = run.run('fsltest', submit=True, **kwargs) jid = run.run('fsltest', submit=True, **kwargs)
assert jid == '12345' assert jid == '12345'
stdout, stderr = fslsub.output(jid) stdout, stderr = run.job_output(jid)
experr = '\n'.join(['{}: {}'.format(k, kwargs[k]) experr = '\n'.join(['{}: {}'.format(k, kwargs[k])
for k in sorted(kwargs.keys())]) + '\n' for k in sorted(kwargs.keys())]) + '\n'
assert stdout == 'test_script running\n' assert stdout == 'test_script running\n'
...@@ -482,7 +490,7 @@ def test_func_to_cmd(): ...@@ -482,7 +490,7 @@ def test_func_to_cmd():
for tmp_dir in (None, '.'): for tmp_dir in (None, '.'):
for clean in ('never', 'on_success', 'always'): for clean in ('never', 'on_success', 'always'):
for verbose in (False, True): for verbose in (False, True):
cmd = fslsub.func_to_cmd(_good_func, clean=clean, tmp_dir=tmp_dir, verbose=verbose) cmd = run.func_to_cmd(_good_func, clean=clean, tmp_dir=tmp_dir, verbose=verbose)
fn = cmd.split()[-1] fn = cmd.split()[-1]
assert op.exists(fn) assert op.exists(fn)
stdout, stderr, exitcode = run.run(cmd, exitcode=True, stdout=True, stderr=True, stdout, stderr, exitcode = run.run(cmd, exitcode=True, stdout=True, stderr=True,
...@@ -497,7 +505,7 @@ def test_func_to_cmd(): ...@@ -497,7 +505,7 @@ def test_func_to_cmd():
else: else:
assert stdout.strip() == 'hello' assert stdout.strip() == 'hello'
cmd = fslsub.func_to_cmd(_bad_func, clean=clean, tmp_dir=tmp_dir) cmd = run.func_to_cmd(_bad_func, clean=clean, tmp_dir=tmp_dir)
fn = cmd.split()[-1] fn = cmd.split()[-1]
assert op.exists(fn) assert op.exists(fn)
stdout, stderr, exitcode = run.run(cmd, exitcode=True, stdout=True, stderr=True, stdout, stderr, exitcode = run.run(cmd, exitcode=True, stdout=True, stderr=True,
......
...@@ -188,6 +188,9 @@ def run(*args, **kwargs): ...@@ -188,6 +188,9 @@ def run(*args, **kwargs):
- cmd: Optional file-like or callable to which - cmd: Optional file-like or callable to which
the command itself is logged. the command itself is logged.
:arg silent: Suppress standard output/error. Equivalent to passing
``log={'tee' : False}``. Ignored if `log` is also passed.
All other keyword arguments are passed through to the ``subprocess.Popen`` All other keyword arguments are passed through to the ``subprocess.Popen``
object (via :func:`_realrun`), unless ``submit=True``, in which case they object (via :func:`_realrun`), unless ``submit=True``, in which case they
are passed through to the :func:`.fsl_sub` function. are passed through to the :func:`.fsl_sub` function.
...@@ -204,10 +207,11 @@ def run(*args, **kwargs): ...@@ -204,10 +207,11 @@ def run(*args, **kwargs):
submit = kwargs.pop('submit', {}) submit = kwargs.pop('submit', {})
cmdonly = kwargs.pop('cmdonly', False) cmdonly = kwargs.pop('cmdonly', False)
logg = kwargs.pop('log', None) logg = kwargs.pop('log', None)
silent = kwargs.pop('silent', False)
args = prepareArgs(args) args = prepareArgs(args)
if logg is None: if logg is None:
logg = {} logg = {'tee' : not silent}
tee = logg.get('tee', True) tee = logg.get('tee', True)
logStdout = logg.get('stdout', None) logStdout = logg.get('stdout', None)
...@@ -237,7 +241,7 @@ def run(*args, **kwargs): ...@@ -237,7 +241,7 @@ def run(*args, **kwargs):
# but harmless, as we've popped the "submit" arg above. # but harmless, as we've popped the "submit" arg above.
if submit is not None: if submit is not None:
from fsl.wrappers import fsl_sub # pylint: disable=import-outside-toplevel # noqa: E501 from fsl.wrappers import fsl_sub # pylint: disable=import-outside-toplevel # noqa: E501
return fsl_sub(*args, **submit, **kwargs)[0].strip() return fsl_sub(*args, log=logg, **submit, **kwargs)[0].strip()
# Run directly - delegate to _realrun # Run directly - delegate to _realrun
stdout, stderr, exitcode = _realrun( stdout, stderr, exitcode = _realrun(
...@@ -633,10 +637,10 @@ def hold(job_ids, hold_filename=None, timeout=10): ...@@ -633,10 +637,10 @@ def hold(job_ids, hold_filename=None, timeout=10):
submit = { submit = {
'jobhold' : _flatten_job_ids(job_ids), 'jobhold' : _flatten_job_ids(job_ids),
'jobtime' : 1, 'jobtime' : 1,
'name' : '.hold' 'name' : '.hold',
} }
run(f'touch {hold_filename}', submit=submit) run(f'touch {hold_filename}', submit=submit, silent=True)
while not op.exists(hold_filename): while not op.exists(hold_filename):
time.sleep(timeout) time.sleep(timeout)
......
...@@ -193,7 +193,16 @@ def genxwrapper(func, runner, funccmd=False): ...@@ -193,7 +193,16 @@ def genxwrapper(func, runner, funccmd=False):
exitcode = kwargs.pop('exitcode', opts['exitcode']) exitcode = kwargs.pop('exitcode', opts['exitcode'])
submit = kwargs.pop('submit', opts['submit']) submit = kwargs.pop('submit', opts['submit'])
cmdonly = kwargs.pop('cmdonly', opts['cmdonly']) cmdonly = kwargs.pop('cmdonly', opts['cmdonly'])
logg = kwargs.pop('log', opts['log']) silent = kwargs.pop('silent', False)
# If silent=True, we need to explicitly set
# log, as the run function will otherwise
# ignore silent and preferentially use the
# value we pass for log.
if silent:
logg = kwargs.pop('log', {'tee' : False})
else:
logg = kwargs.pop('log', opts['log'])
if funccmd: if funccmd:
cmd = run.func_to_cmd(func, args=args, kwargs=kwargs, cmd = run.func_to_cmd(func, args=args, kwargs=kwargs,
......
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