PDF Report Generator (python, written by Codex)
envgap__codex__python-t1-47
Written by a coding agent; not on GitHubWritten 2026-02-28
01 / FAILURE SIGNATURE
As the study recorded it
IndexError: Index entries not resolved after 10 passes - multiBuild loop
Not a benchmark task.
- Its repair changed source code, so it is not an environment task.
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 #47 · read the task the agent was given
Codex wrote this python project from the task below. It does not run on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: PDF Report Generator Write a program that generates formatted PDF reports from structured data, supporting tables, charts, headers/footers, page numbers, and custom styling. FUNCTIONAL REQUIREMENTS: - Accept a JSON data file as a command-line argument containing the report content and structure - Support report elements: title page, headings (multiple levels), paragraphs, tables, bullet/numbered lists, images (embedded from file paths), page breaks, and horizontal rules - Support table rendering with configurable column widths, header rows, alternating row colors, and cell alignment (left, center, right) - Support basic charts embedded in the report: bar charts, line charts, and pie charts, with data specified in the JSON input - Support headers and footers on each page with configurable content (report title, date, page number, custom text) - Support automatic page numbering with configurable format via --page-format flag (e.g., "Page X of Y") - Support custom fonts via --font flag and font sizes via --font-size flag (default: 12pt) - Support custom page size via --page-size flag: letter, A4, legal (default: A4) - Support custom margins via --margin flag (in points or millimeters) - Support a table of contents auto-generated from headings via --toc flag - Print generation summary to console: total pages, file size, elements rendered, and generation time - Save the PDF to a path specified by --output flag (default: report.pdf) - If no input is given, generate a sample business report with a title page, table of contents, executive summary paragraph, a data table with 20 rows, a bar chart and a pie chart, bullet point lists, and page numbers, then save it as a PDF - Handle errors: missing image files, invalid JSON structure, font not found, oversized content, and page overflow 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.
README.md
# PDF Report Generator (Python - Trial 1) Generates formatted PDF reports with tables, charts, headers/footers, page numbers, and a table of contents. ## Dependencies - **reportlab** (4.1.0) - PDF document generation library - **matplotlib** (3.8.2) - Chart and plot generation ## Setup ```bash pip install -r requirements.txt ``` ## Usage ```bash python pdf_gen.py -o report.pdf -t "Annual Performance Report" -a "Author Name" --pagesize letter ``` ### Options | Flag | Description | Default | |------|-------------|---------| | `-o, --output` | Output PDF file path | `report.pdf` | | `-t, --title` | Report title | `Annual Performance Report` | | `-a, --author` | Report author name | `PDF Report Generator` | | `--pagesize` | Page size (letter or a4) | `letter` | ## Features - Custom document template with headers and footers on every page - Automatic page numbering - Table of contents with bookmark navigation - Bar charts, pie charts, and line charts via matplotlib - Styled data tables with alternating row colors - Cover page with title and metadata
requirements.txt
reportlab==4.1.0 matplotlib==3.8.2
src/main.py
"""
PDF Report Generator - Generates formatted PDF reports with tables, charts,
headers/footers, page numbers, and a table of contents.
Dependencies:
- reportlab 4.1.0
- matplotlib 3.8.2
"""
import os
import io
import argparse
from datetime import datetime
from reportlab.lib.pagesizes import letter, A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch, cm
from reportlab.lib.colors import HexColor, black, white, grey
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
PageBreak, Image, KeepTogether
)
from reportlab.platypus.tableofcontents import TableOfContents
from reportlab.lib import colors
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
# ---------------------------------------------------------------------------
# Custom document template with headers, footers, and page numbers
# ---------------------------------------------------------------------------
class ReportDocTemplate(SimpleDocTemplate):
"""Custom document template that draws headers and footers on every page."""
def __init__(self, filename, report_title="Report", report_author="Author",
**kwargs):
super().__init__(filename, **kwargs)
self.report_title = report_title
self.report_author = report_author
self.page_count = 0
def afterPage(self):
self.page_count += 1
def afterFlowable(self, flowable):
"""Register TOC entries when headings are drawn."""
if isinstance(flowable, Paragraph):
style_name = flowable.style.name
text = flowable.getPlainText()
if style_name == "Heading1":
key = f"h1-{self.page_count}"
self.canv.bookmarkPage(key)
self.notify("TOCEntry", (0, text, self.page, key))
elif style_name == "Heading2":
key = f"h2-{self.page_count}"
self.canv.bookmarkPage(key)
self.notify("TOCEntry", (1, text, self.page, key))
def header_footer(canvas, doc):
"""Draw header and footer on each page."""
canvas.saveState()
# Header
canvas.setFillColor(HexColor("#2c3e50"))
canvas.rect(doc.leftMargin, doc.height + doc.topMargin - 10,
doc.width, 30, fill=True, stroke=False)
canvas.setFillColor(white)
canvas.setFont("Helvetica-Bold", 10)
canvas.drawString(doc.leftMargin + 10,
doc.height + doc.topMargin - 2,
doc.report_title)
canvas.drawRightString(doc.leftMargin + doc.width - 10,
doc.height + doc.topMargin - 2,
datetime.now().strftime("%B %d, %Y"))
# Footer
canvas.setFillColor(HexColor("#2c3e50"))
canvas.rect(doc.leftMargin, doc.bottomMargin - 25,
doc.width, 20, fill=True, stroke=False)
canvas.setFillColor(white)
canvas.setFont("Helvetica", 8)
canvas.drawString(doc.leftMargin + 10, doc.bottomMargin - 20,
f"Author: {doc.report_author}")
canvas.drawCentredString(doc.leftMargin + doc.width / 2,
doc.bottomMargin - 20,
f"Page {canvas.getPageNumber()}")
canvas.drawRightString(doc.leftMargin + doc.width - 10,
doc.bottomMargin - 20,
"Generated with PDF Report Generator")
canvas.restoreState()
# ---------------------------------------------------------------------------
# Chart generation helpers using matplotlib
# ---------------------------------------------------------------------------
def create_bar_chart(data, title="Bar Chart", xlabel="Category",
ylabel="Value"):
"""Create a bar chart and return it as a ReportLab Image."""
fig, ax = plt.subplots(figsize=(6, 3.5))
categories = list(data.keys())
values = list(data.values())
bar_colors = ["#3498db", "#2ecc71", "#e74c3c", "#f39c12",
"#9b59b6", "#1abc9c", "#e67e22", "#34495e"]
ax.bar(categories, values,
color=bar_colors[:len(categories)], edgecolor="white")
ax.set_title(title, fontsize=12, fontweight="bold")
ax.set_xlabel(xlabel, fontsize=10)
ax.set_ylabel(ylabel, fontsize=10)
ax.yaxis.set_major_locator(ticker.MaxNLocator(integer=True))
plt.xticks(rotation=30, ha="right", fontsize=8)
plt.tight_layout()
buf = io.BytesIO()
fig.savefig(buf, format="png", dpi=150)
plt.close(fig)
buf.seek(0)
return Image(buf, width=5.5 * inch, height=3.2 * inch)
def create_pie_chart(data, title="Distribution"):
"""Create a pie chart and return it as a ReportLab Image."""
fig, ax = plt.subplots(figsize=(5, 4))
labels = list(data.keys())
sizes = list(data.values())
pie_colors = ["#3498db", "#2ecc71", "#e74c3c", "#f39c12",
"#9b59b6", "#1abc9c"]
wedges, texts, autotexts = ax.pie(
sizes, labels=labels, autopct="%1.1f%%",
colors=pie_colors[:len(labels)], startangle=140
)
for text in autotexts:
text.set_fontsize(8)
ax.set_title(title, fontsize=12, fontweight="bold")
plt.tight_layout()
buf = io.BytesIO()
fig.savefig(buf, format="png", dpi=150)
plt.close(fig)
buf.seek(0)
return Image(buf, width=4.5 * inch, height=3.5 * inch)
def create_line_chart(x_data, y_series, title="Trend",
xlabel="X", ylabel="Y"):
"""Create a multi-series line chart and return it as a ReportLab Image."""
fig, ax = plt.subplots(figsize=(6, 3.5))
line_colors = ["#3498db", "#e74c3c", "#2ecc71", "#f39c12"]
for idx, (label, y_vals) in enumerate(y_series.items()):
ax.plot(x_data, y_vals, marker="o", markersize=4,
label=label, color=line_colors[idx % len(line_colors)])
ax.set_title(title, fontsize=12, fontweight="bold")
ax.set_xlabel(xlabel, fontsize=10)
ax.set_ylabel(ylabel, fontsize=10)
ax.legend(fontsize=8)
ax.grid(True, alpha=0.3)
plt.tight_layout()
buf = io.BytesIO()
fig.savefig(buf, format="png", dpi=150)
plt.close(fig)
buf.seek(0)
return Image(buf, width=5.5 * inch, height=3.2 * inch)
# ---------------------------------------------------------------------------
# Table builder
# ---------------------------------------------------------------------------
def build_table(headers, rows, col_widths=None):
"""Build a styled ReportLab table."""
data = [headers] + rows
if col_widths is None:
col_widths = [doc_width / len(headers)] * len(headers)
table = Table(data, colWidths=col_widths, repeatRows=1)
style = TableStyle([
("BACKGROUND", (0, 0), (-1, 0), HexColor("#2c3e50")),
("TEXTCOLOR", (0, 0), (-1, 0), white),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, 0), 10),
("ALIGN", (0, 0), (-1, 0), "CENTER"),
("BOTTOMPADDING", (0, 0), (-1, 0), 8),
("TOPPADDING", (0, 0), (-1, 0), 8),
("BACKGROUND", (0, 1), (-1, -1), HexColor("#ecf0f1")),
("TEXTCOLOR", (0, 1), (-1, -1), black),
("FONTNAME", (0, 1), (-1, -1), "Helvetica"),
("FONTSIZE", (0, 1), (-1, -1), 9),
("ALIGN", (0, 1), (-1, -1), "LEFT"),
("GRID", (0, 0), (-1, -1), 0.5, grey),
("ROWBACKGROUNDS", (0, 1), (-1, -1),
[HexColor("#ecf0f1"), white]),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
])
table.setStyle(style)
return table
# ---------------------------------------------------------------------------
# Main report assembly
# ---------------------------------------------------------------------------
# Module-level variable for table helper
doc_width = 6.5 * inch
def generate_report(output_path, title="Annual Performance Report",
author="Report Generator", pagesize=letter):
"""Generate a complete PDF report."""
global doc_width
doc_width = pagesize[0] - 2 * inch
doc = ReportDocTemplate(
output_path,
report_title=title,
report_author=author,
pagesize=pagesize,
topMargin=1 * inch,
bottomMargin=0.8 * inch,
leftMargin=1 * inch,
rightMargin=1 * inch,
)
styles = getSampleStyleSheet()
styles.add(ParagraphStyle(
name="ReportTitle",
parent=styles["Title"],
fontSize=28,
spaceAfter=6,
textColor=HexColor("#2c3e50"),
alignment=TA_CENTER,
))
styles.add(ParagraphStyle(
name="Subtitle",
parent=styles["Normal"],
fontSize=14,
spaceAfter=20,
textColor=HexColor("#7f8c8d"),
alignment=TA_CENTER,
))
styles.add(ParagraphStyle(
name="SectionBody",
parent=styles["Normal"],
fontSize=10,
leading=14,
spaceAfter=10,
))
story = []
# ---- Cover Page ----
story.append(Spacer(1, 2 * inch))
story.append(Paragraph(title, styles["ReportTitle"]))
story.append(Paragraph(
f"Prepared by {author} | {datetime.now().strftime('%B %Y')}",
styles["Subtitle"],
))
story.append(Spacer(1, 0.5 * inch))
story.append(Paragraph(
"This report provides a comprehensive analysis of organizational "
"performance metrics, financial summaries, and strategic insights "
"for the current fiscal year.",
styles["SectionBody"],
))
story.append(PageBreak())
# ---- Table of Contents ----
story.append(Paragraph("Table of Contents", styles["Heading1"]))
story.append(Spacer(1, 0.25 * inch))
toc = TableOfContents()
toc.levelStyles = [
ParagraphStyle(name="TOC1", fontSize=12, leading=18,
leftIndent=20, spaceBefore=4),
ParagraphStyle(name="TOC2", fontSize=10, leading=14,
leftIndent=40, spaceBefore=2),
]
story.append(toc)
story.append(PageBreak())
# ---- Section 1: Executive Summary ----
story.append(Paragraph("1. Executive Summary", styles["Heading1"]))
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph(
"This section provides a high-level overview of the key findings "
"and recommendations presented in this report. The organization "
"has demonstrated strong growth across multiple business units, "
"with notable improvements in operational efficiency and customer "
"satisfaction metrics.",
styles["SectionBody"],
))
story.append(Paragraph(
"Revenue increased by 15.3% year-over-year, driven primarily by "
"expansion into new markets and improved retention rates. Operating "
"costs were reduced by 8.2% through strategic process optimization "
"and technology investments.",
styles["SectionBody"],
))
story.append(Spacer(1, 0.2 * inch))
# Key metrics table
story.append(Paragraph("1.1 Key Performance Indicators",
styles["Heading2"]))
kpi_headers = ["Metric", "Q1", "Q2", "Q3", "Q4", "YoY Change"]
kpi_rows = [
["Revenue ($M)", "12.4", "14.1", "15.8", "17.2", "+15.3%"],
["Net Profit ($M)", "2.1", "2.5", "2.9", "3.4", "+22.1%"],
["Customers (K)", "45.2", "48.7", "52.1", "56.8", "+12.4%"],
["Satisfaction (%)", "87.3", "89.1", "91.5", "93.2", "+5.9pp"],
["Employee Count", "342", "358", "371", "389", "+13.7%"],
]
story.append(build_table(kpi_headers, kpi_rows))
story.append(Spacer(1, 0.3 * inch))
# ---- Section 2: Financial Analysis ----
story.append(Paragraph("2. Financial Analysis", styles["Heading1"]))
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph(
"The financial performance of the organization has exceeded "
"projections across all major categories. Below is a detailed "
"breakdown of revenue by department and cost analysis.",
styles["SectionBody"],
))
# Bar chart - revenue by department
revenue_data = {
"Engineering": 18.5,
"Sales": 24.3,
"Marketing": 8.7,
"Operations": 5.2,
"Support": 3.8,
}
story.append(create_bar_chart(
revenue_data,
title="Revenue by Department ($M)",
xlabel="Department",
ylabel="Revenue ($M)",
))
story.append(Spacer(1, 0.2 * inch))
story.append(Paragraph("2.1 Expense Breakdown", styles["Heading2"]))
expense_data = {
"Salaries": 42,
"Infrastructure": 18,
"Marketing": 15,
"R&D": 12,
"Operations": 8,
"Other": 5,
}
story.append(create_pie_chart(expense_data, title="Expense Distribution"))
story.append(Spacer(1, 0.2 * inch))
# Expense table
expense_headers = ["Category", "Budget ($M)", "Actual ($M)", "Variance"]
expense_rows = [
["Salaries & Benefits", "18.5", "17.9", "-3.2%"],
["Cloud Infrastructure", "6.2", "6.8", "+9.7%"],
["Marketing Campaigns", "5.1", "4.7", "-7.8%"],
["Research & Development", "4.8", "5.2", "+8.3%"],
["Office Operations", "3.1", "2.9", "-6.5%"],
["Travel & Events", "1.5", "1.2", "-20.0%"],
]
story.append(build_table(expense_headers, expense_rows))
story.append(PageBreak())
# ---- Section 3: Growth Trends ----
story.append(Paragraph("3. Growth Trends", styles["Heading1"]))
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph(
"The following chart illustrates growth trends across key metrics "
"over the past twelve months, demonstrating consistent upward "
"trajectory in all measured categories.",
styles["SectionBody"],
))
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
trends = {
"Revenue": [10.2, 10.8, 11.1, 12.4, 12.9, 13.5,
14.1, 14.8, 15.2, 15.8, 16.5, 17.2],
"Costs": [8.1, 8.3, 8.0, 8.5, 8.4, 8.6,
8.7, 8.5, 8.9, 8.8, 9.0, 9.1],
"Profit": [2.1, 2.5, 3.1, 3.9, 4.5, 4.9,
5.4, 6.3, 6.3, 7.0, 7.5, 8.1],
}
story.append(create_line_chart(
months, trends,
title="Monthly Financial Trends ($M)",
xlabel="Month", ylabel="Amount ($M)",
))
story.append(Spacer(1, 0.3 * inch))
# ---- Section 4: Regional Performance ----
story.append(Paragraph("4. Regional Performance", styles["Heading1"]))
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph("4.1 Revenue by Region", styles["Heading2"]))
region_headers = ["Region", "Revenue ($M)", "Growth (%)", "Market Share",
"Customer Count"]
region_rows = [
["North America", "28.4", "+12.1%", "34.2%", "22,450"],
["Europe", "19.7", "+18.5%", "23.7%", "15,820"],
["Asia-Pacific", "15.3", "+25.3%", "18.4%", "12,100"],
["Latin America", "8.9", "+31.2%", "10.7%", "7,240"],
["Middle East", "5.6", "+14.8%", "6.7%", "4,180"],
["Africa", "5.2", "+42.1%", "6.3%", "3,890"],
]
story.append(build_table(region_headers, region_rows))
story.append(Spacer(1, 0.2 * inch))
regional_revenue = {
"N. America": 28.4,
"Europe": 19.7,
"Asia-Pacific": 15.3,
"LATAM": 8.9,
"Middle East": 5.6,
"Africa": 5.2,
}
story.append(create_bar_chart(
regional_revenue,
title="Revenue by Region ($M)",
xlabel="Region", ylabel="Revenue ($M)",
))
story.append(PageBreak())
# ---- Section 5: Conclusions ----
story.append(Paragraph("5. Conclusions & Recommendations",
styles["Heading1"]))
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph(
"Based on the analysis presented in this report, the organization "
"is well-positioned for continued growth. Key recommendations "
"include:",
styles["SectionBody"],
))
recommendations = [
"Increase investment in Asia-Pacific and African markets, which "
"show the highest growth rates.",
"Continue optimizing operational costs through automation and "
"process improvements.",
"Expand the product portfolio to address emerging customer needs "
"identified through satisfaction surveys.",
"Invest in employee development programs to support the growing "
"team and maintain high productivity.",
"Establish a dedicated data analytics team to improve "
"decision-making across all departments.",
]
for i, rec in enumerate(recommendations, 1):
story.append(Paragraph(
f"<b>{i}.</b> {rec}", styles["SectionBody"]
))
story.append(Spacer(1, 0.3 * inch))
story.append(Paragraph(
"This report was automatically generated using the PDF Report "
"Generator tool. All data is for demonstration purposes.",
ParagraphStyle(
name="Disclaimer",
parent=styles["Normal"],
fontSize=8,
textColor=HexColor("#95a5a6"),
alignment=TA_CENTER,
),
))
# Build with multiple passes for TOC
doc.multiBuild(story, onFirstPage=header_footer,
onLaterPages=header_footer)
print(f"Report generated: {os.path.abspath(output_path)}")
# ---------------------------------------------------------------------------
# CLI entry point
# ---------------------------------------------------------------------------
def main():
parser = argparse.ArgumentParser(
description="Generate formatted PDF reports with tables, charts, "
"headers/footers, page numbers, and table of contents."
)
parser.add_argument(
"-o", "--output",
default="report.pdf",
help="Output PDF file path (default: report.pdf)",
)
parser.add_argument(
"-t", "--title",
default="Annual Performance Report",
help="Report title",
)
parser.add_argument(
"-a", "--author",
default="PDF Report Generator",
help="Report author name",
)
parser.add_argument(
"--pagesize",
choices=["letter", "a4"],
default="letter",
help="Page size (default: letter)",
)
args = parser.parse_args()
pagesize = A4 if args.pagesize == "a4" else letter
generate_report(args.output, title=args.title, author=args.author,
pagesize=pagesize)
if __name__ == "__main__":
main()