Skip to main content

High-performance JSON comparison library with Zig-powered core

Project description

fastjsondiff

A high-performance Python library for comparing JSON payloads, powered by a Zig core for maximum speed.

Features

  • Fast: Zig-powered core delivers sub-millisecond comparisons for typical payloads
  • Complete: Detects added, removed, and changed values with full path reporting
  • Deep: Handles arbitrarily nested structures (objects and arrays)
  • Scalable: Efficiently processes multi-megabyte JSON files
  • Pythonic: Clean API with iteration, filtering, and serialization support

Installation

pip install fastjsondiff-zig

Or using uv:

uv add fastjsondiff-zig

Development Installation

# Clone the repository
git clone https://github.com/adilkhash/fastjsondiff.git
cd fastjsondiff

# Build the Zig core
cd fastjsondiff/_zig
zig build
cd ../..

# Install in development mode
pip install -e .

# Or using uv
uv pip install -e .

Quick Start

import fastjsondiff

# Compare two JSON strings
result = fastjsondiff.compare(
    '{"name": "Alice", "age": 30}',
    '{"name": "Bob", "age": 30, "city": "NYC"}'
)

# Check if there are differences
if result:
    print(f"Found {len(result)} differences")

# Iterate over differences
for diff in result:
    print(f"{diff.type.value}: {diff.path}")
    print(f"  old: {diff.old_value}")
    print(f"  new: {diff.new_value}")

Output:

Found 2 differences
changed: root.name
  old: "Alice"
  new: "Bob"
added: root.city
  old: None
  new: "NYC"

API Reference

compare(a, b, *, array_match="index")

Compare two JSON payloads and return their differences.

Parameters:

  • a: First JSON input (string or bytes)
  • b: Second JSON input (string or bytes)
  • array_match: Array comparison strategy ("index" for position-based comparison)

Returns: DiffResult containing all differences found

Raises:

  • InvalidJsonError: If either input is not valid JSON
  • TypeError: If inputs are not string or bytes
result = fastjsondiff.compare('{"a": 1}', '{"a": 2}')

compare_files(path_a, path_b, *, array_match="index", encoding="utf-8")

Compare two JSON files.

Parameters:

  • path_a: Path to first JSON file
  • path_b: Path to second JSON file
  • array_match: Array comparison strategy
  • encoding: File encoding (default: utf-8)

Returns: DiffResult containing all differences found

result = fastjsondiff.compare_files("old.json", "new.json")

DiffResult

Container for comparison results.

result = fastjsondiff.compare(json_a, json_b)

# Length and boolean
len(result)      # Number of differences
bool(result)     # True if any differences exist

# Iteration
for diff in result:
    print(diff.path)

# Index access
first_diff = result[0]

# Filtering
added = result.filter(DiffType.ADDED)
removed = result.filter(DiffType.REMOVED)
changed = result.filter(DiffType.CHANGED)

# Summary
result.summary.added      # Count of added items
result.summary.removed    # Count of removed items
result.summary.changed    # Count of changed items
result.summary.total      # Total differences

# Metadata
result.metadata.paths_compared  # Number of paths visited
result.metadata.max_depth       # Maximum nesting depth
result.metadata.duration_ms     # Comparison time in milliseconds

# Serialization
result.to_dict()          # Convert to dictionary
result.to_json()          # Convert to JSON string
result.to_json(indent=2)  # Pretty-printed JSON

Difference

Represents a single difference.

diff.type       # DiffType.ADDED, DiffType.REMOVED, or DiffType.CHANGED
diff.path       # JSON path (e.g., "root.users[0].name")
diff.old_value  # Previous value (None for ADDED)
diff.new_value  # New value (None for REMOVED)
diff.to_dict()  # Serialize to dictionary

DiffType

Enum of difference types:

from fastjsondiff import DiffType

DiffType.ADDED    # Key/element exists in second input only
DiffType.REMOVED  # Key/element exists in first input only
DiffType.CHANGED  # Value differs between inputs

Path Format

Paths use dot notation for object keys and bracket notation for array indices:

  • root.name - Object key
  • root.users[0] - Array element
  • root.users[0].email - Nested path

Performance

Benchmarks on typical hardware:

Payload Size Keys Time
2 KB 100 0.2 ms
23 KB 1,000 2.4 ms
252 KB 10,000 24 ms
1.3 MB 50,000 122 ms

Examples

Detecting Configuration Changes

import fastjsondiff

old_config = '{"debug": false, "port": 8080}'
new_config = '{"debug": true, "port": 8080, "host": "0.0.0.0"}'

result = fastjsondiff.compare(old_config, new_config)

for diff in result:
    if diff.type == fastjsondiff.DiffType.CHANGED:
        print(f"Modified: {diff.path}")
    elif diff.type == fastjsondiff.DiffType.ADDED:
        print(f"New setting: {diff.path}")

Comparing API Responses

import fastjsondiff
import json

response_v1 = '{"users": [{"id": 1, "name": "Alice"}]}'
response_v2 = '{"users": [{"id": 1, "name": "Alice", "email": "alice@example.com"}]}'

result = fastjsondiff.compare(response_v1, response_v2)

if result:
    print("API response changed:")
    print(result.to_json(indent=2))

Filtering by Change Type

import fastjsondiff
from fastjsondiff import DiffType

result = fastjsondiff.compare(old_json, new_json)

# Get only added fields
new_fields = result.filter(DiffType.ADDED)
print(f"{len(new_fields)} new fields added")

# Get only removed fields
removed_fields = result.filter(DiffType.REMOVED)
print(f"{len(removed_fields)} fields removed")

Requirements

  • Python 3.10+
  • Zig 0.15.2 (for building from source)

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Run tests (pytest tests/)
  4. Commit your changes (git commit -m 'Add amazing feature')
  5. Push to the branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

Project details


Download files

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

Source Distribution

fastjsondiff_zig-26.1.tar.gz (209.4 kB view details)

Uploaded Source

Built Distributions

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

fastjsondiff_zig-26.1-py3-none-win_amd64.whl (158.9 kB view details)

Uploaded Python 3Windows x86-64

fastjsondiff_zig-26.1-py3-none-manylinux_2_17_x86_64.whl (199.7 kB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

fastjsondiff_zig-26.1-py3-none-macosx_11_0_arm64.whl (76.4 kB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file fastjsondiff_zig-26.1.tar.gz.

File metadata

  • Download URL: fastjsondiff_zig-26.1.tar.gz
  • Upload date:
  • Size: 209.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fastjsondiff_zig-26.1.tar.gz
Algorithm Hash digest
SHA256 3931059a8811d39a1807818f87e70266bcf48b44d065ab496ec44ed1c35bbd67
MD5 db731e6564a6475c234ab79740a411a6
BLAKE2b-256 325ee7d1eb9983820702664805a1a6fd98bf8aaae280494cbe807f6d0a581574

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastjsondiff_zig-26.1.tar.gz:

Publisher: ci.yml on adilkhash/fastjsondiff

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

File details

Details for the file fastjsondiff_zig-26.1-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for fastjsondiff_zig-26.1-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 bb78dc76ff60e8d47f0b409b866b51db0927006a16fc6845f7321227271e463e
MD5 9788e13e1a0c24624abad4406f8d3f29
BLAKE2b-256 f56220f23f6c038adbc8d67f6e7b9980a4c620bd73f579a573e5dddea1bb8a6e

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastjsondiff_zig-26.1-py3-none-win_amd64.whl:

Publisher: ci.yml on adilkhash/fastjsondiff

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

File details

Details for the file fastjsondiff_zig-26.1-py3-none-manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for fastjsondiff_zig-26.1-py3-none-manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 2ac0c7159e5088f7944ac4379ca9c55443a9858fa6702e886efa5be32f72c291
MD5 439202d5ddcdf7a205d3bad42e2d9903
BLAKE2b-256 9763d78f4955105f8a9e88ae9fe7ff888c28006f212f04fb1b6e3c3cdc559852

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastjsondiff_zig-26.1-py3-none-manylinux_2_17_x86_64.whl:

Publisher: ci.yml on adilkhash/fastjsondiff

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

File details

Details for the file fastjsondiff_zig-26.1-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for fastjsondiff_zig-26.1-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a6444e37f19d377d2bd30d1ca1b9d9ad7a01fb4c3d898b07d5b5e4e5a77adcc2
MD5 e29768574de0cdb9d7dff56430cc8c15
BLAKE2b-256 b3f491887def17b4e7e5258e94c3551b877cf65950911458539da3b7e1103804

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastjsondiff_zig-26.1-py3-none-macosx_11_0_arm64.whl:

Publisher: ci.yml on adilkhash/fastjsondiff

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page