Skip to content

Commit 67491af

Browse files
committed
Merge remote-tracking branch 'upstream/master' into ref/interface-base
2 parents 92a8ce5 + 3cb99d8 commit 67491af

File tree

17 files changed

+220
-96
lines changed

17 files changed

+220
-96
lines changed

CHANGES

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

4-
0.14.0 (November 21, 2017)
4+
5+
0.14.0 (November 29, 2017)
56
==========================
67

78
###### [Full changelog](https://github.com/nipy/nipype/milestone/13)
89

10+
* FIX+MAINT: Revision of the resource monitor (https://github.com/nipy/nipype/pull/2285)
11+
* FIX: MultiProc mishandling crashes (https://github.com/nipy/nipype/pull/2301)
12+
* MAINT: Revise use of `subprocess.Popen` (https://github.com/nipy/nipype/pull/2289)
13+
* ENH: Memorize version checks (https://github.com/nipy/nipype/pull/2274, https://github.com/nipy/nipype/pull/2295)
14+
15+
16+
0.14.0rc1 (November 21, 2017)
17+
-----------------------------
18+
919
* ENH: Generate Dockerfiles with neurodocker (https://github.com/nipy/nipype/pull/2202)
1020
* ENH: FLAIR options for recon-all (https://github.com/nipy/nipype/pull/2279)
1121
* ENH: Config option for setting maxtasksperchild when multiprocessing (https://github.com/nipy/nipype/pull/2284)

doc/users/config_file.rst

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,29 @@ Execution
153153
crashfiles allow portability across machines and shorter load time.
154154
(possible values: ``pklz`` and ``txt``; default value: ``pklz``)
155155

156-
*resource_monitor*
156+
157+
Resource Monitor
158+
~~~~~~~~~~~~~~~~
159+
160+
*enabled*
157161
Enables monitoring the resources occupation (possible values: ``true`` and
158-
``false``; default value: ``false``)
162+
``false``; default value: ``false``). All the following options will be
163+
dismissed if the resource monitor is not enabled.
159164

160-
*resource_monitor_frequency*
165+
*sample_frequency*
161166
Sampling period (in seconds) between measurements of resources (memory, cpus)
162-
being used by an interface. Requires ``resource_monitor`` to be ``true``.
163-
(default value: ``1``)
167+
being used by an interface (default value: ``1``)
168+
169+
*summary_file*
170+
Indicates where the summary file collecting all profiling information from the
171+
resource monitor should be stored after execution of a workflow.
172+
The ``summary_file`` does not apply to interfaces run independently.
173+
(unset by default, in which case the summary file will be written out to
174+
``<base_dir>/resource_monitor.json`` of the top-level workflow).
175+
176+
*summary_append*
177+
Append to an existing summary file (only applies to workflows).
178+
(default value: ``true``, possible values: ``true`` or ``false``).
164179

165180
Example
166181
~~~~~~~
@@ -175,6 +190,10 @@ Example
175190
hash_method = timestamp
176191
display_variable = :1
177192

193+
[monitoring]
194+
enabled = false
195+
196+
178197
Workflow.config property has a form of a nested dictionary reflecting the
179198
structure of the .cfg file.
180199

docker/files/run_examples.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ echo '[execution]' >> ${HOME}/.nipype/nipype.cfg
2020
echo 'crashfile_format = txt' >> ${HOME}/.nipype/nipype.cfg
2121

2222
if [[ "${NIPYPE_RESOURCE_MONITOR:-0}" == "1" ]]; then
23-
echo 'resource_monitor = true' >> ${HOME}/.nipype/nipype.cfg
24-
echo 'resource_monitor_frequency = 3' >> ${HOME}/.nipype/nipype.cfg
23+
echo '[monitoring]' >> ${HOME}/.nipype/nipype.cfg
24+
echo 'enabled = true' >> ${HOME}/.nipype/nipype.cfg
25+
echo 'sample_frequency = 3' >> ${HOME}/.nipype/nipype.cfg
2526
fi
2627

2728
# Set up coverage

nipype/algorithms/confounds.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from numpy.polynomial import Legendre
2323
from scipy import linalg
2424

25-
from .. import logging
25+
from .. import config, logging
2626
from ..external.due import BibTeX
2727
from ..interfaces.base import (traits, TraitedSpec, BaseInterface,
2828
BaseInterfaceInputSpec, File, isdefined,
@@ -816,7 +816,7 @@ def plot_confound(tseries, figsize, name, units=None,
816816
817817
"""
818818
import matplotlib
819-
matplotlib.use('Agg')
819+
matplotlib.use(config.get('execution', 'matplotlib_backend'))
820820
import matplotlib.pyplot as plt
821821
from matplotlib.gridspec import GridSpec
822822
from matplotlib.backends.backend_pdf import FigureCanvasPdf as FigureCanvas

nipype/algorithms/metrics.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from scipy.spatial.distance import cdist, euclidean, dice, jaccard
2525
from scipy.ndimage.measurements import center_of_mass, label
2626

27-
from .. import logging
27+
from .. import config, logging
2828
from ..utils.misc import package_check
2929

3030
from ..interfaces.base import (BaseInterface, traits, TraitedSpec, File,
@@ -138,6 +138,8 @@ def _eucl_mean(self, nii1, nii2, weighted=False):
138138

139139
dist_matrix = cdist(set1_coordinates.T, set2_coordinates.T)
140140
min_dist_matrix = np.amin(dist_matrix, axis=0)
141+
import matplotlib
142+
matplotlib.use(config.get('execution', 'matplotlib_backend'))
141143
import matplotlib.pyplot as plt
142144
plt.figure()
143145
plt.hist(min_dist_matrix, 50, normed=1, facecolor='green')

nipype/interfaces/afni/tests/test_auto_Unifize.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ def test_Unifize_inputs():
3232
name_source='in_file',
3333
),
3434
outputtype=dict(),
35+
rbt=dict(argstr='-rbt %f %f %f',
36+
),
3537
scale_file=dict(argstr='-ssave %s',
3638
),
3739
t2=dict(argstr='-T2',

nipype/interfaces/afni/utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2329,6 +2329,14 @@ class UnifizeInputSpec(AFNICommandInputSpec):
23292329
argstr='-EPI',
23302330
requires=['no_duplo', 't2'],
23312331
xor=['gm'])
2332+
rbt = traits.Tuple(
2333+
traits.Float(), traits.Float(), traits.Float(),
2334+
desc='Option for AFNI experts only.'
2335+
'Specify the 3 parameters for the algorithm:\n'
2336+
'R = radius; same as given by option \'-Urad\', [default=18.3]\n'
2337+
'b = bottom percentile of normalizing data range, [default=70.0]\n'
2338+
'r = top percentile of normalizing data range, [default=80.0]\n',
2339+
argstr='-rbt %f %f %f')
23322340

23332341

23342342
class UnifizeOutputSpec(TraitedSpec):

nipype/interfaces/ants/registration.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
# -*- coding: utf-8 -*-
2-
"""The ants module provides basic functions for interfacing with ants functions.
2+
"""The ants module provides basic functions for interfacing with ants
3+
functions.
34
45
Change directory to provide relative paths for doctests
56
>>> import os
67
>>> filepath = os.path.dirname( os.path.realpath( __file__ ) )
78
>>> datadir = os.path.realpath(os.path.join(filepath, '../../testing/data'))
89
>>> os.chdir(datadir)
910
"""
10-
from __future__ import print_function, division, unicode_literals, absolute_import
11+
from __future__ import (print_function, division, unicode_literals,
12+
absolute_import)
1113
from builtins import range, str
1214
import os
1315

@@ -20,17 +22,19 @@ class ANTSInputSpec(ANTSCommandInputSpec):
2022
dimension = traits.Enum(3, 2, argstr='%d', usedefault=False,
2123
position=1, desc='image dimension (2 or 3)')
2224
fixed_image = InputMultiPath(File(exists=True), mandatory=True,
23-
desc=('image to which the moving image is warped'))
25+
desc=('image to which the moving image is '
26+
'warped'))
2427
moving_image = InputMultiPath(File(exists=True), argstr='%s',
2528
mandatory=True,
26-
desc=('image to apply transformation to (generally a coregistered '
29+
desc=('image to apply transformation to '
30+
'(generally a coregistered'
2731
'functional)'))
2832

2933
# Not all metrics are appropriate for all modalities. Also, not all metrics
30-
# are efficeint or appropriate at all resolution levels, Some metrics perform
31-
# well for gross global registraiton, but do poorly for small changes (i.e.
32-
# Mattes), and some metrics do well for small changes but don't work well for
33-
# gross level changes (i.e. 'CC').
34+
# are efficeint or appropriate at all resolution levels, Some metrics
35+
# perform well for gross global registraiton, but do poorly for small
36+
# changes (i.e. Mattes), and some metrics do well for small changes but
37+
# don't work well for gross level changes (i.e. 'CC').
3438
#
3539
# This is a two stage registration. in the first stage
3640
# [ 'Mattes', .................]
@@ -49,10 +53,18 @@ class ANTSInputSpec(ANTSCommandInputSpec):
4953
metric = traits.List(traits.Enum('CC', 'MI', 'SMI', 'PR', 'SSD',
5054
'MSQ', 'PSE'), mandatory=True, desc='')
5155

52-
metric_weight = traits.List(traits.Float(), requires=['metric'], desc='')
53-
radius = traits.List(traits.Int(), requires=['metric'], desc='')
56+
metric_weight = traits.List(traits.Float(), value=[1.0], usedefault=True,
57+
requires=['metric'], mandatory=True,
58+
desc='the metric weight(s) for each stage. '
59+
'The weights must sum to 1 per stage.')
5460

55-
output_transform_prefix = Str('out', usedefault=True, argstr='--output-naming %s',
61+
radius = traits.List(traits.Int(), requires=['metric'], mandatory=True,
62+
desc='radius of the region (i.e. number of layers'
63+
' around a voxel point)'
64+
' that is used for computing cross correlation')
65+
66+
output_transform_prefix = Str('out', usedefault=True,
67+
argstr='--output-naming %s',
5668
mandatory=True, desc='')
5769
transformation_model = traits.Enum('Diff', 'Elast', 'Exp', 'Greedy Exp',
5870
'SyN', argstr='%s', mandatory=True,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
from __future__ import unicode_literals
4+
from nipype.interfaces.ants import registration
5+
import os
6+
import pytest
7+
8+
9+
def test_ants_mand(tmpdir):
10+
tmpdir.chdir()
11+
filepath = os.path.dirname(os.path.realpath(__file__))
12+
datadir = os.path.realpath(os.path.join(filepath, '../../../testing/data'))
13+
14+
ants = registration.ANTS()
15+
ants.inputs.transformation_model = "SyN"
16+
ants.inputs.moving_image = [os.path.join(datadir, 'resting.nii')]
17+
ants.inputs.fixed_image = [os.path.join(datadir, 'T1.nii')]
18+
ants.inputs.metric = ['MI']
19+
20+
with pytest.raises(ValueError) as er:
21+
ants.run()
22+
assert "ANTS requires a value for input 'radius'" in str(er.value)

nipype/interfaces/base/core.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
1414
"""
1515
from __future__ import print_function, division, unicode_literals, absolute_import
16+
1617
from builtins import object, open, str, bytes
1718

19+
import gc
1820
from copy import deepcopy
1921
from datetime import datetime as dt
2022
import errno
@@ -28,7 +30,6 @@
2830
import simplejson as json
2931
from dateutil.parser import parse as parseutc
3032

31-
3233
from ... import config, logging, LooseVersion
3334
from ...utils.provenance import write_provenance
3435
from ...utils.misc import trim, str2bool
@@ -657,6 +658,7 @@ class SimpleInterface(BaseInterface):
657658
>>> os.chdir(old.strpath)
658659
659660
"""
661+
660662
def __init__(self, from_file=None, resource_monitor=None, **inputs):
661663
super(SimpleInterface, self).__init__(
662664
from_file=from_file, resource_monitor=resource_monitor, **inputs)
@@ -705,6 +707,7 @@ def run_command(runtime, output=None, timeout=0.01):
705707
env=env,
706708
close_fds=True,
707709
)
710+
708711
result = {
709712
'stdout': [],
710713
'stderr': [],
@@ -743,37 +746,50 @@ def _process(drain=0):
743746
temp.sort()
744747
result['merged'] = [r[1] for r in temp]
745748

746-
if output == 'allatonce':
747-
stdout, stderr = proc.communicate()
748-
result['stdout'] = read_stream(stdout, logger=iflogger)
749-
result['stderr'] = read_stream(stderr, logger=iflogger)
750-
751-
elif output.startswith('file'):
749+
if output.startswith('file'):
752750
proc.wait()
753751
if outfile is not None:
754752
stdout.flush()
755753
stdout.close()
756754
with open(outfile, 'rb') as ofh:
757755
stdoutstr = ofh.read()
758756
result['stdout'] = read_stream(stdoutstr, logger=iflogger)
757+
del stdoutstr
759758

760759
if errfile is not None:
761760
stderr.flush()
762761
stderr.close()
763762
with open(errfile, 'rb') as efh:
764763
stderrstr = efh.read()
765764
result['stderr'] = read_stream(stderrstr, logger=iflogger)
765+
del stderrstr
766766

767767
if output == 'file':
768768
result['merged'] = result['stdout']
769769
result['stdout'] = []
770770
else:
771-
proc.communicate() # Discard stdout and stderr
771+
stdout, stderr = proc.communicate()
772+
if output == 'allatonce': # Discard stdout and stderr otherwise
773+
result['stdout'] = read_stream(stdout, logger=iflogger)
774+
result['stderr'] = read_stream(stderr, logger=iflogger)
775+
776+
runtime.returncode = proc.returncode
777+
try:
778+
proc.terminate() # Ensure we are done
779+
except OSError as error:
780+
# Python 2 raises when the process is already gone
781+
if error.errno != errno.ESRCH:
782+
raise
783+
784+
# Dereference & force GC for a cleanup
785+
del proc
786+
del stdout
787+
del stderr
788+
gc.collect()
772789

773790
runtime.stderr = '\n'.join(result['stderr'])
774791
runtime.stdout = '\n'.join(result['stdout'])
775792
runtime.merged = '\n'.join(result['merged'])
776-
runtime.returncode = proc.returncode
777793
return runtime
778794

779795

@@ -847,6 +863,9 @@ def __init__(self, command=None, terminal_output=None, **inputs):
847863
# Set command. Input argument takes precedence
848864
self._cmd = command or getattr(self, '_cmd', None)
849865

866+
# Store dependencies in runtime object
867+
self._ldd = str2bool(config.get('execution', 'get_linked_libs', 'true'))
868+
850869
if self._cmd is None:
851870
raise Exception("Missing command")
852871

@@ -895,8 +914,11 @@ def _get_environ(self):
895914
return getattr(self.inputs, 'environ', {})
896915

897916
def version_from_command(self, flag='-v', cmd=None):
917+
iflogger.warning('version_from_command member of CommandLine was '
918+
'Deprecated in nipype-1.0.0 and deleted in 1.1.0')
898919
if cmd is None:
899920
cmd = self.cmd.split()[0]
921+
900922
env = dict(os.environ)
901923
if which(cmd, env=env):
902924
out_environ = self._get_environ()
@@ -942,7 +964,8 @@ def _run_interface(self, runtime, correct_return_codes=(0,)):
942964
executable_name, runtime.hostname))
943965

944966
runtime.command_path = cmd_path
945-
runtime.dependencies = get_dependencies(executable_name, runtime.environ)
967+
runtime.dependencies = (get_dependencies(executable_name, runtime.environ)
968+
if self._ldd else '<skipped>')
946969
runtime = run_command(runtime, output=self.terminal_output)
947970
if runtime.returncode is None or \
948971
runtime.returncode not in correct_return_codes:

0 commit comments

Comments
 (0)