Skip to content
This repository was archived by the owner on Jun 9, 2020. It is now read-only.

Commit 39a8e51

Browse files
authored
Merge pull request #9 from dleehr/master
General improvements for workflow building
2 parents 5fd96b5 + fc563e8 commit 39a8e51

File tree

5 files changed

+164
-5
lines changed

5 files changed

+164
-5
lines changed

cwlgen/__init__.py

+15
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,12 @@ def __init__(self, expression_lib=None):
337337
Requirement.__init__(self, 'InlineJavascriptRequirement')
338338
self.expressionLib = expression_lib
339339

340+
def _to_dict(self):
341+
if self.expressionLib:
342+
return {'expressionLib': [self.expressionLib]}
343+
else:
344+
return {}
345+
340346

341347
class DockerRequirement(Requirement):
342348
'''
@@ -377,6 +383,15 @@ def _to_dict(self):
377383
return {p: v for p, v in vars(self).items() if p.startswith('docker') and v is not None}
378384

379385

386+
class SubworkflowFeatureRequirement(Requirement):
387+
388+
def __init__(self):
389+
Requirement.__init__(self, 'SubworkflowFeatureRequirement')
390+
391+
def _to_dict(self):
392+
return dict()
393+
394+
380395
class Namespaces(object):
381396
"""
382397
Define different namespace for the description.

cwlgen/workflow.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ def __init__(self):
1515
self.steps = []
1616
self.inputs = []
1717
self.outputs = []
18+
self.requirements = []
1819
self._path = None
1920

21+
2022
def export(self, outfile=None):
2123
"""
2224
Export the workflow in CWL either on STDOUT or in outfile.
@@ -46,6 +48,14 @@ def export(self, outfile=None):
4648
for out in self.outputs:
4749
cwl_workflow['outputs'][out.id] = out.get_dict()
4850

51+
# Add requirements.
52+
requirements = {}
53+
for requirement in self.requirements:
54+
requirement.add(requirements)
55+
56+
if requirements:
57+
cwl_workflow['requirements'] = requirements
58+
4959
# Write CWL file in YAML
5060
if outfile is None:
5161
six.print_(CWL_SHEBANG, "\n", sep='')
@@ -185,7 +195,7 @@ def __init__(self, param_id, outputSource, label=None, secondary_files=None, par
185195
self.outputSource = outputSource
186196

187197
############################
188-
# Workflow contruction classes
198+
# Workflow construction classes
189199

190200

191201
class File:
@@ -196,6 +206,8 @@ def __init__(self, path):
196206
self.path = path
197207

198208

209+
210+
199211
class Variable:
200212
"""
201213
An output variable from a workflow step
@@ -216,6 +228,8 @@ def store(self):
216228
return
217229

218230

231+
232+
219233
class StepRun:
220234
"""
221235
Result of adding a step into a workflow
@@ -233,10 +247,13 @@ def __init__(self, workflow, id, tool, params):
233247
step.inputs.append(WorkflowStepInput(i, default=j))
234248
elif isinstance(j, Variable):
235249
step.inputs.append(WorkflowStepInput(i, src=j.path()))
250+
elif isinstance(j, InputParameter):
251+
self.workflow.inputs.append(j),
252+
step.inputs.append(WorkflowStepInput(j.id, src=j.id))
236253
elif isinstance(j, File):
254+
# This is just used as a stub, the 'path' inside the file doesn't do anything
237255
self.workflow.inputs.append(InputParameter(i, param_type="File"))
238256
step.inputs.append(WorkflowStepInput(i, src=i))
239-
240257
for o in tool.outputs:
241258
step.outputs.append(o.id)
242259

test/int_tool.cwl

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env cwl-runner
2+
3+
cwlVersion: v1.0
4+
id: tool_id
5+
label: a_label
6+
baseCommand: cat
7+
class: CommandLineTool
8+
doc: "super_doc"
9+
stdin: "in"
10+
stderr: "err"
11+
stdout: "out"
12+
inputs:
13+
INTEGER:
14+
doc: 'documentation_in'
15+
inputBinding:
16+
loadContents: True
17+
position: 0
18+
prefix: --input
19+
separate: True
20+
itemSeparator: ';'
21+
valueFrom: here
22+
shellQuote: True
23+
type: int
24+
outputs:
25+
OUTPUT1:
26+
label: label_out
27+
doc: 'documentation_out'
28+
outputBinding:
29+
glob: "find"
30+
loadContents: True
31+
outputEval: "eval"
32+
type: File

test/test_unit_cwlgen.py

+23
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,18 @@ def test_init(self):
193193
self.assertEqual(self.js_req.req_class, 'InlineJavascriptRequirement')
194194
self.assertEqual(self.js_req.expressionLib, 'expression')
195195

196+
def test_add(self):
197+
tool = {}
198+
self.js_req.add(tool)
199+
self.assertEqual(tool, {'InlineJavascriptRequirement': {'expressionLib': ['expression']}})
200+
201+
def test_add_without_lib(self):
202+
tool = {}
203+
req = cwlgen.InlineJavascriptReq()
204+
req.add(tool)
205+
self.assertEqual(tool, {'InlineJavascriptRequirement': {}})
206+
207+
196208
class TestDockerRequirement(unittest.TestCase):
197209

198210
def setUp(self):
@@ -215,6 +227,17 @@ def test_export(self):
215227
dockerImageId='id', dockerOutputDir='dir')
216228

217229

230+
class TestSubworkflowFeatureRequirement(unittest.TestCase):
231+
232+
def setUp(self):
233+
self.req = cwlgen.SubworkflowFeatureRequirement()
234+
235+
def test_add(self):
236+
tool = {}
237+
self.req.add(tool)
238+
self.assertEqual(tool, {'SubworkflowFeatureRequirement': {}})
239+
240+
218241
########### Main ###########
219242

220243
if __name__ == "__main__":

test/test_unit_workflow.py

+75-3
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,22 @@
1010
import os
1111
import filecmp
1212
import unittest
13+
from tempfile import NamedTemporaryFile
1314

1415
# External libraries
1516
import cwlgen
1617

1718
# Class(es) ------------------------------
1819

19-
class TestCommandLineTool(unittest.TestCase):
2020

21+
class TestWorkflow(unittest.TestCase):
2122

22-
def test_build(self):
23+
def capture_tempfile(self, func):
24+
with NamedTemporaryFile() as f:
25+
func(f.name)
26+
return f.read()
27+
28+
def test_generates_workflow_two_steps(self):
2329

2430
w = cwlgen.Workflow()
2531
tool = cwlgen.parse_cwl("test/import_cwl.cwl")
@@ -29,4 +35,70 @@ def test_build(self):
2935
o1 = w.add('step-a', tool, {"INPUT1" : f})
3036
o2 = w.add('step-b', tool, {"INPUT1" : o1['OUTPUT1']})
3137
o2['OUTPUT1'].store()
32-
w.export("test.cwl")
38+
generated = self.capture_tempfile(w.export)
39+
expected = b"""#!/usr/bin/env cwl-runner
40+
41+
class: Workflow
42+
cwlVersion: v1.0
43+
inputs:
44+
INPUT1: {id: INPUT1, type: File}
45+
outputs:
46+
step-b_OUTPUT1: {id: step-b_OUTPUT1, outputSource: step-b/OUTPUT1, type: File}
47+
steps:
48+
step-a:
49+
id: step-a
50+
in: {INPUT1: INPUT1}
51+
out: [OUTPUT1]
52+
run: test/import_cwl.cwl
53+
step-b:
54+
id: step-b
55+
in: {INPUT1: step-a/OUTPUT1}
56+
out: [OUTPUT1]
57+
run: test/import_cwl.cwl
58+
"""
59+
self.assertEqual(expected, generated)
60+
61+
def test_generates_workflow_int_inputs(self):
62+
63+
w = cwlgen.Workflow()
64+
tool = cwlgen.parse_cwl("test/int_tool.cwl")
65+
66+
i = cwlgen.workflow.InputParameter('INTEGER', param_type='int')
67+
o1 = w.add('step', tool, {"INTEGER": i})
68+
o1['OUTPUT1'].store()
69+
70+
expected = b"""#!/usr/bin/env cwl-runner
71+
72+
class: Workflow
73+
cwlVersion: v1.0
74+
inputs:
75+
INTEGER: {id: INTEGER, type: int}
76+
outputs:
77+
step_OUTPUT1: {id: step_OUTPUT1, outputSource: step/OUTPUT1, type: File}
78+
steps:
79+
step:
80+
id: step
81+
in: {INTEGER: INTEGER}
82+
out: [OUTPUT1]
83+
run: test/int_tool.cwl
84+
"""
85+
generated = self.capture_tempfile(w.export)
86+
self.assertEqual(expected, generated)
87+
88+
89+
def test_add_requirements(self):
90+
w = cwlgen.Workflow()
91+
req = cwlgen.InlineJavascriptReq()
92+
w.requirements.append(req)
93+
generated = self.capture_tempfile(w.export)
94+
expected = b"""#!/usr/bin/env cwl-runner
95+
96+
class: Workflow
97+
cwlVersion: v1.0
98+
inputs: {}
99+
outputs: {}
100+
requirements:
101+
InlineJavascriptRequirement: {}
102+
"""
103+
self.assertEqual(expected, generated)
104+

0 commit comments

Comments
 (0)