Skip to content

Commit e43e401

Browse files
authored
Merge pull request #3075 from oesteban/enh/better-errors-reading-results
ENH: Minimize the number of calls to ``_load_results`` when populating inputs
2 parents 5058ab7 + 2e5436d commit e43e401

File tree

1 file changed

+45
-34
lines changed

1 file changed

+45
-34
lines changed

nipype/pipeline/engine/nodes.py

+45-34
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
absolute_import)
1010
from builtins import range, str, bytes, open
1111

12-
from collections import OrderedDict
12+
from collections import OrderedDict, defaultdict
1313

1414
import os
1515
import os.path as op
@@ -510,49 +510,60 @@ def _get_hashval(self):
510510
return self._hashed_inputs, self._hashvalue
511511

512512
def _get_inputs(self):
513-
"""Retrieve inputs from pointers to results file
513+
"""
514+
Retrieve inputs from pointers to results files.
514515
515516
This mechanism can be easily extended/replaced to retrieve data from
516517
other data sources (e.g., XNAT, HTTP, etc.,.)
517518
"""
518-
if self._got_inputs:
519+
if self._got_inputs: # Inputs cached
520+
return
521+
522+
if not self.input_source: # No previous nodes
523+
self._got_inputs = True
519524
return
520525

521-
logger.debug('Setting node inputs')
526+
prev_results = defaultdict(list)
522527
for key, info in list(self.input_source.items()):
523-
logger.debug('input: %s', key)
524-
results_file = info[0]
525-
logger.debug('results file: %s', results_file)
526-
outputs = _load_resultfile(results_file).outputs
528+
prev_results[info[0]].append((key, info[1]))
529+
530+
logger.debug(
531+
'[Node] Setting %d connected inputs of node "%s" from %d previous nodes.',
532+
len(self.input_source), self.name, len(prev_results))
533+
534+
for results_fname, connections in list(prev_results.items()):
535+
outputs = None
536+
try:
537+
outputs = _load_resultfile(results_fname).outputs
538+
except AttributeError as e:
539+
logger.critical('%s', e)
540+
527541
if outputs is None:
528542
raise RuntimeError("""\
529-
Error populating the input "%s" of node "%s": the results file of the source node \
530-
(%s) does not contain any outputs.""" % (key, self.name, results_file))
531-
output_value = Undefined
532-
if isinstance(info[1], tuple):
533-
output_name = info[1][0]
534-
value = getattr(outputs, output_name)
535-
if isdefined(value):
536-
output_value = evaluate_connect_function(
537-
info[1][1], info[1][2], value)
538-
else:
539-
output_name = info[1]
543+
Error populating the inputs of node "%s": the results file of the source node \
544+
(%s) does not contain any outputs.""" % (self.name, results_fname))
545+
546+
for key, conn in connections:
547+
output_value = Undefined
548+
if isinstance(conn, tuple):
549+
value = getattr(outputs, conn[0])
550+
if isdefined(value):
551+
output_value = evaluate_connect_function(
552+
conn[1], conn[2], value)
553+
else:
554+
output_value = getattr(outputs, conn)
555+
540556
try:
541-
output_value = outputs.trait_get()[output_name]
542-
except AttributeError:
543-
output_value = outputs.dictcopy()[output_name]
544-
logger.debug('output: %s', output_name)
545-
try:
546-
self.set_input(key, deepcopy(output_value))
547-
except traits.TraitError as e:
548-
msg = (
549-
e.args[0], '', 'Error setting node input:',
550-
'Node: %s' % self.name, 'input: %s' % key,
551-
'results_file: %s' % results_file,
552-
'value: %s' % str(output_value),
553-
)
554-
e.args = ('\n'.join(msg), )
555-
raise
557+
self.set_input(key, deepcopy(output_value))
558+
except traits.TraitError as e:
559+
msg = (
560+
e.args[0], '', 'Error setting node input:',
561+
'Node: %s' % self.name, 'input: %s' % key,
562+
'results_file: %s' % results_fname,
563+
'value: %s' % str(output_value),
564+
)
565+
e.args = ('\n'.join(msg), )
566+
raise
556567

557568
# Successfully set inputs
558569
self._got_inputs = True

0 commit comments

Comments
 (0)