Template Engine (python, written by Codex)
envgap__codex__python-t1-35
Written by a coding agent; not on GitHubWritten 2026-03-03
01 / FAILURE SIGNATURE
As the study recorded it
None
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
codex/python-t1 #35 · read the task the agent was given
Codex 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 output04 / 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.
README.md
# Template Engine (Python) ## Requirements - Ubuntu 22.04 - Python 3.10+ ## Install ```bash python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` ## Pinned Dependencies - `Jinja2==3.1.4` - `MarkupSafe==2.1.5` (transitive dependency pinned explicitly) ## Run ```bash python src/main.py template.tpl data.json python src/main.py template.tpl data.json --strict --output rendered.txt python src/main.py template.tpl --batch data_files.txt --output out_dir ``` If no arguments are passed, sample templates/data are generated and rendered.
requirements.txt
Jinja2==3.1.4 MarkupSafe==2.1.5
src/main.py
#!/usr/bin/env python3
import argparse
import json
import sys
from pathlib import Path
from typing import Any
from jinja2 import Environment, FileSystemLoader, StrictUndefined, Undefined, TemplateError
def load_json(path: Path) -> Any:
try:
return json.loads(path.read_text(encoding="utf-8"))
except Exception as exc:
raise RuntimeError(f"Failed to load JSON {path}: {exc}") from exc
def make_env(templates_dir: Path, strict: bool) -> Environment:
env = Environment(
loader=FileSystemLoader(str(templates_dir)),
undefined=StrictUndefined if strict else Undefined,
trim_blocks=True,
lstrip_blocks=True,
autoescape=False,
)
env.filters["upper"] = lambda v: str(v).upper()
env.filters["format"] = lambda v, fmt="%s": fmt % v
env.filters["join"] = lambda v, sep=", ": sep.join(str(x) for x in (v or []))
env.filters["truncate"] = lambda v, n=50: (str(v) if len(str(v)) <= int(n) else str(v)[: max(0, int(n) - 3)] + "...")
return env
def render_one(template_path: Path, data_path: Path, output: Path | None, strict: bool) -> str:
env = make_env(template_path.parent, strict)
data = load_json(data_path)
try:
template = env.get_template(template_path.name)
rendered = template.render(**data)
except TemplateError as exc:
raise RuntimeError(f"Template rendering failed: {exc}") from exc
print(rendered)
if output:
output.write_text(rendered, encoding="utf-8")
return rendered
def render_batch(template_path: Path, batch_file: Path, output_dir: Path | None, strict: bool) -> list[dict[str, str]]:
rows = [line.strip() for line in batch_file.read_text(encoding="utf-8").splitlines() if line.strip()]
if not rows:
raise RuntimeError("Batch file is empty")
out_dir = output_dir or Path("batch_outputs")
out_dir.mkdir(parents=True, exist_ok=True)
records: list[dict[str, str]] = []
for row in rows:
data_path = Path(row)
out_path = out_dir / f"{data_path.stem}.out.txt"
render_one(template_path, data_path, out_path, strict)
records.append({"dataFile": str(data_path.resolve()), "outputFile": str(out_path.resolve())})
return records
def write_samples(base: Path) -> tuple[Path, Path]:
base.mkdir(parents=True, exist_ok=True)
(base / "base.tpl").write_text(
"""<html>
<body>
<header><h1>{{ company.name | upper }}</h1></header>
{% block content %}{% endblock %}
<footer>{% include "footer.tpl" %}</footer>
</body>
</html>
""",
encoding="utf-8",
)
(base / "email.tpl").write_text(
"""{% extends "base.tpl" %}
{% block content %}
<h2>Hello {{ user.name | default("Customer") }}</h2>
{% if discount > 0 %}
<p>Discount: {{ discount | format("$%.2f") }}</p>
{% elif vip %}
<p>VIP pricing applies</p>
{% else %}
<p>No discount available</p>
{% endif %}
<ul>
{% for product in products %}
<li>{{ loop.index }}. {{ product.name }} - {{ product.price | format("$%.2f") }}</li>
{% endfor %}
</ul>
<p>{{ notes | truncate(60) }}</p>
{% endblock %}
""",
encoding="utf-8",
)
(base / "footer.tpl").write_text("<small>{{ user.email | e }}</small>\n", encoding="utf-8")
data = {
"company": {"name": "Acme Retail"},
"user": {"name": "Alex", "email": "alex@example.com"},
"discount": 12.5,
"vip": False,
"products": [
{"name": "Keyboard", "price": 49.99},
{"name": "Mouse", "price": 29.5},
{"name": "Monitor", "price": 229.0},
],
"notes": "Thank you for your order. Please contact support for invoice changes.",
}
data_path = base / "sample_data.json"
data_path.write_text(json.dumps(data, indent=2), encoding="utf-8")
return base / "email.tpl", data_path
def main() -> int:
parser = argparse.ArgumentParser(description="Template engine")
parser.add_argument("template", nargs="?", help="Template file")
parser.add_argument("data", nargs="?", help="JSON data file")
parser.add_argument("--output", help="Output path for single render, output dir for batch")
parser.add_argument("--batch", help="Batch file containing JSON file paths")
parser.add_argument("--strict", action="store_true", help="Strict mode for undefined variables")
args = parser.parse_args()
try:
if not args.template or (not args.data and not args.batch):
tpl, data = write_samples(Path("sample_template"))
render_one(tpl, data, Path("sample_rendered.html"), args.strict)
return 0
template_path = Path(args.template)
if args.batch:
records = render_batch(template_path, Path(args.batch), Path(args.output) if args.output else None, args.strict)
Path("template_batch_report.json").write_text(
json.dumps({"records": records}, indent=2), encoding="utf-8"
)
return 0
render_one(template_path, Path(args.data), Path(args.output) if args.output else None, args.strict)
return 0
except Exception as exc:
print(f"Error: {exc}", file=sys.stderr)
return 1
if __name__ == "__main__":
raise SystemExit(main())