Skip to content

Commit 799ba19

Browse files
authored
Merge pull request #165 from StackStorm/fix-jinja-block
Fix Jinja evaluator to evaluate block expression correctly
2 parents 66f460b + 937ea97 commit 799ba19

File tree

3 files changed

+46
-26
lines changed

3 files changed

+46
-26
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Fixed
1313
~~~~~
1414

1515
* Allow tasks in the same transition with a "fail" command to run. (bug fix)
16+
* Fix Jinja block expression to render correctly. (bug fix)
1617

1718
0.5
1819
---

orquesta/expressions/jinja.py

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -142,42 +142,47 @@ def validate(cls, text):
142142

143143
@classmethod
144144
def _evaluate_and_expand(cls, text, data=None):
145-
output = str_util.unicode(text)
146145
exprs = cls._regex_parser.findall(text)
147146
block_exprs = cls._regex_block_parser.findall(text)
148147
ctx = cls.contextualize(data)
149148
opts = {'undefined_to_none': False}
150149

151150
try:
152-
# Evaluate inline jinja expressions first.
153-
for expr in exprs:
154-
stripped = cls.strip_delimiter(expr)
155-
compiled = cls._jinja_env.compile_expression(stripped, **opts)
156-
result = compiled(**ctx)
157-
158-
if inspect.isgenerator(result):
159-
result = list(result)
160-
161-
if isinstance(result, six.string_types):
162-
result = cls._evaluate_and_expand(result, data)
163-
164-
# For StrictUndefined values, UndefinedError only gets raised when the value is
165-
# accessed, not when it gets created. The simplest way to access it is to try
166-
# and cast it to string. When StrictUndefined is cast to str below, this will
167-
# raise an exception with error description.
168-
if not isinstance(result, jinja2.runtime.StrictUndefined):
169-
if len(exprs) > 1 or block_exprs or len(output) > len(expr):
170-
output = output.replace(expr, str_util.unicode(result, force=True))
171-
else:
172-
output = str_util.unicode(result)
173-
174-
# Evaluate jinja block(s) after inline expressions are evaluated.
175-
if block_exprs and isinstance(output, six.string_types):
176-
output = cls._jinja_env.from_string(output).render(ctx)
151+
# If there is a Jinja block expression in the text, then process the whole text.
152+
if block_exprs:
153+
expr = text
154+
output = cls._jinja_env.from_string(expr).render(ctx)
155+
output = str_util.unicode(output)
177156

178157
# Traverse and evaulate again in case additional inline epxressions are
179158
# introduced after the jinja block is evaluated.
180159
output = cls._evaluate_and_expand(output, data)
160+
else:
161+
# The output will first be the original text and the expressions
162+
# will be substituted by the evaluated value.
163+
output = str_util.unicode(text)
164+
165+
# Evaluate inline jinja expressions first.
166+
for expr in exprs:
167+
stripped = cls.strip_delimiter(expr)
168+
compiled = cls._jinja_env.compile_expression(stripped, **opts)
169+
result = compiled(**ctx)
170+
171+
if inspect.isgenerator(result):
172+
result = list(result)
173+
174+
if isinstance(result, six.string_types):
175+
result = cls._evaluate_and_expand(result, data)
176+
177+
# For StrictUndefined values, UndefinedError only gets raised when the value is
178+
# accessed, not when it gets created. The simplest way to access it is to try
179+
# and cast it to string. When StrictUndefined is cast to str below, this will
180+
# raise an exception with error description.
181+
if not isinstance(result, jinja2.runtime.StrictUndefined):
182+
if len(exprs) > 1 or block_exprs or len(output) > len(expr):
183+
output = output.replace(expr, str_util.unicode(result, force=True))
184+
else:
185+
output = str_util.unicode(result)
181186

182187
except jinja2.exceptions.UndefinedError as e:
183188
msg = "Unable to evaluate expression '%s'. %s: %s"

orquesta/tests/unit/expressions/test_jinja_eval_raw_blocks.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ def test_block_eval(self):
4343

4444
self.assertEqual('abc', self.evaluator.evaluate(expr, data))
4545

46+
def test_block_eval_complex_data(self):
47+
expr = '{% for i in ctx().x %}{{ i.k }}{{ ctx().z }}{% endfor %}'
48+
49+
data = {
50+
'x': [
51+
{'k': 'a'},
52+
{'k': 'b'},
53+
{'k': 'c'}
54+
],
55+
'z': '->'
56+
}
57+
58+
self.assertEqual('a->b->c->', self.evaluator.evaluate(expr, data))
59+
4660
def test_block_eval_undefined(self):
4761
expr = '{% for i in ctx().x %}{{ ctx().y }}{% endfor %}'
4862

0 commit comments

Comments
 (0)