python-unidiff

A typed Python library that parses unified diff data into inspectable PatchSet, PatchedFile, and Hunk objects.

Library
PyPI
v1.0.0
286stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
80/100Excellent
Development Activity96
Maintenance72
Community72
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
67/100Good
Architecture78
Code Quality88
Innovation48
Learning Curve55

unidiff is a small, focused Python library for parsing and interacting with unified diff (patch) data. Feed it a diff — from git diff, hg diff, a .diff file, or any file-like/bytes source — and it returns a PatchSet: a list of PatchedFile objects, each a list of Hunk objects, each a list of Line objects, mirroring the actual structure of a diff.

Every level exposes the metadata you’d otherwise have to regex out yourself: per-file added/removed line counts, added/removed/renamed/binary file classification, git file modes and symlink detection, hunk source/target line numbers, and per-line added/removed/context flags with source and target line numbers. A metadata_only mode skips content tracking for faster parsing when you only need the stats.

The library also ships a small CLI (unidiff, or python -m unidiff) that prints a per-file addition/deletion summary from stdin or a file, useful as a quick diff-stat replacement in shell pipelines.

What You Get

  • PatchSet — parses from a file-like object, bytes, a string (PatchSet.from_string), or a filename (PatchSet.from_filename), and behaves like a list of PatchedFile objects
  • PatchedFile — per-file metadata: is_added_file, is_removed_file, is_modified_file, is_rename, is_binary_file, added/removed counts, and path
  • Git-specific metadata — source_mode/target_mode file modes (e.g. 100644, 120000) and an is_symlink shortcut, plus diff_line_no to locate hunkless binary entries
  • Hunk and Line objects with source_start/target_start, source_line_no/target_line_no, and is_added/is_removed/is_context flags for line-by-line inspection
  • Round-trip string rendering — str(patch) reconstructs the original unified diff text from any parsed object
  • A unidiff CLI (also python -m unidiff) that prints an addition/deletion summary per file, usable directly in a git diff | unidiff pipeline
  • metadata_only=True parsing mode that skips content tracking for faster stats-only parsing on large diffs
  • bytes input support and an explicit newline='\n' path for diffs containing embedded carriage returns or control characters

Common Use Cases

  • Code review tooling - annotate or comment on specific added/removed lines in a pull request diff by walking Hunk/Line objects
  • Coverage-on-diff / lint-on-diff - restrict a linter or coverage report to only the lines actually changed in a patch
  • Patch application scripts - inspect is_added_file/is_removed_file/is_rename before deciding how to apply a hunk to a working tree
  • Diff-stat CLIs - use the bundled unidiff command, or build a custom summary, from git diff | unidiff style pipelines
  • Changelog / release-note generation - walk added and removed lines across a PatchSet to summarize what changed between two revisions

Under The Hood

Architecture The library models a unified diff as four nested list subclasses that mirror the diff’s own structure: PatchSet (list of PatchedFile) → PatchedFile (list of Hunk) → Hunk (list of Line). Parsing lives in unidiff/patch.py as a hand-written line-by-line scanner (PatchSet._parsePatchedFile._parse_hunk) driven entirely by the compiled regexes centralized in unidiff/constants.py (git header, rename, mode-change, hunk-header, no-newline-marker patterns). This keeps pattern matching separate from the object model and from error signaling, which is isolated in unidiff/errors.py as a single UnidiffParseError. A metadata_only flag threaded through the parse path switches between full line-content tracking and a cheaper line-type-only scan, letting the same parser serve both “I need the exact diff back” and “I only need stats” callers without duplicating logic. __init__.py re-exports the public surface (PatchSet, PatchedFile, Hunk, constants) as the sole supported import path.

Tech Stack Pure Python 3.9+ with zero runtime dependencies — packaging is pyproject.toml/setuptools with a dynamic version pulled from unidiff/__version__.py. Type hints use modern PEP 585/604 generics (list[Line], Union/Optional from typing, from __future__ import annotations) and the package ships a py.typed marker for downstream type-checker consumption. The only extra surface is a stdlib-only argparse-based CLI in unidiff/__main__.py registered via [project.scripts].

Code Quality Tests (1,125 lines across test_parser.py, test_hunks.py, test_line.py, test_patchedfile.py) actually outweigh the library source (965 lines), run via stdlib unittest, and are checked against a real corpus of diff fixtures under tests/samples/ covering git, hg, bzr, quilt, and debdiff formats plus edge cases (symlinks, renames, embedded CR, quoted filenames). CI runs the suite across five Python versions (3.9–3.13) and layers a separate mypy type-check job over the source tree. Naming is consistent and each public property is documented inline; error handling is explicit via UnidiffParseError rather than silent failure on malformed input.

What Makes It Unique The object model is deliberately faithful to the diff format itself rather than flattening it into a generic dict/list structure, so callers can walk patch[i][j][k] and get exactly the file/hunk/line addressed by that position. Combined with the metadata_only fast path and the round-trip str() guarantee (parsed output regenerates byte-identical diff text), it functions equally well as a diff introspection library and as a diff-rewriting primitive, without pulling in any external dependency to do either.

Used by 5 apps in this directory

Python
62%
MIT

AutoGen

AI Development · Automation

60,985

Build autonomous and human-in-the-loop multi-agent AI systems with a layered, event-driven Python and .NET framework pioneered at Microsoft Research.

View details
56
Repo Health
78
Technical
73
Dependency
Built with
Python62%
C#25%
TypeScript12%
Updated 5 months ago
C++
68%
Apache 2.0

ClickHouse

Databases · Analytics · Data Engineering

49,890

Open-source column-oriented database that delivers real-time analytical queries on petabyte-scale data with millisecond latency.

View details
95
Repo Health
90
Technical
68
Dependency
Built with
C++68%
Python13%
Updated 2 days ago
Other

Magic

AI Agents · Automation · Low Code Platforms

5,032

Magic is an enterprise-grade open-source AI agent platform combining a generalist AI agent, workflow engine, IM, and collaborative office system for running an AI-powered digital workforce.

View details
71
Repo Health
79
Technical
0
Dependency
Python
58%
Other

Sentry

Security · Developer Tools · Monitoring

44,778

Developer-first error tracking and performance monitoring platform with AI-powered root-cause analysis across 20+ languages and frameworks.

View details
95
Repo Health
80
Technical
69
Dependency
Built with
Python58%
TypeScript41%
Updated 2 days ago
C++
75%
Apache 2.0

Timeplus Proton

Data Engineering · Analytics

2,259

Single C++ binary SQL engine for real-time stream processing, ETL, and analytics on Kafka, Redpanda, and ClickHouse with sub-millisecond latency.

View details
88
Repo Health
82
Technical
68
Dependency
Built with
C++75%
Python11%
Updated 1 weeks ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search