Skip to content

Commit d338ddd

Browse files
committed
ENH: Minimize the number of calls to _load_results when populating inputs
This PR attempts to alleviate #3014 by opening the result file of a source node only once when that node feeds into several inputs of the node collecting inputs. Before these changes, a call to ``_load_results`` was issued for every input field that needed to collect its inputs from a past node. Now, all the inputs comming from the same node are put together and the ``_load_results`` function is called just once. The PR also modifies the manner the ``AttributeError``s (#3014) were handled to make it easier to spot whether an error occured while loading results araises when gathering the inputs of a node-to-be-run or elsewhere.
1 parent 57f1569 commit d338ddd

File tree

1 file changed

+39
-33
lines changed

1 file changed

+39
-33
lines changed

nipype/pipeline/engine/nodes.py

Lines changed: 39 additions & 33 deletions
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,55 @@ 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
"""
518519
if self._got_inputs:
519520
return
520521

521-
logger.debug('Setting node inputs')
522+
prev_results = defaultdict(list)
522523
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
524+
prev_results[info[0]].append((key, info[1]))
525+
526+
logger.debug('[Node] Setting %d connected inputs from %d previous nodes.',
527+
len(self.input_source), len(prev_results))
528+
529+
for results_fname, connections in list(prev_results.items()):
530+
outputs = None
531+
try:
532+
outputs = _load_resultfile(results_fname).outputs
533+
except AttributeError as e:
534+
logger.critical('%s', e)
535+
527536
if outputs is None:
528537
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]
538+
Error populating the inpus of node "%s": the results file of the source node \
539+
(%s) does not contain any outputs.""" % (self.name, results_fname))
540+
541+
for key, conn in connections:
542+
output_value = Undefined
543+
if isinstance(conn, tuple):
544+
value = getattr(outputs, conn[0])
545+
if isdefined(value):
546+
output_value = evaluate_connect_function(
547+
conn[1], conn[2], value)
548+
else:
549+
output_value = getattr(outputs, conn)
550+
540551
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
552+
self.set_input(key, deepcopy(output_value))
553+
except traits.TraitError as e:
554+
msg = (
555+
e.args[0], '', 'Error setting node input:',
556+
'Node: %s' % self.name, 'input: %s' % key,
557+
'results_file: %s' % results_fname,
558+
'value: %s' % str(output_value),
559+
)
560+
e.args = ('\n'.join(msg), )
561+
raise
556562

557563
# Successfully set inputs
558564
self._got_inputs = True

0 commit comments

Comments
 (0)