Skip to main content

unipatch

https://img.shields.io/github/actions/workflow/status/adamchainz/unipatch/main.yml.svg?branch=main&style=for-the-badge https://img.shields.io/badge/Coverage-100%25-success?style=for-the-badge https://img.shields.io/pypi/v/unipatch.svg?style=for-the-badge https://img.shields.io/badge/code%20style-black-000000.svg?style=for-the-badge pre-commit

Apply unified diffs in memory, compatible with GNU patch.

A quick example:

>>> import textwrap
>>> import unipatch
>>> patch = textwrap.dedent(
...     """\
...     @@ -1,2 +1,3 @@
...      apples
...      bananas
...     +cherries
...     """
... )
>>> print(unipatch.apply_patch("apples\nbananas\n", patch))
apples
bananas
cherries

Installation

Use pip:

python -m pip install unipatch

Python 3.10 to 3.15 supported.

API

apply_patch(source: str, patch: str, forwards: bool=True)

Apply the unified diff in the string patch to the string source and return the resulting string. Pass forwards=False to apply the patch in reverse, undoing it instead.

Raises PatchError if the patch cannot be parsed or does not apply.

>>> unipatch.apply_patch("a\nb\n", "@@ -1 +1 @@\n-a\n+c\n")
'c\nb\n'
>>> unipatch.apply_patch("c\nb\n", "@@ -1 +1 @@\n-a\n+c\n", forwards=False)
'a\nb\n'

PatchError

The base exception class, a subclass of ValueError. It has two subclasses:

  • PatchParseError: the patch is not valid unified diff format.

  • HunkApplyError: the patch parsed, but a hunk’s lines do not match the source.

Exception messages name the failing hunk and what went wrong.

Behaviour

unipatch follows the behaviour of the GNU patch commandline utility, verified by differentially testing against it with randomized inputs:

  • Hunks may apply at an offset from the line numbers stated in their @@ headers, matching by content, with a found offset carrying forward to later hunks.

  • A fuzz factor ignores up to two mismatching context lines at the edges of a hunk. Ignored context lines are left as they are in the source. A hunk with less context on one side, as diff produces at the start or end of a file, only applies at that edge of the source.

  • Oddities are tolerated like GNU patch:

    • Hunks cut short at the end of the patch

    • Context lines that have lost their leading space (empty and tab-led lines)

    • \ No newline at end of file markers

Only unified diff format is supported, not the older context or ed formats. Hence the name is unipatch.

Metadata

Release files for unipatch 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for unipatch 1.0.1
File Size Uploaded
unipatch-1.0.1.tar.gz 8.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for unipatch 1.0.1
File Interpreter ABI Platform
unipatch-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 17.6 kB

Release files / unipatch-1.0.1.tar.gz

Download URL unipatch-1.0.1.tar.gz
Size 8.7 kB
Tags Source
SHA-256 checksum
How to use checksums
876199e2ca3e74fb45afa6fb15caf8a5f076556dbecc3fc4864488bfe3b2b07f
BLAKE2b-256 checksum
How to use checksums
812e6e2bce2bd3dbb78db45f1820f9c1288e702395346a13c0e11ae3ff005f5c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.

Transparency log

Release files / unipatch-1.0.1-py3-none-any.whl

Download URL unipatch-1.0.1-py3-none-any.whl
Size 8.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1994cec00483584ba13290a0745b6c81cf6bb0e557a77ffdfaed668c59ed4218
BLAKE2b-256 checksum
How to use checksums
e5e3a0da2ea893901615f43caeb0d7613bc60b9c4d7140ab20f3ec745f9ecf45
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page