Skip to content

Commit 2b10ff2

Browse files
authored
Merge pull request #2209 from oesteban/fix/1407
Sort out terminal_output
2 parents 6cda3ef + a66678c commit 2b10ff2

File tree

653 files changed

+1680
-825
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

653 files changed

+1680
-825
lines changed

CHANGES

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
Upcoming release
22
================
33

4+
* ENH: Improve terminal_output feature (https://github.com/nipy/nipype/pull/2209)
5+
* ENH: Simple interface to FSL std2imgcoords (https://github.com/nipy/nipype/pull/2209, prev #1398)
46
* ENH: Centralize virtual/physical $DISPLAYs (https://github.com/nipy/nipype/pull/#2203)
57
* ENH: New ResourceMonitor - replaces resource profiler (https://github.com/nipy/nipype/pull/#2200)
68

7-
89
0.13.1 (May 20, 2017)
910
=====================
1011

doc/devel/interface_specs.rst

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,70 @@ generated depending on inputs, by the tool. OutputSpecs inherit from
159159
``interfaces.base.TraitedSpec`` directly.
160160

161161

162+
Controlling outputs to terminal
163+
-------------------------------
164+
165+
It is very likely that the software wrapped within the interface writes
166+
to the standard output or the standard error of the terminal.
167+
Interfaces provide a means to access and retrieve these outputs, by
168+
using the ``terminal_output`` attribute: ::
169+
170+
import nipype.interfaces.fsl as fsl
171+
mybet = fsl.BET(from_file='bet-settings.json')
172+
mybet.terminal_output = 'file_split'
173+
174+
In the example, the ``terminal_output = 'file_split'`` will redirect the
175+
standard output and the standard error to split files (called
176+
``stdout.nipype`` and ``stderr.nipype`` respectively).
177+
The possible values for ``terminal_output`` are:
178+
179+
*file*
180+
Redirects both standard output and standard error to the same file
181+
called ``output.nipype``.
182+
Messages from both streams will be overlapped as they arrive to
183+
the file.
184+
185+
*file_split*
186+
Redirects the output streams separately, to ``stdout.nipype``
187+
and ``stderr.nipype`` respectively, as described in the example.
188+
189+
*file_stdout*
190+
Only the standard output will be redirected to ``stdout.nipype``
191+
and the standard error will be discarded.
192+
193+
*file_stderr*
194+
Only the standard error will be redirected to ``stderr.nipype``
195+
and the standard output will be discarded.
196+
197+
*stream*
198+
Both output streams are redirected to the current logger printing
199+
their messages interleaved and immediately to the terminal.
200+
201+
*allatonce*
202+
Both output streams will be forwarded to a buffer and stored
203+
separately in the `runtime` object that the `run()` method returns.
204+
No files are written nor streams printed out to terminal.
205+
206+
*none*
207+
Both outputs are discarded
208+
209+
In all cases, except for the ``'none'`` setting of ``terminal_output``,
210+
the ``run()`` method will return a "runtime" object that will contain
211+
the streams in the corresponding properties (``runtime.stdout``
212+
for the standard output, ``runtime.stderr`` for the standard error, and
213+
``runtime.merged`` for both when streams are mixed, eg. when using the
214+
*file* option). ::
215+
216+
import nipype.interfaces.fsl as fsl
217+
mybet = fsl.BET(from_file='bet-settings.json')
218+
mybet.terminal_output = 'file_split'
219+
...
220+
result = mybet.run()
221+
result.runtime.stdout
222+
' ... captured standard output ...'
223+
224+
225+
162226
Traited Attributes
163227
------------------
164228

doc/users/interface_tutorial.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Specifying input settings
1010
The nipype interface modules provide a Python interface to external
1111
packages like FSL_ and SPM_. Within the module are a series of Python
1212
classes which wrap specific package functionality. For example, in
13-
the fsl module, the class :class:`nipype.interfaces.fsl.Bet` wraps the
13+
the fsl module, the class :class:`nipype.interfaces.fsl.BET` wraps the
1414
``bet`` command-line tool. Using the command-line tool, one would
1515
specify input settings using flags like ``-o``, ``-m``, ``-f <f>``, etc...
1616
However, in nipype, options are assigned to Python attributes and can

doc/users/saving_workflows.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,20 @@ This will create a file "outputtestsave.py" with the following content:
8282
bet2.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'}
8383
bet2.inputs.ignore_exception = False
8484
bet2.inputs.output_type = 'NIFTI_GZ'
85-
bet2.inputs.terminal_output = 'stream'
85+
bet2.terminal_output = 'stream'
8686
# Node: testsave.bet
8787
bet = Node(BET(), name="bet")
8888
bet.iterables = ('frac', [0.3, 0.4])
8989
bet.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'}
9090
bet.inputs.ignore_exception = False
9191
bet.inputs.output_type = 'NIFTI_GZ'
92-
bet.inputs.terminal_output = 'stream'
92+
bet.terminal_output = 'stream'
9393
# Node: testsave.maths
9494
maths = Node(ImageMaths(), name="maths")
9595
maths.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'}
9696
maths.inputs.ignore_exception = False
9797
maths.inputs.output_type = 'NIFTI_GZ'
98-
maths.inputs.terminal_output = 'stream'
98+
maths.terminal_output = 'stream'
9999
testsave.connect(bet2, ('mask_file', func), maths, "in_file2")
100100
testsave.connect(bet, "mask_file", maths, "in_file")
101101
testsave.connect(testfunc, "output", maths, "op_string")

examples/fmri_ants_openfmri.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def create_reg_workflow(name='registration'):
218218
warpmean.inputs.input_image_type = 0
219219
warpmean.inputs.interpolation = 'Linear'
220220
warpmean.inputs.invert_transform_flags = [False, False]
221-
warpmean.inputs.terminal_output = 'file'
221+
warpmean.terminal_output = 'file'
222222

223223
register.connect(inputnode, 'target_image_brain', warpmean, 'reference_image')
224224
register.connect(inputnode, 'mean_image', warpmean, 'input_image')
@@ -234,7 +234,7 @@ def create_reg_workflow(name='registration'):
234234
warpall.inputs.input_image_type = 0
235235
warpall.inputs.interpolation = 'Linear'
236236
warpall.inputs.invert_transform_flags = [False, False]
237-
warpall.inputs.terminal_output = 'file'
237+
warpall.terminal_output = 'file'
238238

239239
register.connect(inputnode, 'target_image_brain', warpall, 'reference_image')
240240
register.connect(inputnode, 'source_files', warpall, 'input_image')
@@ -428,7 +428,7 @@ def create_fs_reg_workflow(name='registration'):
428428
warpmean.inputs.input_image_type = 0
429429
warpmean.inputs.interpolation = 'Linear'
430430
warpmean.inputs.invert_transform_flags = [False, False]
431-
warpmean.inputs.terminal_output = 'file'
431+
warpmean.terminal_output = 'file'
432432
warpmean.inputs.args = '--float'
433433
# warpmean.inputs.num_threads = 4
434434
# warpmean.plugin_args = {'sbatch_args': '--mem=4G -c 4'}
@@ -443,7 +443,7 @@ def create_fs_reg_workflow(name='registration'):
443443
warpall.inputs.input_image_type = 0
444444
warpall.inputs.interpolation = 'Linear'
445445
warpall.inputs.invert_transform_flags = [False, False]
446-
warpall.inputs.terminal_output = 'file'
446+
warpall.terminal_output = 'file'
447447
warpall.inputs.args = '--float'
448448
warpall.inputs.num_threads = 2
449449
warpall.plugin_args = {'sbatch_args': '--mem=6G -c 2'}

examples/rsfmri_vol_surface_preprocessing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ def create_reg_workflow(name='registration'):
547547
warpmean.inputs.input_image_type = 3
548548
warpmean.inputs.interpolation = 'Linear'
549549
warpmean.inputs.invert_transform_flags = [False, False]
550-
warpmean.inputs.terminal_output = 'file'
550+
warpmean.terminal_output = 'file'
551551
warpmean.inputs.args = '--float'
552552
warpmean.inputs.num_threads = 4
553553

@@ -767,7 +767,7 @@ def merge_files(in1, in2):
767767
warpall.inputs.input_image_type = 3
768768
warpall.inputs.interpolation = 'Linear'
769769
warpall.inputs.invert_transform_flags = [False, False]
770-
warpall.inputs.terminal_output = 'file'
770+
warpall.terminal_output = 'file'
771771
warpall.inputs.reference_image = target_file
772772
warpall.inputs.args = '--float'
773773
warpall.inputs.num_threads = 1

examples/rsfmri_vol_surface_preprocessing_nipy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ def create_reg_workflow(name='registration'):
482482
warpmean.inputs.input_image_type = 3
483483
warpmean.inputs.interpolation = 'Linear'
484484
warpmean.inputs.invert_transform_flags = [False, False]
485-
warpmean.inputs.terminal_output = 'file'
485+
warpmean.terminal_output = 'file'
486486
warpmean.inputs.args = '--float'
487487
warpmean.inputs.num_threads = 4
488488
warpmean.plugin_args = {'sbatch_args': '-c%d' % 4}
@@ -704,7 +704,7 @@ def merge_files(in1, in2):
704704
warpall.inputs.input_image_type = 3
705705
warpall.inputs.interpolation = 'Linear'
706706
warpall.inputs.invert_transform_flags = [False, False]
707-
warpall.inputs.terminal_output = 'file'
707+
warpall.terminal_output = 'file'
708708
warpall.inputs.reference_image = target_file
709709
warpall.inputs.args = '--float'
710710
warpall.inputs.num_threads = 2

nipype/interfaces/afni/preprocess.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,13 +1676,13 @@ class OutlierCountInputSpec(CommandLineInputSpec):
16761676
False,
16771677
usedefault=True,
16781678
argstr='-autoclip',
1679-
xor=['in_file'],
1679+
xor=['mask'],
16801680
desc='clip off small voxels')
16811681
automask = traits.Bool(
16821682
False,
16831683
usedefault=True,
16841684
argstr='-automask',
1685-
xor=['in_file'],
1685+
xor=['mask'],
16861686
desc='clip off small voxels')
16871687
fraction = traits.Bool(
16881688
False,
@@ -1718,28 +1718,19 @@ class OutlierCountInputSpec(CommandLineInputSpec):
17181718
out_file = File(
17191719
name_template='%s_outliers',
17201720
name_source=['in_file'],
1721-
argstr='> %s',
17221721
keep_extension=False,
1723-
position=-1,
17241722
desc='capture standard output')
17251723

17261724

17271725
class OutlierCountOutputSpec(TraitedSpec):
1728-
out_outliers = File(
1729-
exists=True,
1730-
desc='output image file name')
1731-
out_file = File(
1732-
name_template='%s_tqual',
1733-
name_source=['in_file'],
1734-
argstr='> %s',
1735-
keep_extension=False,
1736-
position=-1,
1737-
desc='capture standard output')
1726+
out_outliers = File(exists=True,
1727+
desc='output image file name')
1728+
out_file = File(desc='capture standard output')
17381729

17391730

17401731
class OutlierCount(CommandLine):
1741-
"""Calculates number of 'outliers' a 3D+time dataset, at each
1742-
time point, and writes the results to stdout.
1732+
"""Calculates number of 'outliers' at each time point of a
1733+
a 3D+time dataset.
17431734
17441735
For complete details, see the `3dToutcount Documentation
17451736
<https://afni.nimh.nih.gov/pub/dist/doc/program_help/3dToutcount.html>`_
@@ -1751,28 +1742,42 @@ class OutlierCount(CommandLine):
17511742
>>> toutcount = afni.OutlierCount()
17521743
>>> toutcount.inputs.in_file = 'functional.nii'
17531744
>>> toutcount.cmdline # doctest: +ELLIPSIS +ALLOW_UNICODE
1754-
'3dToutcount functional.nii > functional_outliers'
1745+
'3dToutcount functional.nii'
17551746
>>> res = toutcount.run() # doctest: +SKIP
17561747
17571748
"""
17581749

17591750
_cmd = '3dToutcount'
17601751
input_spec = OutlierCountInputSpec
17611752
output_spec = OutlierCountOutputSpec
1753+
_terminal_output = 'file_split'
17621754

17631755
def _parse_inputs(self, skip=None):
17641756
if skip is None:
17651757
skip = []
17661758

1759+
# This is not strictly an input, but needs be
1760+
# set before run() is called.
1761+
if self.terminal_output == 'none':
1762+
self.terminal_output = 'file_split'
1763+
17671764
if not self.inputs.save_outliers:
17681765
skip += ['outliers_file']
17691766
return super(OutlierCount, self)._parse_inputs(skip)
17701767

1768+
def _run_interface(self, runtime):
1769+
runtime = super(OutlierCount, self)._run_interface(runtime)
1770+
1771+
# Read from runtime.stdout or runtime.merged
1772+
with open(op.abspath(self.inputs.out_file), 'w') as outfh:
1773+
outfh.write(runtime.stdout or runtime.merged)
1774+
return runtime
1775+
17711776
def _list_outputs(self):
17721777
outputs = self.output_spec().get()
1778+
outputs['out_file'] = op.abspath(self.inputs.out_file)
17731779
if self.inputs.save_outliers:
17741780
outputs['out_outliers'] = op.abspath(self.inputs.outliers_file)
1775-
outputs['out_file'] = op.abspath(self.inputs.out_file)
17761781
return outputs
17771782

17781783

@@ -1880,13 +1885,10 @@ class ROIStatsInputSpec(CommandLineInputSpec):
18801885
desc='execute quietly',
18811886
argstr='-quiet',
18821887
position=1)
1883-
terminal_output = traits.Enum(
1884-
'allatonce',
1888+
terminal_output = traits.Enum('allatonce', deprecated='1.0.0',
18851889
desc='Control terminal output:`allatonce` - waits till command is '
18861890
'finished to display output',
1887-
nohash=True,
1888-
mandatory=True,
1889-
usedefault=True)
1891+
nohash=True)
18901892

18911893

18921894
class ROIStatsOutputSpec(TraitedSpec):
@@ -1915,6 +1917,7 @@ class ROIStats(AFNICommandBase):
19151917
19161918
"""
19171919
_cmd = '3dROIstats'
1920+
_terminal_output = 'allatonce'
19181921
input_spec = ROIStatsInputSpec
19191922
output_spec = ROIStatsOutputSpec
19201923

nipype/interfaces/afni/tests/test_auto_ABoverlap.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ def test_ABoverlap_inputs():
3333
outputtype=dict(),
3434
quiet=dict(argstr='-quiet',
3535
),
36-
terminal_output=dict(nohash=True,
36+
terminal_output=dict(deprecated='1.0.0',
37+
nohash=True,
3738
),
3839
verb=dict(argstr='-verb',
3940
),

nipype/interfaces/afni/tests/test_auto_AFNICommand.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ def test_AFNICommand_inputs():
2020
name_template='%s_afni',
2121
),
2222
outputtype=dict(),
23-
terminal_output=dict(nohash=True,
23+
terminal_output=dict(deprecated='1.0.0',
24+
nohash=True,
2425
),
2526
)
2627
inputs = AFNICommand.input_spec()

nipype/interfaces/afni/tests/test_auto_AFNICommandBase.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ def test_AFNICommandBase_inputs():
1212
ignore_exception=dict(nohash=True,
1313
usedefault=True,
1414
),
15-
terminal_output=dict(nohash=True,
15+
terminal_output=dict(deprecated='1.0.0',
16+
nohash=True,
1617
),
1718
)
1819
inputs = AFNICommandBase.input_spec()

nipype/interfaces/afni/tests/test_auto_AFNIPythonCommand.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ def test_AFNIPythonCommand_inputs():
2020
name_template='%s_afni',
2121
),
2222
outputtype=dict(),
23-
terminal_output=dict(nohash=True,
23+
terminal_output=dict(deprecated='1.0.0',
24+
nohash=True,
2425
),
2526
)
2627
inputs = AFNIPythonCommand.input_spec()

nipype/interfaces/afni/tests/test_auto_AFNItoNIFTI.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ def test_AFNItoNIFTI_inputs():
3636
outputtype=dict(),
3737
pure=dict(argstr='-pure',
3838
),
39-
terminal_output=dict(nohash=True,
39+
terminal_output=dict(deprecated='1.0.0',
40+
nohash=True,
4041
),
4142
)
4243
inputs = AFNItoNIFTI.input_spec()

nipype/interfaces/afni/tests/test_auto_AlignEpiAnatPy.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ def test_AlignEpiAnatPy_inputs():
3737
suffix=dict(argstr='-suffix %s',
3838
usedefault=True,
3939
),
40-
terminal_output=dict(nohash=True,
40+
terminal_output=dict(deprecated='1.0.0',
41+
nohash=True,
4142
),
4243
tshift=dict(argstr='-tshift %s',
4344
usedefault=True,

nipype/interfaces/afni/tests/test_auto_Allineate.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ def test_Allineate_inputs():
104104
),
105105
source_mask=dict(argstr='-source_mask %s',
106106
),
107-
terminal_output=dict(nohash=True,
107+
terminal_output=dict(deprecated='1.0.0',
108+
nohash=True,
108109
),
109110
two_best=dict(argstr='-twobest %d',
110111
),

nipype/interfaces/afni/tests/test_auto_AutoTLRC.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ def test_AutoTLRC_inputs():
2222
no_ss=dict(argstr='-no_ss',
2323
),
2424
outputtype=dict(),
25-
terminal_output=dict(nohash=True,
25+
terminal_output=dict(deprecated='1.0.0',
26+
nohash=True,
2627
),
2728
)
2829
inputs = AutoTLRC.input_spec()

nipype/interfaces/afni/tests/test_auto_AutoTcorrelate.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ def test_AutoTcorrelate_inputs():
3737
outputtype=dict(),
3838
polort=dict(argstr='-polort %d',
3939
),
40-
terminal_output=dict(nohash=True,
40+
terminal_output=dict(deprecated='1.0.0',
41+
nohash=True,
4142
),
4243
)
4344
inputs = AutoTcorrelate.input_spec()

0 commit comments

Comments
 (0)