Skip to main content

similar-rs

PyPI CI Python versions License

Rust-powered text diffing for Python: bindings to the similar crate by Armin Ronacher. It also ships a drop-in replacement for the standard library's difflib that runs 2-4x faster on real file diffs and ~200x on accurate whole-file similarity — on tiny inputs it is a wash. It also adds six diff algorithms stdlib does not have.

Bar chart comparing stdlib difflib and similar-rs on three workloads: about the same on a tiny diff, 4x faster on a real file diff, about 200x faster on accurate whole-file similarity.

Real CPython sources, one Apple M4 — per-pair tables in benchmarks/results.md.

Install

pip install similar-rs

Wheels: Linux (x86_64, aarch64), macOS (arm64, x86_64) and Windows (AMD64). They are abi3 — one wheel per platform, CPython 3.9+. No system dependencies. An sdist is published too; building from it needs a Rust toolchain.

Usage

import similar

print(similar.unified_diff("a\nb\n", "a\nc\n", header=("old", "new")))

TextDiff computes the diff once and exposes the opcodes and a similarity ratio:

d = similar.TextDiff("a\nb\n", "a\nc\n", granularity="lines")
d.ops()    # [("equal", (0, 1), (0, 1)), ("replace", (1, 2), (1, 2))]
d.ratio()  # 0.5

granularity is lines, words or chars. algorithm is one of myers (default), raw-myers, patience, lcs, hunt or histogram; both TextDiff and unified_diff accept it.

difflib drop-in

Change one import line — SequenceMatcher, unified_diff and get_close_matches then run on Rust:

from similar import difflib  # instead of: import difflib

difflib.SequenceMatcher(None, "kitten", "sitting").ratio()  # 0.6153...
"".join(difflib.unified_diff(["a\n", "b\n"], ["a\n", "c\n"], "old", "new"))

difflib compatibility

API Status
SequenceMatcher.ratio, quick_ratio, real_quick_ratio Rust
SequenceMatcher.get_opcodes, get_matching_blocks, get_grouped_opcodes Rust
unified_diff, get_close_matches Rust
Differ, HtmlDiff, ndiff, context_diff, restore, diff_bytes stdlib passthrough
SequenceMatcher.find_longest_match stdlib passthrough

Known differences:

  • isjunk and autojunk are ignored; passing an isjunk raises a RuntimeWarning.
  • Opcodes are a valid edit script, but not byte-for-byte the one stdlib produces — it is a different algorithm, finding a different (as a rule, no smaller) set of matches. ratio() and get_opcodes() can therefore differ from stdlib's at either autojunk setting, not just autojunk=True.
  • get_close_matches can return a different set for the same reason: the underlying ratios differ. The tie order among equal ratios matches stdlib.
  • find_longest_match runs stdlib's algorithm with autojunk=False, so its result can differ from a default stdlib matcher's (autojunk=True) — and it may name a block that get_matching_blocks() of the same object (Rust opcodes) does not contain.
  • Inputs must be str or sequences of str.
  • The stdlib instance attributes b2j, bjunk, bpopular, opcodes and matching_blocks are absent; the caches are private.
  • Strings holding lone surrogates (as diff_bytes produces) cannot cross into Rust, so they take a slow pure-Python fallback via stdlib difflib.

Limitations

No isjunk/autojunk, str only (no bytes), and no grapheme or Unicode-word granularity yet. Open an issue if you need any of these.

Benchmarks

The same three workloads as the chart above, measured on real CPython sources (v3.9.0 vs v3.13.0 releases):

workload stdlib similar-rs speedup
two-line diff (call overhead) 3.7 us 2.9 us 1.3x
real file diff (argparse.py, 2,669 lines) 3.7 ms 0.9 ms 4.0x
accurate similarity of two ~35 KB files (autojunk=False) 23.8 s 120 ms 198.1x

Why the floor is a few times, not more: stdlib difflib is not naive — it hashes lines once and diffs the hashes through C-backed dicts, so a Rust port removes the interpreter, not the algorithm. Across five real file pairs the win is 1.1-4.0x, growing with how much of the file changed.

Why the ceiling is ~200x: stdlib's autojunk heuristic trades accuracy for speed, and on char-level input it discards most of the alphabet. Turn it off for an accurate answer and stdlib exceeded a 30 s cap on four of the five pairs, while similar-rs stays under 0.7 s. The heuristic also has bad days of its own: on the difflib.py pair stdlib's default ran 712 ms against our 3 ms. With autojunk on, the two libraries price the answer differently — our default ratio is coarser than stdlib's on some inputs; algorithm="raw-myers" returns a better match set than accurate stdlib at a fraction of its cost.

Crossing into Rust costs a fixed ~2 us per call, which only shows on inputs too small to contain work — that is the first row. For whole texts, prefer the native entry point (similar.unified_diff): the line splitting and formatting happen in Rust too.

When to use it:

you are doing what you get
diffs in a hot loop (services, CI, batch pipelines) typically 2-4x for a one-line import change
accurate similarity of long texts (dedup, fuzzy matching) the 200x class: feasible where stdlib times out
git-style diffs (patience, histogram) algorithms stdlib does not have at any speed

benchmarks/results.md has the per-pair tables and the exact method; python benchmarks/bench.py reproduces all of it, charts included. One machine, one benchmark — try it on yours.

Contributing

Issues and PRs welcome. Build from a clone:

uv venv && uv pip install maturin pytest hypothesis
maturin develop
pytest

License

Apache-2.0 (see LICENSE). The difflib-compatible formatting code in python/similar/difflib.py is derived from CPython's difflib and is covered by the PSF License Version 2; see the notice at the end of LICENSE. The wheel statically links the Rust crates it is built from; their licenses are collected in LICENSE-THIRD-PARTY, which ships inside the wheel.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

similar_rs-0.1.0.tar.gz (58.8 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

similar_rs-0.1.0-cp39-abi3-win_amd64.whl (557.2 kB view details)

Uploaded CPython 3.9+Windows x86-64

similar_rs-0.1.0-cp39-abi3-manylinux_2_28_x86_64.whl (703.4 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ x86-64

similar_rs-0.1.0-cp39-abi3-manylinux_2_28_aarch64.whl (650.2 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ ARM64

similar_rs-0.1.0-cp39-abi3-macosx_11_0_arm64.whl (621.5 kB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

similar_rs-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl (677.7 kB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file similar_rs-0.1.0.tar.gz.

File metadata

  • Download URL: similar_rs-0.1.0.tar.gz
  • Upload date:
  • Size: 58.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for similar_rs-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c38f881bc621e7a60fd8a67d980816ac9482553fc45a67c10396e2b2d13d3433
MD5 b738458a3bac17ae77baa906d913b718
BLAKE2b-256 73f3f12654efbfb5208515c0a0d88f9380662c30b01fcda7c120f2e618b6fab9

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.0.tar.gz:

Publisher: wheels.yml on Maksim-Burtsev/similar-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file similar_rs-0.1.0-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: similar_rs-0.1.0-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 557.2 kB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for similar_rs-0.1.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 7d1f019323968ba6f2c62ae969b857806fe5a5e1c7866af8c64d6041390a3e11
MD5 5700278176257e64573b790df310e6ac
BLAKE2b-256 8b9d99cdaf2ab5715ef3ad3fcbd0ebd69886770fa458eee3d290225a49ef4f1a

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.0-cp39-abi3-win_amd64.whl:

Publisher: wheels.yml on Maksim-Burtsev/similar-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file similar_rs-0.1.0-cp39-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for similar_rs-0.1.0-cp39-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 0253f17ad5c0cebbbc00258fa7c6c5560d2add966cc7bb189e64e4f8b9aa91fb
MD5 92d5f1727e40f2276df341fb0cc22363
BLAKE2b-256 c8b8fa72f94d8a7e0f6136176f7d4c4a0939054b3407c10722143cb3af367b8a

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.0-cp39-abi3-manylinux_2_28_x86_64.whl:

Publisher: wheels.yml on Maksim-Burtsev/similar-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file similar_rs-0.1.0-cp39-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for similar_rs-0.1.0-cp39-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 e16c811acf24a15707b8fbe97c6e12f936143dbbc5bbca9122b81fe66d33a699
MD5 8a745813b59780360c20ca27fe851a3e
BLAKE2b-256 eb325b17fbd35e43ea064d86deaaca12c84f02d0f7f11416f57de34f7c3e50c6

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.0-cp39-abi3-manylinux_2_28_aarch64.whl:

Publisher: wheels.yml on Maksim-Burtsev/similar-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file similar_rs-0.1.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for similar_rs-0.1.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a180cbd5bd6dde6f76c4e978eba8afb64ed275fdea49e56eaec3e457650fde6d
MD5 f089a082b95a2f681c783613a822d50b
BLAKE2b-256 baf559f0b408999be7284482e0bf3abc635abe84ecbbb496443164ae6038b6fc

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.0-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: wheels.yml on Maksim-Burtsev/similar-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file similar_rs-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for similar_rs-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 52116a47f7fec0ef35f94a5030f596d7018bf1886a8eabba4a22e712fc0bcf30
MD5 8d1968973392b3b3b2e24724fbea5f56
BLAKE2b-256 ef709fe2324dcf9bc3e97ce4629c3ff75c4ca3a581c0465ef6d234924203bf0b

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl:

Publisher: wheels.yml on Maksim-Burtsev/similar-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.1

6 files

This release

0.1.0 This release

6 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