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.1.tar.gz (58.9 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.1-cp39-abi3-win_amd64.whl (557.2 kB view details)

Uploaded CPython 3.9+Windows x86-64

similar_rs-0.1.1-cp39-abi3-manylinux_2_28_x86_64.whl (703.3 kB view details)

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

similar_rs-0.1.1-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.1-cp39-abi3-macosx_11_0_arm64.whl (621.5 kB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

similar_rs-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl (674.3 kB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

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

File metadata

  • Download URL: similar_rs-0.1.1.tar.gz
  • Upload date:
  • Size: 58.9 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.1.tar.gz
Algorithm Hash digest
SHA256 8ebe07fb8b7de193cc731940d338b5965767871e1f8be127cd556c6ccb16953a
MD5 4887a3ed4fc3fdcc3f76aa3f6ee17219
BLAKE2b-256 e698cfe41a27789882c35383ee8558bcbdac32ab2ef11839ba117b096de350e0

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.1.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.1-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: similar_rs-0.1.1-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.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 a4f217e18f15f7fc89b85499777597127f5ea01d3dc3a94fee926d86a04ff7fa
MD5 8c52ecac3de25dd33b41fb37d7fa958b
BLAKE2b-256 83322a14f142f7e0e2a6b951dc24da512b8e7bc094990bd05fc264c35d6b80b5

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.1-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.1-cp39-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for similar_rs-0.1.1-cp39-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6cb0b51e79d7bdabb6f20a0af971c0d3f47d7e0e5dc993eeb98e5ca321b1725c
MD5 64ea0582b164b42cf1c7a975d2be12ba
BLAKE2b-256 9ff245b6912a80e19d468d92bf9b93cbeaebf0f4e98583794e64cd90846db0a8

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.1-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.1-cp39-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for similar_rs-0.1.1-cp39-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 6253fbcfed90df5492e97af0a48630911b714ca5acefdc29e72710d3fef7a4e0
MD5 6da4b5a2086d33edda4c4dcc5b7795c3
BLAKE2b-256 c85397ff2cd8d46af89b68276cad812574307096bd0fc5daee48e92c343ebd4b

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.1-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.1-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for similar_rs-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6ac5f3845931550f426cad8e0eda776ebd637866a4799f4b6c2543757298a6dc
MD5 a14bcdb2f3727eaa61cf7c83582984bd
BLAKE2b-256 821dc16887a3e6ebcdfe216b4c952e440075ef55040f55334658d0ee76a64480

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.1-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.1-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for similar_rs-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 d40f118b65ce03d830c949f0879ff228447784a99d71b85613a3983277e96e4e
MD5 31d5690392dc1c9489578b8675b7b47a
BLAKE2b-256 b3e2ec3483ab58b88ed37a593248a3964d228406f3a6390152a4be243cf87ff0

See more details on using hashes here.

Provenance

The following attestation bundles were made for similar_rs-0.1.1-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

This release

0.1.1 This release

6 files

0.1.0

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