Skip to content

Commit ae92ff5

Browse files
committed
Merge pull request #20 from chrisfilo/enh/saveworkflow
Enh/saveworkflow
2 parents b84da54 + 4a9ef91 commit ae92ff5

File tree

4 files changed

+117
-2
lines changed

4 files changed

+117
-2
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Next release
33
* ENH: New interfaces: nipy.Trim
44

55
* ENH: Allow control over terminal output for commandline interfaces
6+
* ENH: Added preliminary support for generating Python code from Workflows.
67

78
Release 0.7.0 (Dec 18, 2012)
89
============================

doc/users/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
function_interface
3232
mapnode_and_iterables
3333
model_specification
34+
saving_workflows
3435

3536

3637

doc/users/saving_workflows.rst

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
.. _saving_workflows:
2+
3+
===================================================
4+
Saving Workflows and Nodes to a file (experimental)
5+
===================================================
6+
7+
On top of the standard way of saving (i.e. serializing) objects in Python
8+
(see `pickle <http://docs.python.org/2/library/pickle.html>`_) Nipype
9+
provides methods to turn Workflows and nodes into human readable code.
10+
This is useful if you want to save a Workflow that you have generated
11+
on the fly for future use.
12+
13+
To generate Python code for a Workflow use the export method:
14+
15+
.. testcode::
16+
17+
from nipype.interfaces.fsl import BET, ImageMaths
18+
from nipype.pipeline.engine import Workflow, Node, MapNode, format_node
19+
from nipype.interfaces.utility import Function, IdentityInterface
20+
21+
bet = Node(BET(), name='bet')
22+
bet.iterables = ('frac', [0.3, 0.4])
23+
24+
bet2 = MapNode(BET(), name='bet2', iterfield=['infile'])
25+
bet2.iterables = ('frac', [0.4, 0.5])
26+
27+
maths = Node(ImageMaths(), name='maths')
28+
29+
def testfunc(in1):
30+
"""dummy func
31+
"""
32+
out = in1 + 'foo' + "out1"
33+
return out
34+
35+
funcnode = Node(Function(input_names=['a'], output_names=['output'], function=testfunc),
36+
name='testfunc')
37+
funcnode.inputs.in1 = '-sub'
38+
func = lambda x: x
39+
40+
inode = Node(IdentityInterface(fields=['a']), name='inode')
41+
42+
wf = Workflow('testsave')
43+
wf.add_nodes([bet2])
44+
wf.connect(bet, 'mask_file', maths, 'in_file')
45+
wf.connect(bet2, ('mask_file', func), maths, 'in_file2')
46+
wf.connect(inode, 'a', funcnode, 'in1')
47+
wf.connect(funcnode, 'output', maths, 'op_string')
48+
49+
wf.export()
50+
51+
This will create a file "outputtestsave.py" with the following content:
52+
53+
.. testcode::
54+
55+
from nipype.pipeline.engine import Workflow, Node, MapNode
56+
from nipype.interfaces.utility import IdentityInterface
57+
from nipype.interfaces.utility import Function
58+
from nipype.utils.misc import getsource
59+
from nipype.interfaces.fsl.preprocess import BET
60+
from nipype.interfaces.fsl.utils import ImageMaths
61+
# Functions
62+
func = lambda x: x
63+
# Workflow
64+
testsave = Workflow("testsave")
65+
# Node: testsave.inode
66+
inode = Node(IdentityInterface(fields=['a'], mandatory_inputs=True), name="inode")
67+
# Node: testsave.testfunc
68+
testfunc = Node(Function(input_names=['a'], output_names=['output']), name="testfunc")
69+
def testfunc_1(in1):
70+
"""dummy func
71+
"""
72+
out = in1 + 'foo' + "out1"
73+
return out
74+
75+
testfunc.inputs.function_str = getsource(testfunc_1)
76+
testfunc.inputs.ignore_exception = False
77+
testfunc.inputs.in1 = '-sub'
78+
testsave.connect(inode, "a", testfunc, "in1")
79+
# Node: testsave.bet2
80+
bet2 = MapNode(BET(), iterfield=['infile'], name="bet2")
81+
bet2.iterables = ('frac', [0.4, 0.5])
82+
bet2.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'}
83+
bet2.inputs.ignore_exception = False
84+
bet2.inputs.output_type = 'NIFTI_GZ'
85+
bet2.inputs.terminal_output = 'stream'
86+
# Node: testsave.bet
87+
bet = Node(BET(), name="bet")
88+
bet.iterables = ('frac', [0.3, 0.4])
89+
bet.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'}
90+
bet.inputs.ignore_exception = False
91+
bet.inputs.output_type = 'NIFTI_GZ'
92+
bet.inputs.terminal_output = 'stream'
93+
# Node: testsave.maths
94+
maths = Node(ImageMaths(), name="maths")
95+
maths.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'}
96+
maths.inputs.ignore_exception = False
97+
maths.inputs.output_type = 'NIFTI_GZ'
98+
maths.inputs.terminal_output = 'stream'
99+
testsave.connect(bet2, ('mask_file', func), maths, "in_file2")
100+
testsave.connect(bet, "mask_file", maths, "in_file")
101+
testsave.connect(testfunc, "output", maths, "op_string")
102+
103+
The file is ready to use and includes all the necessary imports.
104+
105+
.. include:: ../links_names.txt

nipype/pipeline/engine.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -543,17 +543,22 @@ def write_hierarchical_dotfile(self, dotfilename=None, colored=True,
543543
else:
544544
logger.info(dotstr)
545545

546-
def export(self, prefix="output", format="python", include_config=False):
546+
def export(self, filename=None, prefix="output", format="python", include_config=False):
547547
"""Export object into a different format
548548
549549
Parameters
550550
----------
551+
filename: string
552+
file to save the code to; overrides prefix
551553
552554
prefix: string
553555
prefix to use for output file
554556
555557
format: string
556558
one of "python"
559+
560+
include_config: boolean
561+
whether to include node and workflow config values
557562
"""
558563
formats = ["python"]
559564
if format not in formats:
@@ -606,7 +611,10 @@ def export(self, prefix="output", format="python", include_config=False):
606611
for function in functions:
607612
functionlines.append(cPickle.loads(function).rstrip())
608613
all_lines = importlines + functionlines + lines
609-
with open('%s%s.py' % (prefix, self.name), 'wt') as fp:
614+
615+
if not filename:
616+
filename = '%s%s.py' % (prefix, self.name)
617+
with open(filename, 'wt') as fp:
610618
#fp.writelines('\n'.join([line.replace('\n', '\\n') for line in all_lines]))
611619
fp.writelines('\n'.join(all_lines))
612620
return all_lines

0 commit comments

Comments
 (0)