Skip to content

Commit 9eeff23

Browse files
authored
Merge pull request #652 from wtsi-hgi/fix-648
Fix #628 and improve parameter reference error messages
2 parents d9a3a01 + 25d69c0 commit 9eeff23

File tree

1 file changed

+51
-30
lines changed

1 file changed

+51
-30
lines changed

cwltool/expression.py

+51-30
Original file line numberDiff line numberDiff line change
@@ -120,55 +120,76 @@ def scanner(scan): # type: (Text) -> List[int]
120120
return None
121121

122122

123-
def next_seg(remain, obj): # type: (Text, Any) -> Any
124-
if remain:
125-
m = segment_re.match(remain)
123+
def next_seg(parsed_string, remaining_string, current_value): # type: (Text, Text, Any) -> Any
124+
if remaining_string:
125+
m = segment_re.match(remaining_string)
126+
next_segment_str = m.group(0)
127+
126128
key = None # type: Union[Text, int]
127-
if m.group(0)[0] == '.':
128-
key = m.group(0)[1:]
129-
elif m.group(0)[1] in ("'", '"'):
130-
key = m.group(0)[2:-2].replace("\\'", "'").replace('\\"', '"')
129+
if next_segment_str[0] == '.':
130+
key = next_segment_str[1:]
131+
elif next_segment_str[1] in ("'", '"'):
132+
key = next_segment_str[2:-2].replace("\\'", "'").replace('\\"', '"')
131133

132134
if key:
133-
if isinstance(obj, list) and key == "length" and not remain[m.end(0):]:
134-
return len(obj)
135-
if not isinstance(obj, dict):
136-
raise WorkflowException(" is a %s, cannot index on string '%s'" % (type(obj).__name__, key))
137-
if key not in obj:
138-
raise WorkflowException(" does not contain key '%s'" % key)
135+
if isinstance(current_value, list) and key == "length" and not remaining_string[m.end(0):]:
136+
return len(current_value)
137+
if not isinstance(current_value, dict):
138+
raise WorkflowException("%s is a %s, cannot index on string '%s'" % (parsed_string, type(current_value).__name__, key))
139+
if key not in current_value:
140+
raise WorkflowException("%s does not contain key '%s'" % (parsed_string, key))
139141
else:
140142
try:
141-
key = int(m.group(0)[1:-1])
143+
key = int(next_segment_str[1:-1])
142144
except ValueError as v:
143145
raise WorkflowException(u(str(v)))
144-
if not isinstance(obj, list):
145-
raise WorkflowException(" is a %s, cannot index on int '%s'" % (type(obj).__name__, key))
146-
if key >= len(obj):
147-
raise WorkflowException(" list index %i out of range" % key)
146+
if not isinstance(current_value, list):
147+
raise WorkflowException("%s is a %s, cannot index on int '%s'" % (parsed_string, type(current_value).__name__, key))
148+
if key >= len(current_value):
149+
raise WorkflowException("%s list index %i out of range" % (parsed_string, key))
150+
148151
try:
149-
return next_seg(remain[m.end(0):], obj[key])
150-
except WorkflowException as w:
151-
raise WorkflowException("%s%s" % (m.group(0), w))
152+
return next_seg(parsed_string + remaining_string, remaining_string[m.end(0):], current_value[key])
153+
except KeyError:
154+
raise WorkflowException("%s doesn't have property %s" % (parsed_string, key))
152155
else:
153-
return obj
156+
return current_value
154157

155158

156159
def evaluator(ex, jslib, obj, fullJS=False, timeout=None, force_docker_pull=False, debug=False, js_console=False):
157160
# type: (Text, Text, Dict[Text, Any], bool, int, bool, bool, bool) -> JSON
158161
m = param_re.match(ex)
162+
163+
expression_parse_exception = None
164+
expression_parse_succeeded = False
165+
159166
if m:
160-
if m.end(1)+1 == len(ex) and m.group(1) == "null":
167+
first_symbol = m.group(1)
168+
first_symbol_end = m.end(1)
169+
170+
if first_symbol_end + 1 == len(ex) and first_symbol == "null":
161171
return None
162172
try:
163-
return next_seg(m.group(0)[m.end(1) - m.start(0):-1], obj[m.group(1)])
164-
except Exception as w:
165-
raise WorkflowException("%s%s" % (m.group(1), w))
166-
elif fullJS:
173+
if obj.get(first_symbol) is None:
174+
raise WorkflowException("%s is not defined" % first_symbol)
175+
176+
return next_seg(first_symbol, ex[first_symbol_end:-1], obj[first_symbol])
177+
except WorkflowException as w:
178+
expression_parse_exception = w
179+
else:
180+
expression_parse_succeeded = True
181+
182+
if fullJS and not expression_parse_succeeded:
167183
return sandboxjs.execjs(ex, jslib, timeout=timeout, force_docker_pull=force_docker_pull, debug=debug, js_console=js_console)
168184
else:
169-
raise sandboxjs.JavascriptException(
170-
"Syntax error in parameter reference '%s' or used Javascript code without specifying InlineJavascriptRequirement.",
171-
ex)
185+
if expression_parse_exception is not None:
186+
raise sandboxjs.JavascriptException(
187+
"Syntax error in parameter reference '%s': %s. This could be due to using Javascript code without specifying InlineJavascriptRequirement." % \
188+
(ex[1:-1], expression_parse_exception))
189+
else:
190+
raise sandboxjs.JavascriptException(
191+
"Syntax error in parameter reference '%s'. This could be due to using Javascript code without specifying InlineJavascriptRequirement." % \
192+
ex)
172193

173194

174195
def interpolate(scan, rootvars,

0 commit comments

Comments
 (0)