Repository: nipy/nipype

Issue:
more than 26 iterables in distinct graphs causes workflow expansion to crash
to replicate:

``` python
import os
from nipype.interfaces.utility import Function
from nipype.pipeline.engine import Workflow, MapNode, Node

def fwhm(fwhm):
    return fwhm

def create_wf(name):
    pipe = Workflow(name=name)
    process = Node(Function(input_names=['fwhm'],
                            output_names=['fwhm'],
                            function=fwhm),
                   name='proc')
    process.iterables = ('fwhm', [0,1])
    pipe.add_nodes([process])
    return pipe

metawf = Workflow(name='meta')
metawf.add_nodes([create_wf('wf%d' % i) for i in range(27)]) # 26 will not crash but 27 will
metawf.run()
```



Discussion:

Resolving patch:
diff --git a/nipype/pipeline/utils.py b/nipype/pipeline/utils.py
--- a/nipype/pipeline/utils.py
+++ b/nipype/pipeline/utils.py
@@ -492,8 +492,7 @@ def generate_expanded_graph(graph_in):
             node.iterables = dict(map(lambda(x): (x[0],
                                                   lambda: x[1]),
                                       node.iterables))
-    allprefixes = list('0abcdefghijklmnopqrstuvwxyz')
-    iterable_prefix = '0'
+    allprefixes = list('abcdefghijklmnopqrstuvwxyz')
     while moreiterables:
         nodes = nx.topological_sort(graph_in)
         nodes.reverse()
@@ -501,12 +500,21 @@ def generate_expanded_graph(graph_in):
         if inodes:
             node = inodes[0]
             iterables = node.iterables.copy()
-            iterable_prefix = \
-                            allprefixes[allprefixes.index(iterable_prefix) + 1]
-            logger.debug('node: %s iterables: %s' % (node, iterables))
             node.iterables = None
-            node._id += ('.' + iterable_prefix + 'I')
+            logger.debug('node: %s iterables: %s' % (node, iterables))
             subnodes = [s for s in dfs_preorder(graph_in, node)]
+            prior_prefix = []
+            for s in subnodes:
+                prior_prefix.extend(re.findall('\.(.)I', s._id))
+            prior_prefix = sorted(prior_prefix)
+            if not len(prior_prefix):
+                iterable_prefix = 'a'
+            else:
+                if prior_prefix[-1] == 'z':
+                    raise ValueError('Too many iterables in the workflow')
+                iterable_prefix =\
+                allprefixes[allprefixes.index(prior_prefix[-1]) + 1]
+            node._id += ('.' + iterable_prefix + 'I')
             logger.debug(('subnodes:', subnodes))
             subgraph = graph_in.subgraph(subnodes)
             graph_in = _merge_graphs(graph_in, subnodes,


Test patch:
diff --git a/nipype/pipeline/tests/test_utils.py b/nipype/pipeline/tests/test_utils.py
--- a/nipype/pipeline/tests/test_utils.py
+++ b/nipype/pipeline/tests/test_utils.py
@@ -130,3 +130,30 @@ def test_inputs_removal():
                                                    n1.name,
                                                    'file1.txt'))
     rmtree(out_dir)
+
+def fwhm(fwhm):
+    return fwhm
+
+def create_wf(name):
+    pipe = pe.Workflow(name=name)
+    process = pe.Node(niu.Function(input_names=['fwhm'],
+                            output_names=['fwhm'],
+                            function=fwhm),
+                   name='proc')
+    process.iterables = ('fwhm', [0])
+    process2 = pe.Node(niu.Function(input_names=['fwhm'],
+                                   output_names=['fwhm'],
+                                   function=fwhm),
+                      name='proc2')
+    process2.iterables = ('fwhm', [0])
+    pipe.connect(process, 'fwhm', process2, 'fwhm')
+    return pipe
+
+def test_multi_disconnected_iterable():
+    out_dir = mkdtemp()
+    metawf = pe.Workflow(name='meta')
+    metawf.base_dir = out_dir
+    metawf.add_nodes([create_wf('wf%d' % i) for i in range(30)])
+    eg = metawf.run(plugin='Linear')
+    yield assert_equal, len(eg.nodes()), 60
+    rmtree(out_dir)