Text Diff Tool (python, written by Claude Code)
envgap__claude-code__python-t1-33
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 #33 · 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: Text Diff Tool Write a program that compares two text files and produces a detailed diff showing additions, deletions, and modifications with configurable output formats and context control. FUNCTIONAL REQUIREMENTS: - Accept two file paths as command-line arguments (original and modified) - Compute the longest common subsequence (LCS) based diff to identify added, deleted, and changed lines - Support multiple output formats via --format flag: unified diff (default, similar to git diff), side-by-side (two-column view), inline (changes marked within lines), and html (visual diff as an HTML page) - Support configurable context lines around changes via --context flag (default: 3 lines of unchanged context around each change) - Detect and highlight intra-line changes: when a line is modified, show exactly which words or characters changed within the line - Support ignoring whitespace differences via --ignore-whitespace flag - Support ignoring case differences via --ignore-case flag - Support ignoring blank lines via --ignore-blank-lines flag - Compute and display diff statistics: total lines in each file, lines added, lines deleted, lines modified, and a similarity percentage - Support comparing directories via --recursive flag: compare all matching files in two directory trees and report which files are added, deleted, modified, or identical - Apply color coding in console output: green for additions, red for deletions, yellow for modifications - Save the diff output to a file via --output flag - If no input files are given, generate two sample text files (original and modified version with insertions, deletions, modifications, and moved blocks), then compute and display the diff in all supported formats - Handle errors: binary files (detect and skip with warning), missing files, encoding mismatches, and very large 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.
diff_tool.py
"""
Text Diff Tool - Compares text files showing additions, deletions, and modifications.
Supports unified, side-by-side, and HTML output formats.
Uses difflib (built-in) and rich for terminal rendering.
"""
import argparse
import difflib
import html
import os
import sys
from pathlib import Path
from rich.console import Console
from rich.table import Table
from rich.text import Text
from rich.panel import Panel
from rich.syntax import Syntax
console = Console()
class TextDiffTool:
"""Compares two text files and displays differences in multiple formats."""
def __init__(self, file1_path: str, file2_path: str, context_lines: int = 3):
self.file1_path = file1_path
self.file2_path = file2_path
self.context_lines = context_lines
self.file1_lines = self._read_file(file1_path)
self.file2_lines = self._read_file(file2_path)
@staticmethod
def _read_file(filepath: str) -> list[str]:
"""Read file and return list of lines."""
path = Path(filepath)
if not path.exists():
console.print(f"[red]Error:[/red] File not found: {filepath}")
sys.exit(1)
try:
with open(path, "r", encoding="utf-8") as f:
return f.readlines()
except UnicodeDecodeError:
console.print(f"[red]Error:[/red] Cannot read binary file: {filepath}")
sys.exit(1)
def get_unified_diff(self) -> list[str]:
"""Generate unified diff output."""
return list(
difflib.unified_diff(
self.file1_lines,
self.file2_lines,
fromfile=self.file1_path,
tofile=self.file2_path,
n=self.context_lines,
)
)
def get_context_diff(self) -> list[str]:
"""Generate context diff output."""
return list(
difflib.context_diff(
self.file1_lines,
self.file2_lines,
fromfile=self.file1_path,
tofile=self.file2_path,
n=self.context_lines,
)
)
def get_ndiff(self) -> list[str]:
"""Generate ndiff (detailed character-level) output."""
return list(difflib.ndiff(self.file1_lines, self.file2_lines))
def compute_stats(self) -> dict:
"""Compute diff statistics: additions, deletions, modifications."""
matcher = difflib.SequenceMatcher(None, self.file1_lines, self.file2_lines)
additions = 0
deletions = 0
modifications = 0
for tag, i1, i2, j1, j2 in matcher.get_opcodes():
if tag == "insert":
additions += j2 - j1
elif tag == "delete":
deletions += i2 - i1
elif tag == "replace":
modifications += max(i2 - i1, j2 - j1)
return {
"additions": additions,
"deletions": deletions,
"modifications": modifications,
"total_changes": additions + deletions + modifications,
"file1_lines": len(self.file1_lines),
"file2_lines": len(self.file2_lines),
}
def display_unified(self) -> None:
"""Display unified diff with rich formatting."""
diff_lines = self.get_unified_diff()
if not diff_lines:
console.print("[green]Files are identical.[/green]")
return
output = Text()
for line in diff_lines:
line_stripped = line.rstrip("\n")
if line.startswith("+++") or line.startswith("---"):
output.append(line_stripped + "\n", style="bold white")
elif line.startswith("@@"):
output.append(line_stripped + "\n", style="cyan")
elif line.startswith("+"):
output.append(line_stripped + "\n", style="green")
elif line.startswith("-"):
output.append(line_stripped + "\n", style="red")
else:
output.append(line_stripped + "\n")
console.print(
Panel(output, title="Unified Diff", border_style="blue", expand=True)
)
def display_side_by_side(self, width: int = 80) -> None:
"""Display side-by-side diff using a rich table."""
matcher = difflib.SequenceMatcher(None, self.file1_lines, self.file2_lines)
table = Table(
title="Side-by-Side Diff",
show_header=True,
header_style="bold magenta",
expand=True,
)
table.add_column("Line", style="dim", width=5, justify="right")
table.add_column(
os.path.basename(self.file1_path), width=width // 2, overflow="fold"
)
table.add_column("Line", style="dim", width=5, justify="right")
table.add_column(
os.path.basename(self.file2_path), width=width // 2, overflow="fold"
)
for tag, i1, i2, j1, j2 in matcher.get_opcodes():
if tag == "equal":
for i, j in zip(range(i1, i2), range(j1, j2)):
left = self.file1_lines[i].rstrip("\n")
right = self.file2_lines[j].rstrip("\n")
table.add_row(str(i + 1), left, str(j + 1), right)
elif tag == "replace":
max_len = max(i2 - i1, j2 - j1)
for k in range(max_len):
left_num = str(i1 + k + 1) if k < (i2 - i1) else ""
right_num = str(j1 + k + 1) if k < (j2 - j1) else ""
left = (
Text(
self.file1_lines[i1 + k].rstrip("\n"), style="red strike"
)
if k < (i2 - i1)
else Text("")
)
right = (
Text(self.file2_lines[j1 + k].rstrip("\n"), style="green")
if k < (j2 - j1)
else Text("")
)
table.add_row(left_num, left, right_num, right)
elif tag == "delete":
for i in range(i1, i2):
left = Text(self.file1_lines[i].rstrip("\n"), style="red strike")
table.add_row(str(i + 1), left, "", Text(""))
elif tag == "insert":
for j in range(j1, j2):
right = Text(self.file2_lines[j].rstrip("\n"), style="green")
table.add_row("", Text(""), str(j + 1), right)
console.print(table)
def generate_html(self, output_path: str = None) -> str:
"""Generate HTML diff report."""
differ = difflib.HtmlDiff(tabsize=4, wrapcolumn=80)
html_content = differ.make_file(
self.file1_lines,
self.file2_lines,
fromdesc=self.file1_path,
todesc=self.file2_path,
context=True,
numlines=self.context_lines,
)
# Wrap with additional styling
stats = self.compute_stats()
stats_html = f"""
<div style="font-family: monospace; padding: 10px; background: #f0f0f0;
border: 1px solid #ccc; margin: 10px 0;">
<h3>Diff Statistics</h3>
<p>Additions: <span style="color: green;">{stats['additions']}</span></p>
<p>Deletions: <span style="color: red;">{stats['deletions']}</span></p>
<p>Modifications: <span style="color: orange;">{stats['modifications']}</span></p>
<p>Total changes: {stats['total_changes']}</p>
<p>File 1 lines: {stats['file1_lines']} | File 2 lines: {stats['file2_lines']}</p>
</div>
"""
html_content = html_content.replace("</body>", stats_html + "</body>")
if output_path:
with open(output_path, "w", encoding="utf-8") as f:
f.write(html_content)
console.print(f"[green]HTML diff saved to: {output_path}[/green]")
return html_content
def display_stats(self) -> None:
"""Display diff statistics with rich formatting."""
stats = self.compute_stats()
table = Table(title="Diff Statistics", show_header=True)
table.add_column("Metric", style="bold")
table.add_column("Value", justify="right")
table.add_row("Additions", f"[green]+{stats['additions']}[/green]")
table.add_row("Deletions", f"[red]-{stats['deletions']}[/red]")
table.add_row("Modifications", f"[yellow]~{stats['modifications']}[/yellow]")
table.add_row("Total Changes", str(stats["total_changes"]))
table.add_row("File 1 Lines", str(stats["file1_lines"]))
table.add_row("File 2 Lines", str(stats["file2_lines"]))
console.print(table)
def main():
parser = argparse.ArgumentParser(
description="Text Diff Tool - Compare text files with rich output"
)
parser.add_argument("file1", help="Path to the first (original) file")
parser.add_argument("file2", help="Path to the second (modified) file")
parser.add_argument(
"--format",
choices=["unified", "side-by-side", "html", "ndiff", "context", "all"],
default="unified",
help="Output format (default: unified)",
)
parser.add_argument(
"--context-lines",
type=int,
default=3,
help="Number of context lines (default: 3)",
)
parser.add_argument(
"--html-output", type=str, default=None, help="Path for HTML output file"
)
parser.add_argument(
"--width",
type=int,
default=80,
help="Column width for side-by-side view (default: 80)",
)
parser.add_argument(
"--stats", action="store_true", help="Show diff statistics"
)
args = parser.parse_args()
diff_tool = TextDiffTool(args.file1, args.file2, args.context_lines)
if args.stats or args.format == "all":
diff_tool.display_stats()
if args.format == "unified" or args.format == "all":
diff_tool.display_unified()
if args.format == "side-by-side" or args.format == "all":
diff_tool.display_side_by_side(args.width)
if args.format == "html" or args.format == "all":
output_path = args.html_output or "diff_report.html"
diff_tool.generate_html(output_path)
if args.format == "ndiff":
lines = diff_tool.get_ndiff()
for line in lines:
console.print(line.rstrip("\n"))
if args.format == "context":
lines = diff_tool.get_context_diff()
for line in lines:
console.print(line.rstrip("\n"))
if __name__ == "__main__":
main()
README.md
# Text Diff Tool (Python - Trial 1) A text file comparison tool that shows additions, deletions, and modifications in unified, side-by-side, and HTML formats. ## Dependencies - **difflib** (built-in): Python standard library module for computing deltas between sequences - **rich** (13.7.0): Rich text formatting and terminal rendering library ## Installation ```bash pip install -r requirements.txt ``` ## Usage ```bash # Unified diff (default) python diff_tool.py file1.txt file2.txt # Side-by-side diff python diff_tool.py file1.txt file2.txt --format side-by-side # HTML output python diff_tool.py file1.txt file2.txt --format html --html-output report.html # All formats with statistics python diff_tool.py file1.txt file2.txt --format all --stats # Context diff python diff_tool.py file1.txt file2.txt --format context --context-lines 5 ``` ## Features - Unified diff display with color-coded additions/deletions - Side-by-side comparison in a formatted table - HTML report generation with embedded statistics - Detailed character-level diff (ndiff format) - Context diff format - Diff statistics (additions, deletions, modifications) - Configurable context lines
requirements.txt
rich==13.7.0