@@ -441,6 +441,7 @@ def test_write_graph_runs(tmpdir):
441441
442442 assert os .path .exists ('graph.dot' ) or os .path .exists (
443443 'graph_detailed.dot' )
444+
444445 try :
445446 os .remove ('graph.dot' )
446447 except OSError :
@@ -484,6 +485,164 @@ def test_deep_nested_write_graph_runs(tmpdir):
484485 pass
485486
486487
488+ # examples of dot files used in the following test
489+ dotfile_orig = ['strict digraph {\n ' ,
490+ '"mod1 (engine)";\n ' ,
491+ '"mod2 (engine)";\n ' ,
492+ '"mod1 (engine)" -> "mod2 (engine)";\n ' ,
493+ '}\n ' ]
494+
495+ dotfile_detailed_orig = ['digraph structs {\n ' ,
496+ 'node [shape=record];\n ' ,
497+ 'pipemod1 [label="{IN}|{ mod1 | engine | }|{OUT|<outoutput1> output1}"];\n ' ,
498+ 'pipemod2 [label="{IN|<ininput1> input1}|{ mod2 | engine | }|{OUT}"];\n ' ,
499+ 'pipemod1:outoutput1:e -> pipemod2:ininput1:w;\n ' ,
500+ '}' ]
501+
502+
503+ dotfile_hierarchical = ['digraph pipe{\n ' ,
504+ ' label="pipe";\n ' ,
505+ ' pipe_mod1[label="mod1 (engine)"];\n ' ,
506+ ' pipe_mod2[label="mod2 (engine)"];\n ' ,
507+ ' pipe_mod1 -> pipe_mod2;\n ' ,
508+ '}' ]
509+
510+ dotfile_colored = ['digraph pipe{\n ' ,
511+ ' label="pipe";\n ' ,
512+ ' pipe_mod1[label="mod1 (engine)", style=filled, fillcolor="#FFFFC8"];\n ' ,
513+ ' pipe_mod2[label="mod2 (engine)", style=filled, fillcolor="#FFFFC8"];\n ' ,
514+ ' pipe_mod1 -> pipe_mod2;\n ' ,
515+ '}' ]
516+
517+ dotfiles = {
518+ "orig" : dotfile_orig ,
519+ "flat" : dotfile_orig ,
520+ "exec" : dotfile_orig ,
521+ "hierarchical" : dotfile_hierarchical ,
522+ "colored" : dotfile_colored
523+ }
524+
525+ @pytest .mark .parametrize ("simple" , [True , False ])
526+ @pytest .mark .parametrize ("graph_type" , ['orig' , 'flat' , 'exec' , 'hierarchical' , 'colored' ])
527+ def test_write_graph_dotfile (tmpdir , graph_type , simple ):
528+ """ checking dot files for a workflow without iterables"""
529+ tmpdir .chdir ()
530+
531+ pipe = pe .Workflow (name = 'pipe' )
532+ mod1 = pe .Node (interface = EngineTestInterface (), name = 'mod1' )
533+ mod2 = pe .Node (interface = EngineTestInterface (), name = 'mod2' )
534+ pipe .connect ([(mod1 , mod2 , [('output1' , 'input1' )])])
535+ pipe .write_graph (
536+ graph2use = graph_type , simple_form = simple , format = 'dot' )
537+
538+ with open ("graph.dot" ) as f :
539+ graph_str = f .read ()
540+
541+ if simple :
542+ for line in dotfiles [graph_type ]:
543+ assert line in graph_str
544+ else :
545+ # if simple=False graph.dot uses longer names
546+ for line in dotfiles [graph_type ]:
547+ if graph_type in ["hierarchical" , "colored" ]:
548+ assert line .replace ("mod1 (engine)" , "mod1.EngineTestInterface.engine" ).replace (
549+ "mod2 (engine)" , "mod2.EngineTestInterface.engine" ) in graph_str
550+ else :
551+ assert line .replace (
552+ "mod1 (engine)" , "pipe.mod1.EngineTestInterface.engine" ).replace (
553+ "mod2 (engine)" , "pipe.mod2.EngineTestInterface.engine" ) in graph_str
554+
555+ # graph_detailed is the same for orig, flat, exec (if no iterables)
556+ # graph_detailed is not created for hierachical or colored
557+ if graph_type not in ["hierarchical" , "colored" ]:
558+ with open ("graph_detailed.dot" ) as f :
559+ graph_str = f .read ()
560+ for line in dotfile_detailed_orig :
561+ assert line in graph_str
562+
563+
564+ # examples of dot files used in the following test
565+ dotfile_detailed_iter_exec = [
566+ 'digraph structs {\n ' ,
567+ 'node [shape=record];\n ' ,
568+ 'pipemod1aIa1 [label="{IN}|{ a1 | engine | mod1.aI }|{OUT|<outoutput1> output1}"];\n ' ,
569+ 'pipemod2a1 [label="{IN|<ininput1> input1}|{ a1 | engine | mod2 }|{OUT}"];\n ' ,
570+ 'pipemod1aIa0 [label="{IN}|{ a0 | engine | mod1.aI }|{OUT|<outoutput1> output1}"];\n ' ,
571+ 'pipemod2a0 [label="{IN|<ininput1> input1}|{ a0 | engine | mod2 }|{OUT}"];\n ' ,
572+ 'pipemod1aIa0:outoutput1:e -> pipemod2a0:ininput1:w;\n ' ,
573+ 'pipemod1aIa1:outoutput1:e -> pipemod2a1:ininput1:w;\n ' ,
574+ '}' ]
575+
576+ dotfile_iter_hierarchical = [
577+ 'digraph pipe{\n ' ,
578+ ' label="pipe";\n ' ,
579+ ' pipe_mod1[label="mod1 (engine)", shape=box3d,style=filled, color=black, colorscheme=greys7 fillcolor=2];\n ' ,
580+ ' pipe_mod2[label="mod2 (engine)"];\n ' ,
581+ ' pipe_mod1 -> pipe_mod2;\n ' ,
582+ '}' ]
583+
584+ dotfile_iter_colored = [
585+ 'digraph pipe{\n ' ,
586+ ' label="pipe";\n ' ,
587+ ' pipe_mod1[label="mod1 (engine)", shape=box3d,style=filled, color=black, colorscheme=greys7 fillcolor=2];\n ' ,
588+ ' pipe_mod2[label="mod2 (engine)", style=filled, fillcolor="#FFFFC8"];\n ' ,
589+ ' pipe_mod1 -> pipe_mod2;\n ' ,
590+ '}' ]
591+
592+ dotfiles_iter = {
593+ "orig" : dotfile_orig ,
594+ "flat" : dotfile_orig ,
595+ "exec" : dotfile_orig ,
596+ "hierarchical" : dotfile_iter_hierarchical ,
597+ "colored" : dotfile_iter_colored
598+ }
599+
600+ dotfiles_detailed_iter = {
601+ "orig" : dotfile_detailed_orig ,
602+ "flat" : dotfile_detailed_orig ,
603+ "exec" : dotfile_detailed_iter_exec
604+ }
605+
606+ @pytest .mark .parametrize ("simple" , [True , False ])
607+ @pytest .mark .parametrize ("graph_type" , ['orig' , 'flat' , 'exec' , 'hierarchical' , 'colored' ])
608+ def test_write_graph_dotfile_iterables (tmpdir , graph_type , simple ):
609+ """ checking dot files for a workflow with iterables"""
610+ tmpdir .chdir ()
611+
612+ pipe = pe .Workflow (name = 'pipe' )
613+ mod1 = pe .Node (interface = EngineTestInterface (), name = 'mod1' )
614+ mod1 .iterables = ('input1' , [1 , 2 ])
615+ mod2 = pe .Node (interface = EngineTestInterface (), name = 'mod2' )
616+ pipe .connect ([(mod1 , mod2 , [('output1' , 'input1' )])])
617+ pipe .write_graph (
618+ graph2use = graph_type , simple_form = simple , format = 'dot' )
619+
620+ with open ("graph.dot" ) as f :
621+ graph_str = f .read ()
622+
623+ if simple :
624+ for line in dotfiles_iter [graph_type ]:
625+ assert line in graph_str
626+ else :
627+ # if simple=False graph.dot uses longer names
628+ for line in dotfiles_iter [graph_type ]:
629+ if graph_type in ["hierarchical" , "colored" ]:
630+ assert line .replace ("mod1 (engine)" , "mod1.EngineTestInterface.engine" ).replace (
631+ "mod2 (engine)" , "mod2.EngineTestInterface.engine" ) in graph_str
632+ else :
633+ assert line .replace (
634+ "mod1 (engine)" , "pipe.mod1.EngineTestInterface.engine" ).replace (
635+ "mod2 (engine)" , "pipe.mod2.EngineTestInterface.engine" ) in graph_str
636+
637+ # graph_detailed is not created for hierachical or colored
638+ if graph_type not in ["hierarchical" , "colored" ]:
639+ with open ("graph_detailed.dot" ) as f :
640+ graph_str = f .read ()
641+ for line in dotfiles_detailed_iter [graph_type ]:
642+ assert line in graph_str
643+
644+
645+
487646def test_io_subclass ():
488647 """Ensure any io subclass allows dynamic traits"""
489648 from nipype .interfaces .io import IOBase
0 commit comments