CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-jinja2

A very fast and expressive template engine for Python applications

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

error-handling-debugging.mddocs/

Error Handling and Debugging

Comprehensive exception hierarchy and debugging tools for template development including detailed error messages, source location tracking, and runtime debugging capabilities.

Capabilities

Exception Hierarchy

Jinja2 provides a comprehensive exception hierarchy for different types of template errors.

class TemplateError(Exception):
    """
    Base class for all template-related errors.
    
    Attributes:
        message: Error message
        lineno: Line number where error occurred (if available)
        name: Template name where error occurred (if available)
        filename: Template filename where error occurred (if available)
    """

class TemplateNotFound(TemplateError):
    """
    Raised when a template cannot be found.
    
    Attributes:
        name: Template name that was not found
        message: Error message
    """

class TemplatesNotFound(TemplateNotFound):
    """
    Raised when multiple templates cannot be found (used by select_template).
    
    Attributes:
        names: List of template names that were not found
        message: Error message including all attempted names
    """

class TemplateSyntaxError(TemplateError):
    """
    Raised when template syntax is malformed.
    
    Attributes:
        message: Detailed syntax error message
        lineno: Line number of syntax error
        name: Template name
        filename: Template filename
        source: Template source code (if available)
    """

class TemplateRuntimeError(TemplateError):
    """
    Raised during template execution for runtime errors.
    
    Attributes:
        message: Runtime error message
        lineno: Line number where error occurred
        name: Template name
        filename: Template filename
    """

class TemplateAssertionError(TemplateRuntimeError):
    """
    Raised when template assertion fails ({% assert %} tag).
    
    Attributes:
        message: Assertion error message
        lineno: Line number of failed assertion
        name: Template name
        filename: Template filename
    """

class UndefinedError(TemplateRuntimeError):
    """
    Raised when undefined variable is used inappropriately.
    
    Attributes:
        message: Undefined error message
        name: Variable name that was undefined
        exc_info: Original exception info (if available)
    """

class SecurityError(TemplateRuntimeError):
    """
    Raised when template tries to perform insecure operations in sandbox mode.
    
    Attributes:
        message: Security violation description
        lineno: Line number where violation occurred
        name: Template name
        filename: Template filename
    """

class FilterArgumentError(TemplateRuntimeError):
    """
    Raised when filter is called with inappropriate arguments.
    
    Attributes:
        message: Argument error description
        filter_name: Name of filter that failed (if available)
        lineno: Line number where error occurred
        name: Template name
        filename: Template filename
    """

Undefined Types for Debugging

Specialized undefined types that provide different behaviors for debugging and error handling.

class Undefined:
    """
    Default undefined type that raises UndefinedError on most operations.
    
    Methods:
        _undefined_hint: Get hint about undefined variable
        _undefined_obj: Get undefined object info
        _undefined_name: Get undefined variable name
        _undefined_exception: Get undefined exception type
    """

class StrictUndefined(Undefined):
    """
    Undefined that raises errors on any operation including __str__ and __iter__.
    More strict than default Undefined for catching undefined usage early.
    """

class DebugUndefined(Undefined):
    """
    Undefined that shows debug information when printed instead of raising errors.
    Useful for template development and debugging.
    
    When rendered shows: {{ undefined value 'variable_name' }}
    """

class ChainableUndefined(Undefined):
    """
    Undefined that doesn't raise errors on getattr/getitem operations.
    Allows chaining operations on undefined values without immediate errors.
    
    Example: {{ undefined_obj.attr.nested_attr }} won't raise until final rendering
    """

def make_logging_undefined(logger=None, base=None):
    """
    Create an undefined class that logs undefined variable access.
    
    Parameters:
        logger: Logger instance to use (default: creates new logger)
        base: Base undefined class (default: Undefined)
        
    Returns:
        class: Custom undefined class that logs access attempts
    """

Usage examples:

from jinja2 import Environment, DebugUndefined, StrictUndefined

# Debug mode - shows undefined variables without errors
debug_env = Environment(undefined=DebugUndefined)
template = debug_env.from_string('Hello {{ name }}! Age: {{ user.age }}')
result = template.render()
# Result: Hello {{ undefined value 'name' }}! Age: {{ undefined value 'user' }}

# Strict mode - raises errors immediately
strict_env = Environment(undefined=StrictUndefined)
template = strict_env.from_string('Hello {{ name }}!')
try:
    result = template.render()  # Raises UndefinedError
except UndefinedError as e:
    print(f'Undefined variable: {e}')

# Logging undefined access
import logging
logging.basicConfig(level=logging.WARNING)
LoggingUndefined = make_logging_undefined()
log_env = Environment(undefined=LoggingUndefined)
template = log_env.from_string('Hello {{ name }}!')
result = template.render()  # Logs warning about undefined 'name'

Error Context and Debugging

Tools for understanding and debugging template errors with detailed context information.

def get_template_module(env, template_name):
    """
    Get template module for introspection and debugging.
    
    Parameters:
        env: Jinja2 environment
        template_name: Name of template to introspect
        
    Returns:
        TemplateModule: Module with template exports and metadata
    """

def render_template_with_context(template, **context):
    """
    Render template and return both result and execution context.
    
    Parameters:
        template: Template instance
        **context: Template context variables
        
    Returns:
        tuple: (rendered_output, execution_context)
    """

Error Handling Patterns

Graceful Error Handling

Handle template errors gracefully in production applications:

from jinja2 import Environment, TemplateNotFound, TemplateSyntaxError, TemplateRuntimeError
from jinja2 import FileSystemLoader, select_autoescape
import logging

logger = logging.getLogger(__name__)

class RobustTemplateRenderer:
    def __init__(self):
        self.env = Environment(
            loader=FileSystemLoader('templates'),
            autoescape=select_autoescape(),
            undefined=ChainableUndefined  # Don't fail on undefined variables
        )
    
    def render_template(self, template_name, fallback_template=None, **context):
        """
        Render template with comprehensive error handling.
        
        Parameters:
            template_name: Primary template to render
            fallback_template: Fallback template if primary fails
            **context: Template context variables
            
        Returns:
            str: Rendered template or error message
        """
        try:
            template = self.env.get_template(template_name)
            return template.render(**context)
            
        except TemplateNotFound as e:
            logger.error(f'Template not found: {e}')
            if fallback_template:
                try:
                    template = self.env.get_template(fallback_template)
                    return template.render(**context)
                except Exception as fallback_error:
                    logger.error(f'Fallback template failed: {fallback_error}')
            return f'<p>Template {template_name} not found</p>'
            
        except TemplateSyntaxError as e:
            logger.error(f'Template syntax error in {e.name} at line {e.lineno}: {e.message}')
            return f'<p>Template syntax error in {template_name}</p>'
            
        except TemplateRuntimeError as e:
            logger.error(f'Template runtime error in {e.name} at line {e.lineno}: {e.message}')
            return f'<p>Template runtime error in {template_name}</p>'
            
        except Exception as e:
            logger.error(f'Unexpected error rendering {template_name}: {e}')
            return f'<p>Error rendering template {template_name}</p>'

# Usage
renderer = RobustTemplateRenderer()
result = renderer.render_template('user_profile.html', 'default_profile.html', user=user_data)

Development Error Display

Detailed error display for development environments:

from jinja2 import Environment, TemplateSyntaxError, TemplateRuntimeError
from jinja2 import DictLoader, DebugUndefined
import traceback
import html

class DevelopmentTemplateRenderer:
    def __init__(self):
        self.env = Environment(
            loader=DictLoader({}),
            undefined=DebugUndefined,  # Show undefined variables
            auto_reload=True           # Reload templates on changes
        )
    
    def render_with_debug(self, template_source, **context):
        """
        Render template with detailed debugging information.
        
        Parameters:
            template_source: Template source code
            **context: Template context variables
            
        Returns:
            str: Rendered template or detailed error page
        """
        try:
            template = self.env.from_string(template_source)
            return template.render(**context)
            
        except TemplateSyntaxError as e:
            return self._format_syntax_error(e, template_source)
            
        except TemplateRuntimeError as e:
            return self._format_runtime_error(e, template_source, context)
            
        except Exception as e:
            return self._format_generic_error(e, template_source, context)
    
    def _format_syntax_error(self, error, source):
        """Format syntax error with source context."""
        lines = source.split('\n')
        error_line = error.lineno - 1 if error.lineno else 0
        
        context_lines = []
        for i, line in enumerate(lines):
            line_num = i + 1
            marker = ' >>> ' if i == error_line else '     '
            context_lines.append(f'{marker}{line_num:3d}: {html.escape(line)}')
        
        return f'''
        <h2>Template Syntax Error</h2>
        <p><strong>Error:</strong> {html.escape(str(error))}</p>
        <p><strong>Line:</strong> {error.lineno}</p>
        <h3>Template Source:</h3>
        <pre>{"".join(context_lines)}</pre>
        '''
    
    def _format_runtime_error(self, error, source, context):
        """Format runtime error with context information."""
        tb = traceback.format_exc()
        
        return f'''
        <h2>Template Runtime Error</h2>
        <p><strong>Error:</strong> {html.escape(str(error))}</p>
        <p><strong>Line:</strong> {error.lineno}</p>
        <h3>Context Variables:</h3>
        <pre>{html.escape(str(context))}</pre>
        <h3>Template Source:</h3>
        <pre>{html.escape(source)}</pre>
        <h3>Full Traceback:</h3>
        <pre>{html.escape(tb)}</pre>
        '''
    
    def _format_generic_error(self, error, source, context):
        """Format generic error with all available information."""
        tb = traceback.format_exc()
        
        return f'''
        <h2>Template Error</h2>
        <p><strong>Error Type:</strong> {type(error).__name__}</p>
        <p><strong>Error:</strong> {html.escape(str(error))}</p>
        <h3>Context Variables:</h3>
        <pre>{html.escape(str(context))}</pre>
        <h3>Template Source:</h3>
        <pre>{html.escape(source)}</pre>
        <h3>Full Traceback:</h3>
        <pre>{html.escape(tb)}</pre>
        '''

# Usage
dev_renderer = DevelopmentTemplateRenderer()
result = dev_renderer.render_with_debug(
    'Hello {{ user.name }}! You have {{ user.messages | lenght }} messages.',
    user={'name': 'Alice'}
)

Template Validation

Validate templates before rendering to catch errors early:

from jinja2 import Environment, TemplateSyntaxError
from jinja2.meta import find_undeclared_variables
import ast

class TemplateValidator:
    def __init__(self, env):
        self.env = env
    
    def validate_template(self, source, required_vars=None, available_vars=None):
        """
        Validate template syntax and variable usage.
        
        Parameters:
            source: Template source code
            required_vars: Set of variables that must be used
            available_vars: Set of variables that are available
            
        Returns:
            dict: Validation results with errors and warnings
        """
        results = {
            'valid': True,
            'errors': [],
            'warnings': [],
            'undeclared_vars': set(),
            'syntax_ok': True
        }
        
        # Check syntax
        try:
            ast_tree = self.env.parse(source)
            results['syntax_ok'] = True
        except TemplateSyntaxError as e:
            results['valid'] = False
            results['syntax_ok'] = False
            results['errors'].append(f'Syntax error at line {e.lineno}: {e.message}')
            return results  # Can't continue without valid syntax
        
        # Find undeclared variables
        try:
            undeclared = find_undeclared_variables(ast_tree)
            results['undeclared_vars'] = undeclared
            
            # Check against available variables
            if available_vars is not None:
                missing_vars = undeclared - set(available_vars)
                if missing_vars:
                    results['warnings'].extend([
                        f'Undeclared variable: {var}' for var in missing_vars
                    ])
            
            # Check required variables are used
            if required_vars is not None:
                unused_required = set(required_vars) - undeclared
                if unused_required:
                    results['warnings'].extend([
                        f'Required variable not used: {var}' for var in unused_required
                    ])
                    
        except Exception as e:
            results['errors'].append(f'Variable analysis failed: {e}')
        
        return results
    
    def validate_template_file(self, template_name, **validation_kwargs):
        """Validate template loaded from file."""
        try:
            template = self.env.get_template(template_name)
            return self.validate_template(template.source, **validation_kwargs)
        except Exception as e:
            return {
                'valid': False,
                'errors': [f'Failed to load template {template_name}: {e}'],
                'warnings': [],
                'undeclared_vars': set(),
                'syntax_ok': False
            }

# Usage
from jinja2 import FileSystemLoader

env = Environment(loader=FileSystemLoader('templates'))
validator = TemplateValidator(env)

# Validate template source
results = validator.validate_template(
    'Hello {{ user.name }}! You have {{ user.message_count }} messages.',
    available_vars=['user'],
    required_vars=['user']
)

if results['valid']:
    print('Template is valid')
else:
    print('Template validation failed:')
    for error in results['errors']:
        print(f'  ERROR: {error}')
    for warning in results['warnings']:
        print(f'  WARNING: {warning}')

Types

class ErrorContext:
    """
    Context information for template errors.
    
    Attributes:
        template_name: Name of template where error occurred
        line_number: Line number of error
        column_number: Column number of error (if available)
        source_line: Source code line where error occurred
        context_vars: Template context variables at time of error
        stack_trace: Full stack trace information
    """

class DebugInfo:
    """
    Debug information for template execution.
    
    Attributes:
        template_name: Template name
        execution_time: Template rendering time
        context_size: Size of template context
        undefined_vars: List of undefined variables accessed
        filter_calls: List of filters called during rendering
        include_chain: Chain of included/extended templates
    """

docs

bytecode-caching.md

environment-templates.md

error-handling-debugging.md

extensions-custom-syntax.md

filters-data-processing.md

index.md

meta-analysis.md

native-types.md

security-sandboxing.md

template-loaders.md

tests-conditionals.md

tile.json