dograh/api/utils/template_renderer.py

52 lines
1.9 KiB
Python
Raw Permalink Normal View History

2025-09-09 14:37:32 +05:30
"""Common template rendering utility."""
import re
from typing import Any, Dict
def render_template(template_str: str, template_var_mapping: Dict[str, Any]) -> str: # noqa: C901 complex but self-contained
"""Replace template placeholders in *template_str* with values from *template_var_mapping*.
Supported syntax:
* ``{{ variable_name }}``
* ``{{ variable_name | fallback }}``
* ``{{ variable_name | fallback:default_value }}``
If the variable is undefined and a *fallback* filter is specified the value
of *default_value* (or the *variable_name* itself if no default is given)
is used instead.
"""
if not template_str:
return template_str
# Regex matches e.g. ``{{ name }}``, ``{{ name | fallback }}``, ``{{ name | fallback:John }}``
pattern = r"\{\{\s*([^|\s}]+)(?:\s*\|\s*([^:}]+)(?::([^}]+))?)?\s*\}\}"
def _replace(match: re.Match[str]) -> str: # type: ignore[type-arg]
variable_name = match.group(1).strip()
filter_name = match.group(2).strip() if match.group(2) else None
filter_value = match.group(3).strip() if match.group(3) else None
# Pull value from context
value = template_var_mapping.get(variable_name)
# Apply filters
if filter_name == "fallback":
if value is None or value == "":
# Use explicit default value or a title-cased variable name.
value = (
filter_value if filter_value is not None else variable_name.title()
)
# Convert *None* to an empty string so that re.sub replacement works.
return str(value) if value is not None else ""
# Replace template variables
result = re.sub(pattern, _replace, template_str)
# Handle line breaks (convert literal \n to actual newlines)
result = result.replace("\\n", "\n")
return result