Skip to content

Commit bca9dfe

Browse files
committedNov 25, 2018
Merge remote-tracking branch 'upstream/master' into enh/antsCT
* upstream/master: fix import of specs [MAINT] Outsource ``get_filecopy_info()`` from interfaces [MAINT] One less DeprecationWarning (configparser) [MAINT] Import only Sequence to avoid DeprecationWarning fixed [MAINT] DeprecationWarning: use ``HasTraits.trait_set`` instead [HOTFIX] Latest nilearn-0.5.0 breaks tests [MAINT] Stop using deprecated ``logger.warn()`` [FIX] MapNodes failed when ``MultiProcPlugin`` passed by instance
2 parents e72334a + 11f8eb2 commit bca9dfe

File tree

21 files changed

+130
-78
lines changed

21 files changed

+130
-78
lines changed
 

‎nipype/algorithms/confounds.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ def _run_interface(self, runtime):
327327
tr = self.inputs.series_tr
328328

329329
if self.inputs.normalize and tr is None:
330-
IFLOGGER.warn('FD plot cannot be normalized if TR is not set')
330+
IFLOGGER.warning('FD plot cannot be normalized if TR is not set')
331331

332332
self._results['out_figure'] = op.abspath(self.inputs.out_figure)
333333
fig = plot_confound(
@@ -1267,7 +1267,7 @@ def _full_rank(X, cmax=1e15):
12671267
c = smax / smin
12681268
if c < cmax:
12691269
return X, c
1270-
IFLOGGER.warn('Matrix is singular at working precision, regularizing...')
1270+
IFLOGGER.warning('Matrix is singular at working precision, regularizing...')
12711271
lda = (smax - cmax * smin) / (cmax - 1)
12721272
s = s + lda
12731273
X = np.dot(U, np.dot(np.diag(s), V))

‎nipype/algorithms/mesh.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -422,5 +422,5 @@ class P2PDistance(ComputeMeshWarp):
422422

423423
def __init__(self, **inputs):
424424
super(P2PDistance, self).__init__(**inputs)
425-
IFLOGGER.warn('This interface has been deprecated since 1.0, please '
426-
'use ComputeMeshWarp')
425+
IFLOGGER.warning('This interface has been deprecated since 1.0, please '
426+
'use ComputeMeshWarp')

‎nipype/algorithms/misc.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ def _run_interface(self, runtime):
589589
extraheadingBool = True
590590

591591
if len(self.inputs.in_files) == 1:
592-
iflogger.warn('Only one file input!')
592+
iflogger.warning('Only one file input!')
593593

594594
if isdefined(self.inputs.row_headings):
595595
iflogger.info('Row headings have been provided. Adding "labels"'

‎nipype/algorithms/modelgen.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ def _generate_design(self, infolist=None):
602602
try:
603603
out = np.loadtxt(filename)
604604
except IOError:
605-
iflogger.warn('Error reading outliers file %s', filename)
605+
iflogger.warning('Error reading outliers file %s', filename)
606606
out = np.array([])
607607

608608
if out.size > 0:

‎nipype/info.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def get_nipype_gitversion():
163163
'doc': ['Sphinx>=1.4', 'numpydoc', 'matplotlib', 'pydotplus', 'pydot>=1.2.3'],
164164
'tests': TESTS_REQUIRES,
165165
'specs': ['yapf'],
166-
'nipy': ['nitime', 'nilearn', 'dipy', 'nipy', 'matplotlib'],
166+
'nipy': ['nitime', 'nilearn<0.5.0', 'dipy', 'nipy', 'matplotlib'],
167167
'profiler': ['psutil>=5.0'],
168168
'duecredit': ['duecredit'],
169169
'xvfbwrapper': ['xvfbwrapper'],

‎nipype/interfaces/base/core.py

+11-19
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from .specs import (BaseInterfaceInputSpec, CommandLineInputSpec,
4343
StdOutCommandLineInputSpec, MpiCommandLineInputSpec)
4444
from .support import (Bunch, InterfaceResult, NipypeInterfaceError)
45+
from .specs import get_filecopy_info
4546

4647
from future import standard_library
4748
standard_library.install_aliases()
@@ -122,11 +123,15 @@ def _list_outputs(self):
122123
""" List expected outputs"""
123124
raise NotImplementedError
124125

125-
def _get_filecopy_info(self):
126-
""" Provides information about file inputs to copy or link to cwd.
127-
Necessary for pipeline operation
126+
@classmethod
127+
def _get_filecopy_info(cls):
128+
"""Provides information about file inputs to copy or link to cwd.
129+
Necessary for pipeline operation
128130
"""
129-
raise NotImplementedError
131+
iflogger.warning(
132+
'_get_filecopy_info member of Interface was deprecated '
133+
'in nipype-1.1.6 and will be removed in 1.2.0')
134+
return get_filecopy_info(cls)
130135

131136

132137
class BaseInterface(Interface):
@@ -330,19 +335,6 @@ def _outputs(self):
330335

331336
return outputs
332337

333-
@classmethod
334-
def _get_filecopy_info(cls):
335-
""" Provides information about file inputs to copy or link to cwd.
336-
Necessary for pipeline operation
337-
"""
338-
info = []
339-
if cls.input_spec is None:
340-
return info
341-
metadata = dict(copyfile=lambda t: t is not None)
342-
for name, spec in sorted(cls.input_spec().traits(**metadata).items()):
343-
info.append(dict(key=name, copy=spec.copyfile))
344-
return info
345-
346338
def _check_requires(self, spec, name, value):
347339
""" check if required inputs are satisfied
348340
"""
@@ -1180,8 +1172,8 @@ def __init__(self, check_import=True, *args, **kwargs):
11801172
except ImportError:
11811173
failed_imports.append(pkg)
11821174
if failed_imports:
1183-
iflogger.warn('Unable to import %s; %s interface may fail to '
1184-
'run', failed_imports, self.__class__.__name__)
1175+
iflogger.warning('Unable to import %s; %s interface may fail to '
1176+
'run', failed_imports, self.__class__.__name__)
11851177

11861178
@property
11871179
def version(self):

‎nipype/interfaces/base/specs.py

+19
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
absolute_import)
1414

1515
import os
16+
from inspect import isclass
1617
from copy import deepcopy
1718
from warnings import warn
1819
from builtins import str, bytes
@@ -375,3 +376,21 @@ class MpiCommandLineInputSpec(CommandLineInputSpec):
375376
n_procs = traits.Int(desc="Num processors to specify to mpiexec. Do not "
376377
"specify if this is managed externally (e.g. through "
377378
"SGE)")
379+
380+
381+
def get_filecopy_info(cls):
382+
"""Provides information about file inputs to copy or link to cwd.
383+
Necessary for pipeline operation
384+
"""
385+
if cls.input_spec is None:
386+
return None
387+
388+
# normalize_filenames is not a classmethod, hence check first
389+
if not isclass(cls) and hasattr(cls, 'normalize_filenames'):
390+
cls.normalize_filenames()
391+
info = []
392+
inputs = cls.input_spec() if isclass(cls) else cls.inputs
393+
metadata = dict(copyfile=lambda t: t is not None)
394+
for name, spec in sorted(inputs.traits(**metadata).items()):
395+
info.append(dict(key=name, copy=spec.copyfile))
396+
return info

‎nipype/interfaces/base/tests/test_core.py

-7
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,12 @@ def __init__(self):
6262
nif.aggregate_outputs()
6363
with pytest.raises(NotImplementedError):
6464
nif._list_outputs()
65-
with pytest.raises(NotImplementedError):
66-
nif._get_filecopy_info()
6765

6866

6967
def test_BaseInterface():
7068
config.set('monitoring', 'enable', '0')
7169

7270
assert nib.BaseInterface.help() is None
73-
assert nib.BaseInterface._get_filecopy_info() == []
7471

7572
class InputSpec(nib.TraitedSpec):
7673
foo = nib.traits.Int(desc='a random int')
@@ -90,10 +87,6 @@ class DerivedInterface(nib.BaseInterface):
9087
assert DerivedInterface.help() is None
9188
assert 'moo' in ''.join(DerivedInterface._inputs_help())
9289
assert DerivedInterface()._outputs() is None
93-
assert DerivedInterface._get_filecopy_info()[0]['key'] == 'woo'
94-
assert DerivedInterface._get_filecopy_info()[0]['copy']
95-
assert DerivedInterface._get_filecopy_info()[1]['key'] == 'zoo'
96-
assert not DerivedInterface._get_filecopy_info()[1]['copy']
9790
assert DerivedInterface().inputs.foo == nib.Undefined
9891
with pytest.raises(ValueError):
9992
DerivedInterface()._check_mandatory_inputs()

‎nipype/interfaces/base/tests/test_specs.py

+45-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from ....interfaces import fsl
1515
from ...utility.wrappers import Function
1616
from ....pipeline import Node
17-
17+
from ..specs import get_filecopy_info
1818

1919
standard_library.install_aliases()
2020

@@ -55,8 +55,8 @@ def test_TraitedSpec_tab_completion():
5555
bet_nd = Node(fsl.BET(), name='bet')
5656
bet_interface = fsl.BET()
5757
bet_inputs = bet_nd.inputs.class_editable_traits()
58-
bet_outputs = bet_nd.outputs.class_editable_traits()
59-
58+
bet_outputs = bet_nd.outputs.class_editable_traits()
59+
6060
# Check __all__ for bet node and interface inputs
6161
assert set(bet_nd.inputs.__all__) == set(bet_inputs)
6262
assert set(bet_interface.inputs.__all__) == set(bet_inputs)
@@ -433,3 +433,45 @@ def test_ImageFile():
433433
with pytest.raises(nib.TraitError):
434434
x.nocompress = 'test.nii.gz'
435435
x.nocompress = 'test.mgh'
436+
437+
438+
def test_filecopy_info():
439+
class InputSpec(nib.TraitedSpec):
440+
foo = nib.traits.Int(desc='a random int')
441+
goo = nib.traits.Int(desc='a random int', mandatory=True)
442+
moo = nib.traits.Int(desc='a random int', mandatory=False)
443+
hoo = nib.traits.Int(desc='a random int', usedefault=True)
444+
zoo = nib.File(desc='a file', copyfile=False)
445+
woo = nib.File(desc='a file', copyfile=True)
446+
447+
class DerivedInterface(nib.BaseInterface):
448+
input_spec = InputSpec
449+
resource_monitor = False
450+
451+
def normalize_filenames(self):
452+
"""A mock normalize_filenames for freesurfer interfaces that have one"""
453+
self.inputs.zoo = 'normalized_filename.ext'
454+
455+
assert get_filecopy_info(nib.BaseInterface) == []
456+
457+
# Test on interface class, not instantiated
458+
info = get_filecopy_info(DerivedInterface)
459+
assert info[0]['key'] == 'woo'
460+
assert info[0]['copy']
461+
assert info[1]['key'] == 'zoo'
462+
assert not info[1]['copy']
463+
info = None
464+
465+
# Test with instantiated interface
466+
derived = DerivedInterface()
467+
# First check that zoo is not defined
468+
assert derived.inputs.zoo == Undefined
469+
# After the first call to get_filecopy_info zoo is defined
470+
info = get_filecopy_info(derived)
471+
# Ensure that normalize_filenames was called
472+
assert derived.inputs.zoo == 'normalized_filename.ext'
473+
# Check the results are consistent
474+
assert info[0]['key'] == 'woo'
475+
assert info[0]['copy']
476+
assert info[1]['key'] == 'zoo'
477+
assert not info[1]['copy']

‎nipype/interfaces/base/traits_extension.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
from builtins import str, bytes
2727
import os
28-
import collections
28+
from collections import Sequence
2929

3030
# perform all external trait imports here
3131
from traits import __version__ as traits_version
@@ -323,7 +323,7 @@ def validate(self, object, name, value):
323323

324324
# want to treat range and other sequences (except str) as list
325325
if not isinstance(value, (str, bytes)) and isinstance(
326-
value, collections.Sequence):
326+
value, Sequence):
327327
value = list(value)
328328

329329
if not isdefined(value) or \

‎nipype/interfaces/dipy/reconstruction.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,9 @@ def _run_interface(self, runtime):
124124
sigma = mean_std * (1 + bias)
125125

126126
if sigma == 0:
127-
IFLOGGER.warn('Noise std is 0.0, looks like data was masked and '
128-
'noise cannot be estimated correctly. Using default '
129-
'tensor model instead of RESTORE.')
127+
IFLOGGER.warning('Noise std is 0.0, looks like data was masked and '
128+
'noise cannot be estimated correctly. Using default '
129+
'tensor model instead of RESTORE.')
130130
dti = TensorModel(gtab)
131131
else:
132132
IFLOGGER.info('Performing RESTORE with noise std=%.4f.', sigma)
@@ -258,11 +258,11 @@ def _run_interface(self, runtime):
258258
ratio = abs(response[1] / response[0])
259259

260260
if ratio > 0.25:
261-
IFLOGGER.warn('Estimated response is not prolate enough. '
262-
'Ratio=%0.3f.', ratio)
261+
IFLOGGER.warning('Estimated response is not prolate enough. '
262+
'Ratio=%0.3f.', ratio)
263263
elif ratio < 1.e-5 or np.any(np.isnan(response)):
264264
response = np.array([1.8e-3, 3.6e-4, 3.6e-4, S0])
265-
IFLOGGER.warn(
265+
IFLOGGER.warning(
266266
'Estimated response is not valid, using a default one')
267267
else:
268268
IFLOGGER.info('Estimated response: %s', str(response[:3]))
@@ -344,8 +344,8 @@ def _run_interface(self, runtime):
344344
ratio = response[0][1] / response[0][0]
345345

346346
if abs(ratio - 0.2) > 0.1:
347-
IFLOGGER.warn('Estimated response is not prolate enough. '
348-
'Ratio=%0.3f.', ratio)
347+
IFLOGGER.warning('Estimated response is not prolate enough. '
348+
'Ratio=%0.3f.', ratio)
349349

350350
csd_model = ConstrainedSphericalDeconvModel(
351351
gtab, response, sh_order=self.inputs.sh_order)

‎nipype/interfaces/dipy/tracks.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ def _run_interface(self, runtime):
7373
data_dims = refnii.shape[:3]
7474
kwargs = dict(affine=affine)
7575
else:
76-
IFLOGGER.warn('voxel_dims and data_dims are deprecated as of dipy '
77-
'0.7.1. Please use reference input instead')
76+
IFLOGGER.warning('voxel_dims and data_dims are deprecated as of dipy '
77+
'0.7.1. Please use reference input instead')
7878

7979
if not isdefined(self.inputs.data_dims):
8080
data_dims = header['dim']

‎nipype/interfaces/freesurfer/base.py

-10
Original file line numberDiff line numberDiff line change
@@ -189,16 +189,6 @@ class FSSurfaceCommand(FSCommand):
189189
including the full path in the filename, we can also avoid this behavior.
190190
"""
191191

192-
def _get_filecopy_info(self):
193-
self._normalize_filenames()
194-
return super(FSSurfaceCommand, self)._get_filecopy_info()
195-
196-
def _normalize_filenames(self):
197-
"""Filename normalization routine to perform only when run in Node
198-
context
199-
"""
200-
pass
201-
202192
@staticmethod
203193
def _associated_file(in_file, out_name):
204194
"""Based on MRIsBuildFileName in freesurfer/utils/mrisurf.c

‎nipype/interfaces/freesurfer/utils.py

+14-9
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,8 @@ def _format_arg(self, name, spec, value):
316316
"Cannot create {} file with extension "
317317
"{}".format(value, ext))
318318
else:
319-
logger.warn('Creating %s file with extension %s: %s%s',
320-
value, ext, base, ext)
319+
logger.warning('Creating %s file with extension %s: %s%s',
320+
value, ext, base, ext)
321321

322322
if value in implicit_filetypes:
323323
return ""
@@ -554,8 +554,8 @@ def _format_arg(self, name, spec, value):
554554
"Cannot create {} file with extension "
555555
"{}".format(value, ext))
556556
else:
557-
logger.warn('Creating %s file with extension %s: %s%s',
558-
value, ext, base, ext)
557+
logger.warning('Creating %s file with extension %s: %s%s',
558+
value, ext, base, ext)
559559
if value in implicit_filetypes:
560560
return ""
561561
return super(SurfaceTransform, self)._format_arg(name, spec, value)
@@ -1289,9 +1289,11 @@ def _list_outputs(self):
12891289

12901290
return outputs
12911291

1292-
def _normalize_filenames(self):
1293-
""" In a Node context, interpret out_file as a literal path to
1294-
reduce surprise.
1292+
def normalize_filenames(self):
1293+
"""
1294+
Filename normalization routine to perform only when run in Node
1295+
context.
1296+
Interpret out_file as a literal path to reduce surprise.
12951297
"""
12961298
if isdefined(self.inputs.out_file):
12971299
self.inputs.out_file = os.path.abspath(self.inputs.out_file)
@@ -3837,8 +3839,11 @@ def _list_outputs(self):
38373839
self.inputs.out_name)
38383840
return outputs
38393841

3840-
def _normalize_filenames(self):
3841-
""" Find full paths for pial, thickness and sphere files for copying
3842+
def normalize_filenames(self):
3843+
"""
3844+
Filename normalization routine to perform only when run in Node
3845+
context.
3846+
Find full paths for pial, thickness and sphere files for copying.
38423847
"""
38433848
in_file = self.inputs.in_file
38443849

‎nipype/interfaces/fsl/base.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ def output_type(cls):
107107
try:
108108
return os.environ['FSLOUTPUTTYPE']
109109
except KeyError:
110-
IFLOGGER.warn('FSLOUTPUTTYPE environment variable is not set. '
111-
'Setting FSLOUTPUTTYPE=NIFTI')
110+
IFLOGGER.warning('FSLOUTPUTTYPE environment variable is not set. '
111+
'Setting FSLOUTPUTTYPE=NIFTI')
112112
return 'NIFTI'
113113

114114
@staticmethod

‎nipype/interfaces/mrtrix3/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def _format_arg(self, name, trait_spec, value):
7777
from multiprocessing import cpu_count
7878
value = cpu_count()
7979
except:
80-
iflogger.warn('Number of threads could not be computed')
80+
iflogger.warning('Number of threads could not be computed')
8181
pass
8282
return trait_spec.argstr % value
8383

‎nipype/pipeline/engine/nodes.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
from ...interfaces.base import (traits, InputMultiPath, CommandLine, Undefined,
3333
DynamicTraitedSpec, Bunch, InterfaceResult,
3434
Interface, isdefined)
35+
from ...interfaces.base.specs import get_filecopy_info
36+
3537
from .utils import (
3638
_parameterization_dir, save_hashfile as _save_hashfile, load_resultfile as
3739
_load_resultfile, save_resultfile as _save_resultfile, nodelist_runner as
@@ -656,7 +658,8 @@ def _run_command(self, execute, copyfiles=True):
656658

657659
def _copyfiles_to_wd(self, execute=True, linksonly=False):
658660
"""copy files over and change the inputs"""
659-
if not hasattr(self._interface, '_get_filecopy_info'):
661+
filecopy_info = get_filecopy_info(self.interface)
662+
if not filecopy_info:
660663
# Nothing to be done
661664
return
662665

@@ -669,7 +672,7 @@ def _copyfiles_to_wd(self, execute=True, linksonly=False):
669672
outdir = op.join(outdir, '_tempinput')
670673
makedirs(outdir, exist_ok=True)
671674

672-
for info in self._interface._get_filecopy_info():
675+
for info in filecopy_info:
673676
files = self.inputs.trait_get().get(info['key'])
674677
if not isdefined(files) or not files:
675678
continue

‎nipype/pipeline/engine/utils.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -304,13 +304,15 @@ def save_resultfile(result, cwd, name):
304304
tosave = _uncollapse(outputs.copy(), collapsed)
305305
except AttributeError:
306306
tosave = outputs = result.outputs.dictcopy() # outputs was a bunch
307-
result.outputs.set(**modify_paths(tosave, relative=True, basedir=cwd))
307+
for k, v in list(modify_paths(tosave, relative=True, basedir=cwd).items()):
308+
setattr(result.outputs, k, v)
308309

309310
savepkl(resultsfile, result)
310311
logger.debug('saved results in %s', resultsfile)
311312

312313
if result.outputs:
313-
result.outputs.set(**outputs)
314+
for k, v in list(outputs.items()):
315+
setattr(result.outputs, k, v)
314316

315317

316318
def load_resultfile(path, name):
@@ -360,8 +362,9 @@ def load_resultfile(path, name):
360362
except AttributeError:
361363
outputs = result.outputs.dictcopy() # outputs == Bunch
362364
try:
363-
result.outputs.set(
364-
**modify_paths(outputs, relative=False, basedir=path))
365+
for k, v in list(modify_paths(outputs, relative=False,
366+
basedir=path).items()):
367+
setattr(result.outputs, k, v)
365368
except FileNotFoundError:
366369
logger.debug('conversion to full path results in '
367370
'non existent file')

‎nipype/pipeline/engine/workflows.py

+2
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,8 @@ def run(self, plugin=None, plugin_args=None, updatehash=False):
566566
plugin = config.get('execution', 'plugin')
567567
if not isinstance(plugin, (str, bytes)):
568568
runner = plugin
569+
plugin = runner.__class__.__name__[:-len('Plugin')]
570+
plugin_args = runner.plugin_args
569571
else:
570572
name = '.'.join(__name__.split('.')[:-2] + ['plugins'])
571573
try:

‎nipype/pkg_info.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ def pkg_commit_hash(pkg_path):
5151
raise IOError('Missing commit info file %s' % pth)
5252
cfg_parser = configparser.RawConfigParser()
5353
with open(pth, encoding='utf-8') as fp:
54-
cfg_parser.readfp(fp)
54+
if sys.version_info >= (3, 2):
55+
cfg_parser.read_file(fp)
56+
else:
57+
cfg_parser.readfp(fp)
5558
archive_subst = cfg_parser.get('commit hash', 'archive_subst_hash')
5659
if not archive_subst.startswith('$Format'): # it has been substituted
5760
return 'archive substitution', archive_subst

‎nipype/utils/filemanip.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ def copyfile(originalfile,
471471
fmlogger.debug('Copying File: %s->%s', newfile, originalfile)
472472
shutil.copyfile(originalfile, newfile)
473473
except shutil.Error as e:
474-
fmlogger.warn(e.message)
474+
fmlogger.warning(e.message)
475475

476476
# Associated files
477477
if copy_related_files:

0 commit comments

Comments
 (0)
Please sign in to comment.