Fix Jinja2 template errors from invalid parameter/block names with special characters (SKY-7356) (#4644)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import uuid
|
||||
|
||||
@@ -18,3 +19,30 @@ def is_uuid(string: str) -> bool:
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def sanitize_identifier(value: str, default: str = "identifier") -> str:
|
||||
"""Sanitizes a string to be a valid Python/Jinja2 identifier.
|
||||
|
||||
Replaces non-alphanumeric characters (except underscores) with underscores,
|
||||
collapses consecutive underscores, strips leading/trailing underscores,
|
||||
and prepends an underscore if the result starts with a digit.
|
||||
|
||||
Args:
|
||||
value: The raw value to sanitize.
|
||||
default: Fallback value if everything is stripped.
|
||||
|
||||
Returns:
|
||||
A sanitized string that is a valid Python identifier.
|
||||
"""
|
||||
sanitized = re.sub(r"[^a-zA-Z0-9_]", "_", value)
|
||||
sanitized = re.sub(r"_+", "_", sanitized)
|
||||
sanitized = sanitized.strip("_")
|
||||
|
||||
if sanitized and sanitized[0].isdigit():
|
||||
sanitized = "_" + sanitized
|
||||
|
||||
if not sanitized:
|
||||
sanitized = default
|
||||
|
||||
return sanitized
|
||||
|
||||
@@ -7,6 +7,28 @@ class Constants:
|
||||
MissingVariablePattern = var_pattern = r"\{\{\s*([a-zA-Z_][a-zA-Z0-9_.\[\]'\"]*)\s*\}\}"
|
||||
|
||||
|
||||
def replace_jinja_reference(text: str, old_key: str, new_key: str) -> str:
|
||||
"""Replaces jinja-style references in a string.
|
||||
|
||||
Handles patterns like {{oldKey}}, {{oldKey.field}}, {{oldKey | filter}}, {{oldKey[0]}}
|
||||
|
||||
Args:
|
||||
text: The text to search in
|
||||
old_key: The key to replace (without braces)
|
||||
new_key: The new key to use (without braces)
|
||||
|
||||
Returns:
|
||||
The text with references replaced
|
||||
"""
|
||||
# Match {{oldKey}} or {{oldKey.something}} or {{oldKey | filter}} or {{oldKey[0]}} etc.
|
||||
# Use negative lookahead to ensure key is not followed by identifier characters,
|
||||
# which prevents matching {{keyOther}} when searching for {{key}}
|
||||
# Capture whitespace after {{ to preserve formatting (e.g., "{{ key }}" stays "{{ newKey }}")
|
||||
escaped_old_key = re.escape(old_key)
|
||||
pattern = rf"\{{\{{(\s*){escaped_old_key}(?![a-zA-Z0-9_])"
|
||||
return re.sub(pattern, rf"{{{{\1{new_key}", text)
|
||||
|
||||
|
||||
def get_missing_variables(template_source: str, template_data: dict) -> set[str]:
|
||||
# quick check - catch top-level undefineds
|
||||
env = Environment(undefined=StrictUndefined)
|
||||
|
||||
Reference in New Issue
Block a user