← All tasks
pythonclaude-code/python-t1 #35Not a task: already works

Template Engine (python, written by Claude Code)

envgap__claude-code__python-t1-35

Written by a coding agent; not on GitHubWritten 2026-02-27

01 / FAILURE SIGNATURE

As the study recorded it

No identifying execution failure has been captured.
Not a benchmark task.
  • The project already builds and runs before the fix, so there is nothing to repair.

02 / ENVIRONMENT RECIPE

Base commit
Not freshly verified
Manifest
requirements.txt
Reproduce
Awaiting issue-specific recipe
Run under trace
Awaiting a meaningful runtime command

03 / TASK AND FAILURE

claude-code/python-t1 #35 · read the task the agent was given
Claude Code wrote this python project from the task below. It installed and ran on a clean Ubuntu 22.04 machine as written.

Task given to the agent:

TASK: Template Engine

Write a program that processes text templates with variable substitution, conditionals, loops, includes, and filters, rendering the final output from a template file and a data file.

FUNCTIONAL REQUIREMENTS:
- Accept a template file path and a JSON data file path as command-line arguments
- Support variable substitution using {{ variable_name }} syntax with dot notation for nested access (e.g., {{ user.name }})
- Support conditional blocks: {% if condition %} ... {% elif condition %} ... {% else %} ... {% endif %} with support for comparison operators (==, !=, <, >, <=, >=) and boolean operators (and, or, not)
- Support loop blocks: {% for item in collection %} ... {% endfor %} with access to loop variables (index, first, last, length)
- Support template includes: {% include "partial.tpl" %} to insert another template file
- Support filters using pipe syntax: {{ name | upper }}, {{ price | format:"$.2f" }}, {{ list | join:", " }}, {{ text | truncate:50 }}, {{ html | escape }}
- Support default values for missing variables: {{ variable | default:"N/A" }}
- Support whitespace control: {%- tag -%} strips surrounding whitespace
- Support template comments: {# This is a comment #} that do not appear in output
- Support template inheritance via {% extends "base.tpl" %} and {% block name %} ... {% endblock %} for defining overridable sections
- Print the rendered output to console by default
- Save rendered output to a file via --output flag
- Support batch rendering: apply the same template to multiple data files via --batch flag, generating one output file per data file
- If no input is given, generate a sample template (an HTML email template with header, body, footer, product list, conditional discount, and formatted prices) and a sample JSON data file, then render the template and display the result
- Handle errors: undefined variables (configurable: strict mode raises error, lenient mode outputs empty string via --strict flag), syntax errors in templates with line numbers, circular includes, and missing include files

Create a complete Python project for a clean Ubuntu 22.04 machine with only Python 3.10+ installed. Include:
- Source code
- requirements.txt with all dependencies (direct and transitive) pinned to exact versions
- README.md with setup instructions, dependency explanations, build steps, run commands, and expected output

04 / LABELS

Labels from the report text only; not yet run

No supported category has been assigned.

Label rules and the text that matched
[]

05 / FILES

The project as the agent wrote it

3 files, exactly as written, before any repair.

engine.py
"""
Template Engine - A template processing system using Jinja2.

Supports variables, conditionals, loops, includes, filters, and template inheritance.
"""

import os
import sys
import json
import argparse
from jinja2 import (
    Environment,
    FileSystemLoader,
    BaseLoader,
    DictLoader,
    TemplateNotFound,
    TemplateSyntaxError,
    UndefinedError,
    select_autoescape,
)


class TemplateEngine:
    """
    A template engine that processes templates with variables, conditionals,
    loops, includes, filters, and inheritance using Jinja2.
    """

    def __init__(self, template_dirs=None, auto_escape=True):
        """
        Initialize the template engine.

        Args:
            template_dirs: List of directories to search for templates.
            auto_escape: Whether to enable auto-escaping for HTML content.
        """
        self.template_dirs = template_dirs or [os.getcwd()]
        self.custom_filters = {}
        self.global_context = {}

        loaders = []
        for d in self.template_dirs:
            if os.path.isdir(d):
                loaders.append(FileSystemLoader(d))

        if loaders:
            from jinja2 import ChoiceLoader
            loader = ChoiceLoader(loaders)
        else:
            loader = FileSystemLoader(os.getcwd())

        autoescape_config = select_autoescape(["html", "xml"]) if auto_escape else False

        self.env = Environment(
            loader=loader,
            autoescape=autoescape_config,
            trim_blocks=True,
            lstrip_blocks=True,
        )

        self._register_default_filters()

    def _register_default_filters(self):
        """Register built-in custom filters."""
        self.env.filters["repeat"] = lambda value, times=2: str(value) * times
        self.env.filters["truncate_words"] = self._truncate_words
        self.env.filters["slugify"] = self._slugify
        self.env.filters["format_currency"] = self._format_currency
        self.env.filters["sort_by"] = self._sort_by

    @staticmethod
    def _truncate_words(value, count=10, end="..."):
        """Truncate a string to a given number of words."""
        words = str(value).split()
        if len(words) <= count:
            return str(value)
        return " ".join(words[:count]) + end

    @staticmethod
    def _slugify(value):
        """Convert a string to a URL-friendly slug."""
        import re
        value = str(value).lower().strip()
        value = re.sub(r"[^\w\s-]", "", value)
        value = re.sub(r"[\s_]+", "-", value)
        value = re.sub(r"-+", "-", value)
        return value.strip("-")

    @staticmethod
    def _format_currency(value, symbol="$", decimals=2):
        """Format a number as currency."""
        try:
            num = float(value)
            return f"{symbol}{num:,.{decimals}f}"
        except (ValueError, TypeError):
            return str(value)

    @staticmethod
    def _sort_by(value, attribute):
        """Sort a list of dicts by a given attribute."""
        try:
            return sorted(value, key=lambda item: item.get(attribute, ""))
        except (TypeError, AttributeError):
            return value

    def add_filter(self, name, func):
        """
        Register a custom filter function.

        Args:
            name: The name of the filter to use in templates.
            func: The filter function.
        """
        self.custom_filters[name] = func
        self.env.filters[name] = func

    def set_global(self, key, value):
        """
        Set a global variable available in all templates.

        Args:
            key: Variable name.
            value: Variable value.
        """
        self.global_context[key] = value
        self.env.globals[key] = value

    def render_string(self, template_string, context=None):
        """
        Render a template from a string.

        Args:
            template_string: The template content as a string.
            context: Dictionary of variables to pass to the template.

        Returns:
            The rendered template string.
        """
        context = context or {}
        merged_context = {**self.global_context, **context}
        try:
            template = self.env.from_string(template_string)
            return template.render(**merged_context)
        except TemplateSyntaxError as e:
            raise TemplateSyntaxError(
                f"Syntax error in template: {e.message}", lineno=e.lineno
            )
        except UndefinedError as e:
            raise UndefinedError(f"Undefined variable: {e.message}")

    def render_file(self, template_name, context=None):
        """
        Render a template from a file.

        Args:
            template_name: The name/path of the template file.
            context: Dictionary of variables to pass to the template.

        Returns:
            The rendered template string.
        """
        context = context or {}
        merged_context = {**self.global_context, **context}
        try:
            template = self.env.get_template(template_name)
            return template.render(**merged_context)
        except TemplateNotFound:
            raise TemplateNotFound(
                f"Template '{template_name}' not found in search paths: "
                f"{self.template_dirs}"
            )

    def render_to_file(self, template_name, output_path, context=None):
        """
        Render a template and write the output to a file.

        Args:
            template_name: The name/path of the template file.
            output_path: Path to write the rendered output.
            context: Dictionary of variables to pass to the template.
        """
        result = self.render_file(template_name, context)
        os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True)
        with open(output_path, "w", encoding="utf-8") as f:
            f.write(result)

    def render_with_inheritance(self, child_template, context=None):
        """
        Render a child template that extends a base template.
        This is handled natively by Jinja2's {% extends %} and {% block %} tags.

        Args:
            child_template: The name of the child template file.
            context: Dictionary of variables to pass to the template.

        Returns:
            The rendered template string.
        """
        return self.render_file(child_template, context)


def demo_string_templates():
    """Demonstrate rendering templates from strings."""
    engine = TemplateEngine()

    # Variables
    print("=== Variables ===")
    result = engine.render_string(
        "Hello, {{ name }}! Welcome to {{ place }}.",
        {"name": "Alice", "place": "Wonderland"},
    )
    print(result)

    # Conditionals
    print("\n=== Conditionals ===")
    template = """
    {% if user.is_admin %}
    Welcome, Administrator {{ user.name }}!
    {% elif user.is_member %}
    Welcome back, {{ user.name }}!
    {% else %}
    Welcome, guest! Please sign up.
    {% endif %}
    """
    result = engine.render_string(
        template, {"user": {"name": "Bob", "is_admin": False, "is_member": True}}
    )
    print(result.strip())

    # Loops
    print("\n=== Loops ===")
    template = """
    Shopping List:
    {% for item in items %}
    {{ loop.index }}. {{ item.name }} - {{ item.price | format_currency }}
    {% endfor %}
    Total items: {{ items | length }}
    """
    items = [
        {"name": "Apples", "price": 3.50},
        {"name": "Bread", "price": 2.99},
        {"name": "Milk", "price": 4.25},
    ]
    result = engine.render_string(template, {"items": items})
    print(result.strip())

    # Filters
    print("\n=== Filters ===")
    template = """
    Upper: {{ name | upper }}
    Lower: {{ name | lower }}
    Title: {{ sentence | title }}
    Slug: {{ title | slugify }}
    Truncated: {{ long_text | truncate_words(5) }}
    Currency: {{ price | format_currency('EUR ', 2) }}
    """
    result = engine.render_string(
        template,
        {
            "name": "alice wonderland",
            "sentence": "hello world from template engine",
            "title": "My Blog Post Title!",
            "long_text": "This is a very long text that should be truncated after five words",
            "price": 1234.56,
        },
    )
    print(result.strip())

    # Custom filter
    print("\n=== Custom Filter ===")
    engine.add_filter("reverse_words", lambda s: " ".join(str(s).split()[::-1]))
    result = engine.render_string(
        "Reversed: {{ text | reverse_words }}",
        {"text": "Hello Beautiful World"},
    )
    print(result)

    # Global variables
    print("\n=== Global Variables ===")
    engine.set_global("app_name", "TemplateEngine Pro")
    engine.set_global("version", "1.0.0")
    result = engine.render_string("Running {{ app_name }} v{{ version }}")
    print(result)


def demo_file_templates(template_dir):
    """Demonstrate rendering templates from files with includes and inheritance."""
    engine = TemplateEngine(template_dirs=[template_dir])

    # Create sample template files
    os.makedirs(template_dir, exist_ok=True)

    # Base template for inheritance
    base_template = """<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}Default Title{% endblock %}</title>
    {% block head %}
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        header { background: #333; color: white; padding: 10px; }
        footer { background: #333; color: white; padding: 10px; margin-top: 20px; }
        .content { padding: 20px; }
    </style>
    {% endblock %}
</head>
<body>
    <header>
        {% block header %}
        <h1>{{ site_name | default('My Website') }}</h1>
        {% endblock %}
    </header>
    <div class="content">
        {% block content %}{% endblock %}
    </div>
    <footer>
        {% block footer %}
        <p>&copy; 2024 {{ site_name | default('My Website') }}</p>
        {% endblock %}
    </footer>
</body>
</html>"""

    # Child template with inheritance
    child_template = """{% extends "base.html" %}

{% block title %}{{ page_title }}{% endblock %}

{% block content %}
<h2>{{ page_title }}</h2>
{% for article in articles %}
<article>
    <h3>{{ article.title }}</h3>
    <p class="meta">By {{ article.author }} on {{ article.date }}</p>
    <p>{{ article.summary | truncate_words(15) }}</p>
    {% if article.tags %}
    <div class="tags">
        Tags: {% for tag in article.tags %}
        <span class="tag">{{ tag | slugify }}</span>{% if not loop.last %}, {% endif %}
        {% endfor %}
    </div>
    {% endif %}
</article>
{% endfor %}
{% endblock %}

{% block footer %}
{{ super() }}
<p>Blog section - {{ articles | length }} articles</p>
{% endblock %}"""

    # Include template (partial)
    nav_template = """<nav>
    <ul>
    {% for link in nav_links %}
        <li><a href="{{ link.url }}">{{ link.label }}</a></li>
    {% endfor %}
    </ul>
</nav>"""

    # Write templates to files
    with open(os.path.join(template_dir, "base.html"), "w") as f:
        f.write(base_template)
    with open(os.path.join(template_dir, "blog.html"), "w") as f:
        f.write(child_template)
    with open(os.path.join(template_dir, "nav.html"), "w") as f:
        f.write(nav_template)

    # Render the blog template (demonstrates inheritance)
    print("=== Template Inheritance ===")
    context = {
        "site_name": "Tech Blog",
        "page_title": "Latest Articles",
        "articles": [
            {
                "title": "Getting Started with Jinja2",
                "author": "Alice",
                "date": "2024-01-15",
                "summary": "Jinja2 is a powerful template engine for Python that lets you create dynamic content with ease and flexibility for web applications and more.",
                "tags": ["Python", "Web Dev", "Templates"],
            },
            {
                "title": "Advanced Template Patterns",
                "author": "Bob",
                "date": "2024-02-20",
                "summary": "Learn how to use template inheritance, macros, and custom filters to build maintainable and reusable template structures for your projects.",
                "tags": ["Advanced", "Best Practices"],
            },
        ],
    }
    result = engine.render_with_inheritance("blog.html", context)
    print(result)

    # Demonstrate includes
    print("\n=== Template Includes ===")
    include_template = """<div>
{% include "nav.html" %}
<main>
    <h1>Welcome, {{ user_name }}!</h1>
</main>
</div>"""

    with open(os.path.join(template_dir, "page_with_nav.html"), "w") as f:
        f.write(include_template)

    result = engine.render_file(
        "page_with_nav.html",
        {
            "user_name": "Charlie",
            "nav_links": [
                {"url": "/", "label": "Home"},
                {"url": "/about", "label": "About"},
                {"url": "/blog", "label": "Blog"},
                {"url": "/contact", "label": "Contact"},
            ],
        },
    )
    print(result)


def main():
    parser = argparse.ArgumentParser(description="Template Engine using Jinja2")
    parser.add_argument(
        "--template", "-t", help="Path to template file to render"
    )
    parser.add_argument(
        "--data", "-d", help="Path to JSON file with context data"
    )
    parser.add_argument(
        "--output", "-o", help="Path to write rendered output"
    )
    parser.add_argument(
        "--template-dir",
        help="Directory containing templates",
        default="./templates",
    )
    parser.add_argument(
        "--demo", action="store_true", help="Run demo examples"
    )

    args = parser.parse_args()

    if args.demo:
        print("=" * 60)
        print("Template Engine Demo - Jinja2")
        print("=" * 60)
        print()
        demo_string_templates()
        print()
        template_dir = os.path.join(args.template_dir, "demo")
        demo_file_templates(template_dir)
        return

    if args.template:
        template_dir = os.path.dirname(os.path.abspath(args.template))
        engine = TemplateEngine(template_dirs=[template_dir])

        context = {}
        if args.data:
            with open(args.data, "r", encoding="utf-8") as f:
                context = json.load(f)

        template_name = os.path.basename(args.template)

        if args.output:
            engine.render_to_file(template_name, args.output, context)
            print(f"Rendered output written to: {args.output}")
        else:
            result = engine.render_file(template_name, context)
            print(result)
    else:
        parser.print_help()


if __name__ == "__main__":
    main()
README.md
# Template Engine - Python (Jinja2)

A template processing engine that supports variables, conditionals, loops, includes, filters, and template inheritance using Jinja2.

## Dependencies

- **Jinja2 3.1.3** - A fast, expressive, extensible templating engine for Python.

## Setup

```bash
pip install -r requirements.txt
```

## Usage

### Run Demo
```bash
python engine.py --demo
```

### Render a Template File
```bash
python engine.py --template path/to/template.html --data context.json
```

### Render with Output File
```bash
python engine.py --template path/to/template.html --data context.json --output output.html
```

## Features

- **Variables**: `{{ variable_name }}` syntax for variable interpolation.
- **Conditionals**: `{% if %}`, `{% elif %}`, `{% else %}` blocks.
- **Loops**: `{% for item in items %}` iteration with loop metadata.
- **Includes**: `{% include "partial.html" %}` for template composition.
- **Filters**: Built-in and custom filters (e.g., `{{ value | upper }}`).
- **Inheritance**: `{% extends "base.html" %}` and `{% block %}` for layout reuse.
requirements.txt
Jinja2==3.1.3