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
Extensible plugin system for adding custom template syntax, processing logic, and integration with external tools. Includes built-in extensions for internationalization, loop controls, expression statements, and debugging.
Base class for implementing custom template extensions with hooks for preprocessing, parsing, and code generation.
class Extension:
def __init__(self, environment):
"""
Initialize extension.
Parameters:
environment: Jinja2 environment instance
"""
def bind(self, environment):
"""
Bind extension to different environment.
Parameters:
environment: New Jinja2 environment instance
Returns:
Extension: New extension instance bound to environment
"""
def preprocess(self, source, name, filename=None):
"""
Preprocess template source before parsing.
Parameters:
source: Template source code
name: Template name
filename: Template filename
Returns:
str: Preprocessed template source
"""
def filter_stream(self, stream):
"""
Filter token stream before parsing.
Parameters:
stream: Token stream iterator
Returns:
Iterator: Filtered token stream
"""
def parse(self, parser):
"""
Parse extension tags and return AST nodes.
Parameters:
parser: Jinja2 parser instance
Returns:
Node: AST node for extension functionality
"""
def attr(self, name, lineno=None):
"""
Create extension attribute node.
Parameters:
name: Attribute name
lineno: Line number for debugging
Returns:
Node: Attribute access AST node
"""
def call_method(self, name, args=None, kwargs=None, dyn_args=None, dyn_kwargs=None, lineno=None):
"""
Create extension method call node.
Parameters:
name: Method name
args: Method arguments
kwargs: Method keyword arguments
dyn_args: Dynamic arguments
dyn_kwargs: Dynamic keyword arguments
lineno: Line number for debugging
Returns:
Node: Method call AST node
"""Built-in extension for internationalization and localization support using gettext-style translation functions.
class InternationalizationExtension(Extension):
"""
Extension for internationalization support.
Adds:
- {% trans %}...{% endtrans %} blocks for translatable text
- {% pluralize %} for plural forms within trans blocks
- Automatic message extraction for translation tools
Usage:
env = Environment(extensions=['jinja2.ext.i18n'])
env.install_gettext_translations(translations)
"""Usage example:
from jinja2 import Environment
import gettext
# Setup translations
translations = gettext.translation('messages', 'locale', languages=['es'])
env = Environment(extensions=['jinja2.ext.i18n'])
env.install_gettext_translations(translations)
template_str = '''
{% trans %}Hello World!{% endtrans %}
{% trans count=items|length %}
There is {{ count }} item.
{% pluralize %}
There are {{ count }} items.
{% endtrans %}
'''Extension that adds the {% do %} tag for executing expressions without output.
class ExprStmtExtension(Extension):
"""
Extension that adds {% do %} tag for expression statements.
Adds:
- {% do expression %} for executing expressions without output
- Useful for variable assignments and side effects
Usage:
env = Environment(extensions=['jinja2.ext.do'])
"""Usage example:
from jinja2 import Environment
env = Environment(extensions=['jinja2.ext.do'])
template_str = '''
{% set items = [] %}
{% do items.append('first') %}
{% do items.extend(['second', 'third']) %}
Items: {{ items | join(', ') }}
'''Extension that adds {% break %} and {% continue %} statements for loop control.
class LoopControlsExtension(Extension):
"""
Extension that adds loop control statements.
Adds:
- {% break %} to exit loops early
- {% continue %} to skip to next loop iteration
Usage:
env = Environment(extensions=['jinja2.ext.loopcontrols'])
"""Usage example:
from jinja2 import Environment
env = Environment(extensions=['jinja2.ext.loopcontrols'])
template_str = '''
{% for item in items %}
{% if item is number and item < 0 %}
{% continue %}
{% endif %}
{% if item is string and item == 'STOP' %}
{% break %}
{% endif %}
Item: {{ item }}
{% endfor %}
'''Extension that adds the {% debug %} tag for debugging template context and variables.
class DebugExtension(Extension):
"""
Extension that adds {% debug %} tag for template debugging.
Adds:
- {% debug %} to print current template context
- Useful for development and troubleshooting
Usage:
env = Environment(extensions=['jinja2.ext.debug'])
"""Usage example:
from jinja2 import Environment
env = Environment(extensions=['jinja2.ext.debug'])
template_str = '''
User: {{ user.name }}
{% debug %}
Age: {{ user.age }}
'''Extensions can be loaded by name or class when creating environments.
# Load by string name
env = Environment(extensions=['jinja2.ext.i18n', 'jinja2.ext.do'])
# Load by class
from jinja2.ext import InternationalizationExtension, ExprStmtExtension
env = Environment(extensions=[InternationalizationExtension, ExprStmtExtension])
# Add after environment creation
env.add_extension('jinja2.ext.loopcontrols')
env.add_extension(DebugExtension)Example of creating a custom extension that adds a {% cache %} tag:
from jinja2 import nodes
from jinja2.ext import Extension
class CacheExtension(Extension):
tags = {'cache'} # Tags handled by this extension
def parse(self, parser):
lineno = next(parser.stream).lineno
# Parse cache key
cache_key = parser.parse_expression()
# Parse optional timeout
timeout = None
if parser.stream.current.test('name:for'):
next(parser.stream) # consume 'for'
timeout = parser.parse_expression()
# Parse body
node = parser.parse_statements(['name:endcache'], drop_needle=True)
# Create cache node
return self.call_method('_cache_support',
[cache_key, timeout, nodes.List(node)],
lineno=lineno)
def _cache_support(self, cache_key, timeout, body):
"""Runtime cache support method."""
# Implementation would check cache, render if needed, store result
cache = getattr(self.environment, '_cache', {})
if cache_key in cache:
return cache[cache_key]
# Render body and cache result
result = ''.join(body)
cache[cache_key] = result
if not hasattr(self.environment, '_cache'):
self.environment._cache = cache
return result
# Usage
env = Environment(extensions=[CacheExtension])
template_str = '''
{% cache 'expensive_computation' for 300 %}
{{ expensive_function() }}
{% endcache %}
'''Extensions can modify parsing behavior, add global functions, and integrate with the compilation process:
class AdvancedExtension(Extension):
def __init__(self, environment):
super().__init__(environment)
# Add global functions
environment.globals['custom_func'] = self.custom_function
def preprocess(self, source, name, filename=None):
# Modify source before parsing
return source.replace('[[', '{%').replace(']]', '%}')
def filter_stream(self, stream):
# Modify token stream
for token in stream:
if token.type == 'name' and token.value == 'old_keyword':
token = token._replace(value='new_keyword')
yield token
def custom_function(self, *args, **kwargs):
"""Custom global function available in templates."""
return f"Custom: {args} {kwargs}"def babel_extract(fileobj, keywords, comment_tags, options):
"""
Babel message extraction function for i18n extension.
Parameters:
fileobj: File-like object containing template source
keywords: Extraction keywords
comment_tags: Comment tags to extract
options: Extraction options
Returns:
Iterator: Extracted messages with line numbers and context
"""class ExtensionEnvironment:
"""
Extension execution environment providing access to parsing and compilation context.
Attributes:
environment: Jinja2 environment instance
parser: Current parser instance (during parsing)
compiler: Current compiler instance (during compilation)
"""
class ExtensionRegistry:
"""
Registry for managing loaded extensions and their capabilities.
Attributes:
extensions: Dictionary of loaded extension instances
tags: Set of all registered tag names
"""