A very fast and expressive template engine for Python applications
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Template introspection functions for analyzing template dependencies and variable usage. Useful for dependency tracking, caching systems, and development tools.
Analyze templates to find all variables that will be looked up from the context at runtime.
def find_undeclared_variables(ast):
"""
Returns a set of all variables in the AST that will be looked up from
the context at runtime.
Because at compile time it's not known which variables will be used
depending on the path the execution takes at runtime, all variables
are returned.
Parameters:
ast: Template AST node from Environment.parse()
Returns:
set: Set of variable names that will be looked up from context
Raises:
TemplateAssertionError: During compilation if template is invalid
"""Find all templates referenced by extends, includes, and imports in a template.
def find_referenced_templates(ast):
"""
Finds all the referenced templates from the AST.
Returns an iterator over all the hardcoded template extensions, inclusions
and imports. If dynamic inheritance or inclusion is used, None will be
yielded for those entries.
Parameters:
ast: Template AST node from Environment.parse()
Yields:
str or None: Template names found, or None for dynamic references
"""from jinja2 import Environment, meta
env = Environment()
# Simple template with variables
template_source = '{{ user.name }} has {{ count }} items'
ast = env.parse(template_source)
variables = meta.find_undeclared_variables(ast)
print(variables) # {'user', 'count'}
# Template with loops and conditions
template_source = '''
{% for item in items %}
{{ item.name }} - {{ item.price }}
{% endfor %}
{% if total > 100 %}
Discount: {{ discount }}
{% endif %}
'''
ast = env.parse(template_source)
variables = meta.find_undeclared_variables(ast)
print(variables) # {'items', 'total', 'discount'}from jinja2 import Environment, meta
env = Environment()
# Template with static dependencies
template_source = '''
{% extends "base.html" %}
{% include "header.html" %}
{% from "macros.html" import button %}
'''
ast = env.parse(template_source)
dependencies = list(meta.find_referenced_templates(ast))
print(dependencies) # ['base.html', 'header.html', 'macros.html']
# Template with dynamic dependencies
template_source = '''
{% extends layout_template %}
{% include "static.html" %}
{% include dynamic_include %}
'''
ast = env.parse(template_source)
dependencies = list(meta.find_referenced_templates(ast))
print(dependencies) # [None, 'static.html', None]from jinja2 import Environment, meta
import os
def analyze_template_dependencies(template_path):
"""Analyze a template file and return its variable and template dependencies."""
env = Environment()
with open(template_path) as f:
source = f.read()
ast = env.parse(source)
# Find variables needed from context
variables = meta.find_undeclared_variables(ast)
# Find referenced templates
templates = [t for t in meta.find_referenced_templates(ast) if t is not None]
return {
'variables': variables,
'templates': templates,
'has_dynamic_dependencies': None in meta.find_referenced_templates(ast)
}
# Example usage
dependencies = analyze_template_dependencies('templates/user_profile.html')
print(f"Variables needed: {dependencies['variables']}")
print(f"Template dependencies: {dependencies['templates']}")
print(f"Has dynamic deps: {dependencies['has_dynamic_dependencies']}")from jinja2 import Environment, meta
def validate_template_context(template_source, provided_context):
"""Validate that all required variables are provided in context."""
env = Environment()
ast = env.parse(template_source)
required_vars = meta.find_undeclared_variables(ast)
missing_vars = required_vars - set(provided_context.keys())
if missing_vars:
raise ValueError(f"Missing required variables: {missing_vars}")
return True
# Example usage
template = "Hello {{ name }}, you have {{ count }} messages"
context = {"name": "Alice", "count": 5}
try:
validate_template_context(template, context)
print("All variables provided!")
except ValueError as e:
print(f"Validation error: {e}")from jinja2 import Environment, meta
import os
from pathlib import Path
def get_template_dependency_graph(template_dir):
"""Build dependency graph for all templates in a directory."""
env = Environment()
dependency_graph = {}
for template_file in Path(template_dir).glob('**/*.html'):
template_path = str(template_file.relative_to(template_dir))
with open(template_file) as f:
source = f.read()
ast = env.parse(source)
dependencies = [
dep for dep in meta.find_referenced_templates(ast)
if dep is not None
]
dependency_graph[template_path] = dependencies
return dependency_graph
# Example usage for build system
deps = get_template_dependency_graph('templates/')
for template, dependencies in deps.items():
print(f"{template} depends on: {dependencies}")from jinja2 import meta
# Access meta functions through the meta module
variables = meta.find_undeclared_variables(ast)
templates = meta.find_referenced_templates(ast)