diffmonkey
Type-aware, key-based structural diffing of tabular datasets — answer "what changed between last month's export and this month's?" in one call, with human- and machine-readable reports.
diffmonkey matches rows by a key column (or composite key), compares the
remaining columns with type awareness (numbers by value, dates by calendar
date, booleans by truth, strings whitespace-normalised, nulls unified), and
buckets the result into added / removed / changed / unchanged with summary
statistics. It is built on the rexbytes ecosystem — typemonkey for type
inference and number parsing, datemonkey for date parsing, cleanmonkey
for whitespace and invisible-character normalisation — so it does not re-derive
those wheels.
In scope: structural comparison, change detection, change reporting. Out of scope: merge/reconciliation, text diffing, schema migration, version control.
Install
pip install diffmonkey # CSV/TSV/pipe input built in
pip install "diffmonkey[excel]" # add .xlsx reading (openpyxl)
Requires Python 3.11+.
Quick start
from diffmonkey import compare
old = [{"id": "1", "name": "Widget", "price": "1,234"},
{"id": "2", "name": "Gadget", "price": "50"}]
new = [{"id": "1", "name": "Widget", "price": "1234"}, # price reformatted, not changed
{"id": "3", "name": "Gizmo", "price": "9"}] # id 2 removed, id 3 added
result = compare(old, new, key="id")
print(result.summary.one_line())
# 1 added, 1 removed, 0 changed (of 2 current), 0 unchanged
print(result.to_markdown()) # human report
result.to_dict() # machine-readable
result.write_csv("changes.csv")
"1,234" vs "1234" is not reported as a change — type-aware numeric
comparison sees one number. The same applies to "01/02/2025" vs "2025-01-02"
(dates, with a locale hint), " foo " vs "foo" (whitespace), and
None/""/"NA" (nulls).
CLI
diffmonkey compare old.csv new.csv --key id
diffmonkey compare old.csv new.csv --key region,sku --ignore updated_at --format markdown
diffmonkey compare old.xlsx new.xlsx --key id --format json -o diff.json
Exit code is 0 when the datasets are identical and 1 when they differ —
handy in CI and scripts.
Key options
| Option | Purpose |
|---|---|
key |
Identity column, or list for a composite key |
columns / ignore |
Restrict / exclude columns from comparison |
column_map={"old":"new"} |
Handle renamed columns (avoids false add+remove) |
rel_tol / abs_tol |
Floating-point tolerance for numeric columns |
locale="us" / "eu" |
Disambiguate slash dates and number separators |
null_equivalent |
Treat all null spellings as one value (default on) |
type_aware / date_aware |
Toggle type/date-aware comparison |
include_unchanged |
Retain unchanged rows in the result |
on_duplicate / on_missing_key |
Policies for messy keys |
Output formats
result.to_dict()— JSON-serialisable structureresult.to_markdown()— report for PRs, chat, emailresult.to_html()— standalone HTML diff reportresult.to_csv()/result.write_csv(path)— one row per field change
Using with AI assistants
See SKILL.md for LLM-oriented usage (decision tree, worked
examples, anti-patterns). See LIMITATIONS.md for the
deliberate design tradeoffs (date/locale ambiguity, null vocabulary, duplicate
handling) so behaviour that looks surprising is not mistaken for a bug.
Contributing & quality
diffmonkey is tested and reviewed against an explicit quality contract. See
CONTRIBUTING.md for the testing philosophy and the
competitive multi-model review process, REVIEW_HISTORY.md
for the review trajectory, and RELEASE_READINESS.md
for the release rubric (python scripts/readiness.py).
License
MIT — see LICENSE.
Metadata
Release files for diffmonkey 1.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| diffmonkey-1.1.1.tar.gz | 54.2 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| diffmonkey-1.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 84.0 kB
Release files / diffmonkey-1.1.1.tar.gz
| Download URL | diffmonkey-1.1.1.tar.gz |
|---|---|
| Size | 54.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
874b5b8038ab882103cd277f2ddce70d3b7e11f5c81b344e618ee2359dd22d9f
|
|
BLAKE2b-256 checksum How to use checksums |
986fcca24e38ad89a52032f1b063b42a0aa2b6a0c3b0e2708879198fe3ab0197
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / diffmonkey-1.1.1-py3-none-any.whl
| Download URL | diffmonkey-1.1.1-py3-none-any.whl |
|---|---|
| Size | 29.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7342a661d4e96b52044146bf04ea91cadb50b07c76d86dae5b3c5a21036babc6
|
|
BLAKE2b-256 checksum How to use checksums |
99c009c286b44f379da07926a338af708eb24149846df19a2f1e581b2eb6454d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Security for diffmonkey 1.1.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.