Skip to content

Commit 3ec7f33

Browse files
committed
Merge remote-tracking branch 'upstream/master' into rel/1.1.7
2 parents 4937e4a + 5d37cae commit 3ec7f33

File tree

7 files changed

+213
-200
lines changed

7 files changed

+213
-200
lines changed

nipype/algorithms/confounds.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,11 @@ class CompCorInputSpec(BaseInterfaceInputSpec):
412412
low=0,
413413
usedefault=True,
414414
desc='Number of volumes at start of series to ignore')
415+
failure_mode = traits.Enum(
416+
'error', 'NaN',
417+
usedefault=True,
418+
desc='When no components are found or convergence fails, raise an error '
419+
'or silently return columns of NaNs.')
415420

416421

417422
class CompCorOutputSpec(TraitedSpec):
@@ -1185,13 +1190,20 @@ def compute_noise_components(imgseries, mask_images, num_components,
11851190

11861191
# "The covariance matrix C = MMT was constructed and decomposed into its
11871192
# principal components using a singular value decomposition."
1188-
u, _, _ = np.linalg.svd(M, full_matrices=False)
1193+
try:
1194+
u, _, _ = np.linalg.svd(M, full_matrices=False)
1195+
except np.linalg.LinAlgError:
1196+
if self.inputs.failure_mode == 'error':
1197+
raise
1198+
u = np.ones((M.shape[0], num_components), dtype=np.float32) * np.nan
11891199
if components is None:
11901200
components = u[:, :num_components]
11911201
else:
11921202
components = np.hstack((components, u[:, :num_components]))
11931203
if components is None and num_components > 0:
1194-
raise ValueError('No components found')
1204+
if self.inputs.failure_mode == 'error':
1205+
raise ValueError('No components found')
1206+
components = np.ones((M.shape[0], num_components), dtype=np.float32) * np.nan
11951207
return components, basis
11961208

11971209

nipype/interfaces/base/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,4 @@
2222
OutputMultiObject, InputMultiObject,
2323
OutputMultiPath, InputMultiPath)
2424

25-
from .support import (Bunch, InterfaceResult, load_template,
26-
NipypeInterfaceError)
25+
from .support import (Bunch, InterfaceResult, NipypeInterfaceError)

nipype/interfaces/base/core.py

Lines changed: 29 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,17 @@
2020
from copy import deepcopy
2121
from datetime import datetime as dt
2222
import os
23-
import re
2423
import platform
2524
import subprocess as sp
2625
import shlex
2726
import sys
28-
from textwrap import wrap
2927
import simplejson as json
3028
from dateutil.parser import parse as parseutc
29+
from future import standard_library
3130

3231
from ... import config, logging, LooseVersion
3332
from ...utils.provenance import write_provenance
34-
from ...utils.misc import trim, str2bool, rgetcwd
33+
from ...utils.misc import str2bool, rgetcwd
3534
from ...utils.filemanip import (FileNotFoundError, split_filename,
3635
which, get_dependencies)
3736
from ...utils.subprocess import run_command
@@ -42,9 +41,9 @@
4241
from .specs import (BaseInterfaceInputSpec, CommandLineInputSpec,
4342
StdOutCommandLineInputSpec, MpiCommandLineInputSpec,
4443
get_filecopy_info)
45-
from .support import (Bunch, InterfaceResult, NipypeInterfaceError)
44+
from .support import (Bunch, InterfaceResult, NipypeInterfaceError,
45+
format_help)
4646

47-
from future import standard_library
4847
standard_library.install_aliases()
4948

5049
iflogger = logging.getLogger('nipype.interface')
@@ -68,47 +67,42 @@ class Interface(object):
6867

6968
input_spec = None # A traited input specification
7069
output_spec = None # A traited output specification
71-
72-
# defines if the interface can reuse partial results after interruption
73-
_can_resume = False
70+
_can_resume = False # See property below
71+
_always_run = False # See property below
7472

7573
@property
7674
def can_resume(self):
75+
"""Defines if the interface can reuse partial results after interruption.
76+
Only applies to interfaces being run within a workflow context."""
7777
return self._can_resume
7878

79-
# should the interface be always run even if the inputs were not changed?
80-
_always_run = False
81-
8279
@property
8380
def always_run(self):
81+
"""Should the interface be always run even if the inputs were not changed?
82+
Only applies to interfaces being run within a workflow context."""
8483
return self._always_run
8584

86-
def __init__(self, **inputs):
87-
"""Initialize command with given args and inputs."""
88-
raise NotImplementedError
89-
90-
@classmethod
91-
def help(cls):
92-
""" Prints class help"""
93-
raise NotImplementedError
94-
95-
@classmethod
96-
def _inputs_help(cls):
97-
""" Prints inputs help"""
98-
raise NotImplementedError
99-
100-
@classmethod
101-
def _outputs_help(cls):
102-
""" Prints outputs help"""
85+
@property
86+
def version(self):
87+
"""interfaces should implement a version property"""
10388
raise NotImplementedError
10489

10590
@classmethod
10691
def _outputs(cls):
10792
""" Initializes outputs"""
10893
raise NotImplementedError
10994

110-
@property
111-
def version(self):
95+
@classmethod
96+
def help(cls, returnhelp=False):
97+
""" Prints class help """
98+
allhelp = format_help(cls)
99+
if returnhelp:
100+
return allhelp
101+
print(allhelp)
102+
return None # R1710
103+
104+
def __init__(self):
105+
"""Subclasses must implement __init__"""
112106
raise NotImplementedError
113107

114108
def run(self):
@@ -190,142 +184,6 @@ def __init__(self, from_file=None, resource_monitor=None,
190184
for name, value in list(inputs.items()):
191185
setattr(self.inputs, name, value)
192186

193-
@classmethod
194-
def help(cls, returnhelp=False):
195-
""" Prints class help
196-
"""
197-
198-
if cls.__doc__:
199-
# docstring = cls.__doc__.split('\n')
200-
# docstring = [trim(line, '') for line in docstring]
201-
docstring = trim(cls.__doc__).split('\n') + ['']
202-
else:
203-
docstring = ['']
204-
205-
allhelp = '\n'.join(docstring + cls._inputs_help(
206-
) + [''] + cls._outputs_help() + [''] + cls._refs_help() + [''])
207-
if returnhelp:
208-
return allhelp
209-
else:
210-
print(allhelp)
211-
212-
@classmethod
213-
def _refs_help(cls):
214-
""" Prints interface references.
215-
"""
216-
if not cls.references_:
217-
return []
218-
219-
helpstr = ['References::']
220-
221-
for r in cls.references_:
222-
helpstr += ['{}'.format(r['entry'])]
223-
224-
return helpstr
225-
226-
@classmethod
227-
def _get_trait_desc(self, inputs, name, spec):
228-
desc = spec.desc
229-
xor = spec.xor
230-
requires = spec.requires
231-
argstr = spec.argstr
232-
233-
manhelpstr = ['\t%s' % name]
234-
235-
type_info = spec.full_info(inputs, name, None)
236-
237-
default = ''
238-
if spec.usedefault:
239-
default = ', nipype default value: %s' % str(
240-
spec.default_value()[1])
241-
line = "(%s%s)" % (type_info, default)
242-
243-
manhelpstr = wrap(
244-
line,
245-
70,
246-
initial_indent=manhelpstr[0] + ': ',
247-
subsequent_indent='\t\t ')
248-
249-
if desc:
250-
for line in desc.split('\n'):
251-
line = re.sub("\s+", " ", line)
252-
manhelpstr += wrap(
253-
line, 70, initial_indent='\t\t', subsequent_indent='\t\t')
254-
255-
if argstr:
256-
pos = spec.position
257-
if pos is not None:
258-
manhelpstr += wrap(
259-
'flag: %s, position: %s' % (argstr, pos),
260-
70,
261-
initial_indent='\t\t',
262-
subsequent_indent='\t\t')
263-
else:
264-
manhelpstr += wrap(
265-
'flag: %s' % argstr,
266-
70,
267-
initial_indent='\t\t',
268-
subsequent_indent='\t\t')
269-
270-
if xor:
271-
line = '%s' % ', '.join(xor)
272-
manhelpstr += wrap(
273-
line,
274-
70,
275-
initial_indent='\t\tmutually_exclusive: ',
276-
subsequent_indent='\t\t ')
277-
278-
if requires:
279-
others = [field for field in requires if field != name]
280-
line = '%s' % ', '.join(others)
281-
manhelpstr += wrap(
282-
line,
283-
70,
284-
initial_indent='\t\trequires: ',
285-
subsequent_indent='\t\t ')
286-
return manhelpstr
287-
288-
@classmethod
289-
def _inputs_help(cls):
290-
""" Prints description for input parameters
291-
"""
292-
helpstr = ['Inputs::']
293-
294-
inputs = cls.input_spec()
295-
if len(list(inputs.traits(transient=None).items())) == 0:
296-
helpstr += ['', '\tNone']
297-
return helpstr
298-
299-
manhelpstr = ['', '\t[Mandatory]']
300-
mandatory_items = inputs.traits(mandatory=True)
301-
for name, spec in sorted(mandatory_items.items()):
302-
manhelpstr += cls._get_trait_desc(inputs, name, spec)
303-
304-
opthelpstr = ['', '\t[Optional]']
305-
for name, spec in sorted(inputs.traits(transient=None).items()):
306-
if name in mandatory_items:
307-
continue
308-
opthelpstr += cls._get_trait_desc(inputs, name, spec)
309-
310-
if manhelpstr:
311-
helpstr += manhelpstr
312-
if opthelpstr:
313-
helpstr += opthelpstr
314-
return helpstr
315-
316-
@classmethod
317-
def _outputs_help(cls):
318-
""" Prints description for output parameters
319-
"""
320-
helpstr = ['Outputs::', '']
321-
if cls.output_spec:
322-
outputs = cls.output_spec()
323-
for name, spec in sorted(outputs.traits(transient=None).items()):
324-
helpstr += cls._get_trait_desc(outputs, name, spec)
325-
if len(helpstr) == 2:
326-
helpstr += ['\tNone']
327-
return helpstr
328-
329187
def _outputs(self):
330188
""" Returns a bunch containing output fields for the class
331189
"""
@@ -645,7 +503,7 @@ def save_inputs_to_json(self, json_file):
645503
A convenient way to save current inputs to a JSON file.
646504
"""
647505
inputs = self.inputs.get_traitsfree()
648-
iflogger.debug('saving inputs {}', inputs)
506+
iflogger.debug('saving inputs %s', inputs)
649507
with open(json_file, 'w' if PY3 else 'wb') as fhandle:
650508
json.dump(inputs, fhandle, indent=4, ensure_ascii=False)
651509

@@ -777,14 +635,6 @@ def set_default_terminal_output(cls, output_type):
777635
raise AttributeError(
778636
'Invalid terminal output_type: %s' % output_type)
779637

780-
@classmethod
781-
def help(cls, returnhelp=False):
782-
allhelp = 'Wraps command **{cmd}**\n\n{help}'.format(
783-
cmd=cls._cmd, help=super(CommandLine, cls).help(returnhelp=True))
784-
if returnhelp:
785-
return allhelp
786-
print(allhelp)
787-
788638
def __init__(self, command=None, terminal_output=None, **inputs):
789639
super(CommandLine, self).__init__(**inputs)
790640
self._environ = None
@@ -804,6 +654,10 @@ def __init__(self, command=None, terminal_output=None, **inputs):
804654
@property
805655
def cmd(self):
806656
"""sets base command, immutable"""
657+
if not self._cmd:
658+
raise NotImplementedError(
659+
'CommandLineInterface should wrap an executable, but '
660+
'none has been set.')
807661
return self._cmd
808662

809663
@property

0 commit comments

Comments
 (0)