Skip to content

Commit

Permalink
feat: 支持 MAKO 渲染嵌套级联的字典和列表对象
Browse files Browse the repository at this point in the history
  • Loading branch information
normal-wls committed Aug 13, 2024
1 parent 6ba7245 commit 98e66a7
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
3 changes: 3 additions & 0 deletions bamboo_engine/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class Settings:

RERUN_INDEX_OFFSET = 0

# 当字符串是纯mako字符串时,是否自动渲染成对象,默认还是会渲染成字符串
ENABLE_RENDER_OBJ_BY_MAKO_STRING = False

PIPELINE_EXCLUSIVE_GATEWAY_EXPR_FUNC = default_expr_func

PIPELINE_EXCLUSIVE_GATEWAY_STRATEGY = ExclusiveGatewayStrategy.ONLY.value
Expand Down
35 changes: 33 additions & 2 deletions bamboo_engine/template/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from mako import lexer, codegen
from mako.exceptions import MakoException

from bamboo_engine.config import Settings
from bamboo_engine.utils.mako_utils.checker import check_mako_template_safety
from bamboo_engine.utils.mako_utils.exceptions import ForbiddenMakoTemplateException
from bamboo_engine.utils import mako_safety
Expand All @@ -34,6 +35,8 @@
logger = logging.getLogger("root")
# find mako template(format is ${xxx},and ${}# not in xxx, # may raise memory error)
TEMPLATE_PATTERN = re.compile(r"\${[^${}#]+}")
NESTED_INDEX_STR_PATTERN = r'^(\w+)(?:\[(?:"\w+"|\'\w+\'|\d+)\])+$'
INDEX_STR_PATTERN = r'\[("\w+"|\'\w+\'|\d+)\]'


class Template:
Expand Down Expand Up @@ -143,8 +146,21 @@ def _render_string(self, string: str, context: dict) -> str:
templates = self._get_string_templates(string)

# TODO keep render return object, here only process simple situation
if len(templates) == 1 and templates[0] == string and deformat_var_key(string) in context:
return context[deformat_var_key(string)]
if len(templates) == 1 and templates[0] == string:
deformat_string = deformat_var_key(string)

# directly get value from context
if deformat_string in context:
return context[deformat_var_key(string)]

# nested get value from tuple/list/dict
match = re.match(NESTED_INDEX_STR_PATTERN, deformat_string)
if Settings.ENABLE_RENDER_OBJ_BY_MAKO_STRING and match and match.group(1) in context:
try:
return self._nested_get_value_from_context(context[match.group(1)], deformat_string)
except Exception as e:
logger.exception("render obj from nested mako string failed: {}".format(e))
pass

for tpl in templates:
try:
Expand All @@ -163,6 +179,21 @@ def _render_string(self, string: str, context: dict) -> str:
string = string.replace(tpl, resolved)
return string

@staticmethod
def _nested_get_value_from_context(context: Any, string: str) -> Any:
"""
从上下文中获取嵌套数据的值,仅支持 list/tuple/dict,且需保证索引合法,外层需要处理异常
"""
cur_context = context
for key in re.findall(INDEX_STR_PATTERN, string):
if isinstance(cur_context, dict):
cur_context = cur_context[key.strip("'\"")]
elif isinstance(cur_context, (list, tuple)):
cur_context = cur_context[int(key)]
else:
raise ValueError("invalid context type: {}".format(type(cur_context)))
return cur_context

@staticmethod
def _render_template(template: str, context: dict) -> Any:
"""
Expand Down
17 changes: 17 additions & 0 deletions tests/template/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,23 @@ def test_render():
syntax_error_template = Template("${a:b}")
assert syntax_error_template.render({}) == "${a:b}"

default_enable_value = Settings.ENABLE_RENDER_OBJ_BY_MAKO_STRING
Settings.ENABLE_RENDER_OBJ_BY_MAKO_STRING = True

simple_list_template = Template("${a}")
assert simple_list_template.render({"a": [1, 2, 3]}) == [1, 2, 3]

nested_list_template = Template("${a[0][3]}")
assert nested_list_template.render({"a": [[1, 2, 3, {"a": "b"}], [5, 6, 7, 8]]}) == {"a": "b"}

simple_dict_template = Template("${a}")
assert simple_dict_template.render({"a": {"a": "b"}}) == {"a": "b"}

nested_dict_template = Template("${a[0][3]['a']}")
assert nested_dict_template.render({"a": [[1, 2, 3, {"a": [1,2,3]}], [5, 6, 7, 8]]}) == [1,2,3]

Settings.ENABLE_RENDER_OBJ_BY_MAKO_STRING = default_enable_value


def test_render__with_sandbox():

Expand Down

0 comments on commit 98e66a7

Please sign in to comment.