Initial commit
This commit is contained in:
commit
5eedbdd039
30 files changed
+2827
No files matched your search
@@ -0,0 +1,48 @@
|
||||
"""Resolve {{path.to.value}} placeholders against the workflow context."""
|
||||
|
||||
import json
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
PLACEHOLDER = re.compile(r"\{\{\s*([a-zA-Z0-9_.\-]+)\s*\}\}")
|
||||
|
||||
|
||||
class TemplateError(KeyError):
|
||||
pass
|
||||
|
||||
|
||||
def lookup(context: dict[str, Any], path: str) -> Any:
|
||||
value: Any = context
|
||||
for part in path.split("."):
|
||||
if isinstance(value, dict) and part in value:
|
||||
value = value[part]
|
||||
elif isinstance(value, list) and part.isdigit() and int(part) < len(value):
|
||||
value = value[int(part)]
|
||||
else:
|
||||
raise TemplateError(f"Cannot resolve '{{{{{path}}}}}': '{part}' not found")
|
||||
return value
|
||||
|
||||
|
||||
def _to_text(value: Any) -> str:
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
return json.dumps(value, ensure_ascii=False)
|
||||
|
||||
|
||||
def render(template: Any, context: dict[str, Any]) -> Any:
|
||||
"""Render strings, lists and dicts recursively.
|
||||
|
||||
A string that is exactly one placeholder keeps the original type
|
||||
(dict, list, number). Mixed text is rendered as a string.
|
||||
"""
|
||||
if isinstance(template, dict):
|
||||
return {key: render(value, context) for key, value in template.items()}
|
||||
if isinstance(template, list):
|
||||
return [render(item, context) for item in template]
|
||||
if not isinstance(template, str):
|
||||
return template
|
||||
|
||||
whole = PLACEHOLDER.fullmatch(template.strip())
|
||||
if whole:
|
||||
return lookup(context, whole.group(1))
|
||||
return PLACEHOLDER.sub(lambda m: _to_text(lookup(context, m.group(1))), template)
|
||||
Reference in new issue
Block a user