make jinja rendering in blocks more strict (#3827)
This commit is contained in:
38
skyvern/utils/templating.py
Normal file
38
skyvern/utils/templating.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import re
|
||||
|
||||
from jinja2 import Environment, StrictUndefined, UndefinedError, meta
|
||||
|
||||
|
||||
class Constants:
|
||||
MissingVariablePattern = var_pattern = r"\{\{\s*([a-zA-Z_][a-zA-Z0-9_.\[\]'\"]*)\s*\}\}"
|
||||
|
||||
|
||||
def get_missing_variables(template_source: str, template_data: dict) -> set[str]:
|
||||
# quick check - catch top-level undefineds
|
||||
env = Environment(undefined=StrictUndefined)
|
||||
ast = env.parse(template_source)
|
||||
undeclared_vars = meta.find_undeclared_variables(ast)
|
||||
missing_vars = undeclared_vars - set(template_data.keys())
|
||||
|
||||
# nested undefined won't be caught; let's check for those
|
||||
if not missing_vars:
|
||||
# try rendering to catch nested undefineds (dotted attributes, list/dict access)
|
||||
try:
|
||||
template = env.from_string(template_source)
|
||||
template.render(template_data)
|
||||
except UndefinedError:
|
||||
# matches: {{ var }}, {{ var.attr }}, {{ var[0] }}, {{ var['key'] }}, {{ var.attr[0] }}
|
||||
matches = re.findall(Constants.MissingVariablePattern, template_source)
|
||||
|
||||
for match in matches:
|
||||
root = match.split("[")[0].split(".")[0]
|
||||
|
||||
# just check if the 'root' of the variable exists in the provided data
|
||||
# if it does, add the whole match as missing
|
||||
if root in template_data:
|
||||
missing_vars.add(match)
|
||||
|
||||
if not missing_vars:
|
||||
raise # re-raise if we couldn't determine missing vars
|
||||
|
||||
return missing_vars
|
||||
Reference in New Issue
Block a user