Skip to content

Commit ebc433c

Browse files
author
Peter Amstutz
committed
Pure-Python parameter interpolation
1 parent 3d1fa17 commit ebc433c

File tree

2 files changed

+138
-4
lines changed

2 files changed

+138
-4
lines changed

cwltool/expression.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import schema_salad.validate as validate
1111
import schema_salad.ref_resolver
1212
import sandboxjs
13+
import re
1314

1415
_logger = logging.getLogger("cwltool")
1516

@@ -85,11 +86,55 @@ class DR(object):
8586

8687
raise WorkflowException("Unknown expression engine '%s'" % ex["engine"])
8788

89+
seg_symbol = r"""[^[\].(){} ]+"""
90+
seg_single = r"""\['([^']|\\')+'\]"""
91+
seg_double = r"""\["([^"]|\\")+"\]"""
92+
seg_index = r"""\[[0-9]+\]"""
93+
segments = r"(\.%s|%s|%s|%s)" % (seg_symbol, seg_single, seg_double, seg_index)
94+
segment_re = re.compile(segments)
95+
param_re = re.compile(r"\$\((%s)%s*\)" % (seg_symbol, segments))
96+
97+
def next_seg(remain, obj):
98+
if remain:
99+
print remain
100+
m = segment_re.match(remain)
101+
if m.group(0)[0] == '.':
102+
return next_seg(remain[m.end(0):], obj[m.group(0)[1:]])
103+
else:
104+
key = m.group(0)[2:-2].replace("\\'", "'").replace('\\"', '"')
105+
return next_seg(remain[m.end(0):], obj[key])
106+
else:
107+
return obj
108+
109+
def param_interpolate(ex, obj, strip=True):
110+
m = param_re.search(ex)
111+
if m:
112+
print "=", m.group(0), "/", m.group(0)[m.end(1) - m.start(0):-1]
113+
leaf = next_seg(m.group(0)[m.end(1) - m.start(0):-1], obj[m.group(1)])
114+
if strip and len(ex.strip()) == len(m.group(0)):
115+
return leaf
116+
else:
117+
leaf = json.dumps(leaf)
118+
if leaf[0] == '"':
119+
leaf = leaf[1:-1]
120+
return ex[0:m.start(0)] + leaf + param_interpolate(ex[m.end(0):], obj, False)
121+
else:
122+
return ex
123+
124+
88125
def do_eval(ex, jobinput, requirements, outdir, tmpdir, context=None, pull_image=True):
89126
if isinstance(ex, dict) and "engine" in ex and "script" in ex:
90127
return exeval(ex, jobinput, requirements, outdir, tmpdir, context, pull_image)
91128
if isinstance(ex, basestring):
92129
for r in requirements:
93130
if r["class"] == "InlineJavascriptRequirement":
94131
return sandboxjs.interpolate(ex, jshead(r.get("expressionLib", []), jobinput, context, tmpdir, outdir))
132+
return param_interpolate(ex, {
133+
"inputs": jobinput,
134+
"self": context,
135+
"runtime": {
136+
"tmpdir": tmpdir,
137+
"outdir": outdir
138+
}
139+
})
95140
return ex

tests/test_examples.py

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,100 @@
11
import unittest
22
import cwltool.draft2tool as tool
3+
import cwltool.expression as expr
34

4-
# Right now, everything in cwltool is tested through conformance tests.
5+
class TestParamMatching(unittest.TestCase):
6+
def test_params(self):
7+
self.assertTrue(expr.param_re.match("$(foo)"))
8+
self.assertTrue(expr.param_re.match("$(foo.bar)"))
9+
self.assertTrue(expr.param_re.match("$(foo['bar'])"))
10+
self.assertTrue(expr.param_re.match("$(foo[\"bar\"])"))
11+
self.assertTrue(expr.param_re.match("$(foo.bar.baz)"))
12+
self.assertTrue(expr.param_re.match("$(foo['bar'].baz)"))
13+
self.assertTrue(expr.param_re.match("$(foo['bar']['baz'])"))
14+
self.assertTrue(expr.param_re.match("$(foo['b\\'ar']['baz'])"))
15+
self.assertTrue(expr.param_re.match("$(foo['b ar']['baz'])"))
516

6-
class TestExamples(unittest.TestCase):
7-
def test_cat1(self):
8-
pass
17+
self.assertFalse(expr.param_re.match("$(foo.[\"bar\"])"))
18+
self.assertFalse(expr.param_re.match("$(.foo[\"bar\"])"))
19+
self.assertFalse(expr.param_re.match("$(foo [\"bar\"])"))
20+
self.assertFalse(expr.param_re.match("$( foo[\"bar\"])"))
21+
self.assertFalse(expr.param_re.match("$(foo[bar].baz)"))
22+
self.assertFalse(expr.param_re.match("$(foo['bar\"].baz)"))
23+
self.assertFalse(expr.param_re.match("$(foo['bar].baz)"))
24+
self.assertFalse(expr.param_re.match("${foo}"))
25+
self.assertFalse(expr.param_re.match("$(foo.bar"))
26+
self.assertFalse(expr.param_re.match("$foo.bar)"))
27+
self.assertFalse(expr.param_re.match("$foo.b ar)"))
28+
self.assertFalse(expr.param_re.match("$foo.b\'ar)"))
29+
30+
inputs = {
31+
"foo": {
32+
"bar": {
33+
"baz": "zab1"
34+
},
35+
"b ar": {
36+
"baz": 2
37+
},
38+
"b'ar": {
39+
"baz": True
40+
},
41+
'b"ar': {
42+
"baz": None
43+
}
44+
}
45+
}
46+
47+
self.assertEqual(expr.param_interpolate("$(foo)", inputs), inputs["foo"])
48+
49+
for pattern in ("$(foo.bar)",
50+
"$(foo['bar'])",
51+
"$(foo[\"bar\"])"):
52+
self.assertEqual(expr.param_interpolate(pattern, inputs), inputs["foo"]["bar"])
53+
54+
for pattern in ("$(foo.bar.baz)",
55+
"$(foo['bar'].baz)",
56+
"$(foo['bar'][\"baz\"])",
57+
"$(foo.bar['baz'])"):
58+
self.assertEqual(expr.param_interpolate(pattern, inputs), "zab1")
59+
60+
self.assertEqual(expr.param_interpolate("$(foo['b ar'].baz)", inputs), 2)
61+
self.assertEqual(expr.param_interpolate("$(foo['b\\'ar'].baz)", inputs), True)
62+
self.assertEqual(expr.param_interpolate("$(foo[\"b\\'ar\"].baz)", inputs), True)
63+
self.assertEqual(expr.param_interpolate("$(foo['b\\\"ar'].baz)", inputs), None)
64+
65+
66+
for pattern in ("-$(foo.bar)",
67+
"-$(foo['bar'])",
68+
"-$(foo[\"bar\"])"):
69+
self.assertEqual(expr.param_interpolate(pattern, inputs), """-{"baz": "zab1"}""")
70+
71+
for pattern in ("-$(foo.bar.baz)",
72+
"-$(foo['bar'].baz)",
73+
"-$(foo['bar'][\"baz\"])",
74+
"-$(foo.bar['baz'])"):
75+
self.assertEqual(expr.param_interpolate(pattern, inputs), "-zab1")
76+
77+
self.assertEqual(expr.param_interpolate("-$(foo['b ar'].baz)", inputs), "-2")
78+
self.assertEqual(expr.param_interpolate("-$(foo['b\\'ar'].baz)", inputs), "-true")
79+
self.assertEqual(expr.param_interpolate("-$(foo[\"b\\'ar\"].baz)", inputs), "-true")
80+
self.assertEqual(expr.param_interpolate("-$(foo['b\\\"ar'].baz)", inputs), "-null")
81+
82+
83+
for pattern in ("$(foo.bar) $(foo.bar)",
84+
"$(foo['bar']) $(foo['bar'])",
85+
"$(foo[\"bar\"]) $(foo[\"bar\"])"):
86+
self.assertEqual(expr.param_interpolate(pattern, inputs), """{"baz": "zab1"} {"baz": "zab1"}""")
87+
88+
for pattern in ("$(foo.bar.baz) $(foo.bar.baz)",
89+
"$(foo['bar'].baz) $(foo['bar'].baz)",
90+
"$(foo['bar'][\"baz\"]) $(foo['bar'][\"baz\"])",
91+
"$(foo.bar['baz']) $(foo.bar['baz'])"):
92+
self.assertEqual(expr.param_interpolate(pattern, inputs), "zab1 zab1")
93+
94+
self.assertEqual(expr.param_interpolate("$(foo['b ar'].baz) $(foo['b ar'].baz)", inputs), "2 2")
95+
self.assertEqual(expr.param_interpolate("$(foo['b\\'ar'].baz) $(foo['b\\'ar'].baz)", inputs), "true true")
96+
self.assertEqual(expr.param_interpolate("$(foo[\"b\\'ar\"].baz) $(foo[\"b\\'ar\"].baz)", inputs), "true true")
97+
self.assertEqual(expr.param_interpolate("$(foo['b\\\"ar'].baz) $(foo['b\\\"ar'].baz)", inputs), "null null")
998

1099
if __name__ == '__main__':
11100
unittest.main()

0 commit comments

Comments
 (0)