ProvenPin Install

DeepDiff diffing of pydantic v2 model dumps with ignore_order: working versions (tested 2026-10-15)

Compare pydantic v2 model dumps with DeepDiff, normalizing python vs json dump modes and taming list order, datetime and float gotchas.

passed6 passed · 0 failed2026-10-15 21:56 UTC
Status
passed
Last passed
2026-10-15 21:56 UTC
Tests
6 / 6
Language
Python
Runtime
Python 3.13.16
pinned versions3
deepdiff@9.1.0pydantic@2.14.1pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt
.venv/bin/python -m pytest -q
test environment
Python 3.13.16
linux 6.17.0-1022-azure
x64
runner: github-actions 38813530570

The code

Exactly the files that passed. Your agent can pull them with get_recipe("deepdiff-pydantic-compare") (install), or see them on GitHub.

requirements.txt
deepdiff==9.1.0
pydantic==2.14.1
pytest==9.1.1
compare.py
from typing import Any

from deepdiff import DeepDiff
from pydantic import BaseModel


def dump(
    model: BaseModel,
    *,
    json_mode: bool = False,
    exclude_none: bool = False,
) -> dict[str, Any]:
    return model.model_dump(
        mode="json" if json_mode else "python",
        exclude_none=exclude_none,
    )


def _as_dict(value: BaseModel | dict[str, Any], json_mode: bool, exclude_none: bool) -> dict[str, Any]:
    if isinstance(value, BaseModel):
        return dump(value, json_mode=json_mode, exclude_none=exclude_none)
    return value


def diff_models(
    left: BaseModel | dict[str, Any],
    right: BaseModel | dict[str, Any],
    *,
    ignore_order: bool = False,
    significant_digits: int | None = None,
    exclude_paths: set[str] | None = None,
    json_mode: bool = False,
    exclude_none: bool = False,
) -> DeepDiff:
    return DeepDiff(
        _as_dict(left, json_mode, exclude_none),
        _as_dict(right, json_mode, exclude_none),
        ignore_order=ignore_order,
        significant_digits=significant_digits,
        exclude_paths=exclude_paths or set(),
    )
tests/test_compare.py
import json
from datetime import datetime, timedelta, timezone

from pydantic import BaseModel

from compare import diff_models

NOW = datetime(2024, 1, 1, tzinfo=timezone.utc)


class Event(BaseModel):
    name: str
    tags: set[str] = set()
    steps: list[str] = []
    meta: dict[str, int] = {}
    at: datetime
    score: float = 0.0


def test_dict_key_order_is_ignored():
    a = Event(name="x", meta={"a": 1, "b": 2}, at=NOW)
    b = Event(name="x", meta={"b": 2, "a": 1}, at=NOW)
    assert diff_models(a, b) == {}


def test_list_order_is_significant_until_ignored():
    a = Event(name="x", steps=["build", "test"], at=NOW)
    b = Event(name="x", steps=["test", "build"], at=NOW)
    assert "values_changed" in diff_models(a, b)
    assert diff_models(a, b, ignore_order=True) == {}


def test_python_dump_vs_json_payload_types():
    a = Event(name="x", tags={"a", "b"}, at=NOW)
    wire = json.loads(a.model_dump_json())
    assert "type_changes" in diff_models(a, wire)
    assert diff_models(a, wire, json_mode=True) == {}


def test_aware_datetimes_same_instant_but_different_json():
    a = Event(name="x", at=datetime.fromisoformat("2024-01-01T00:00:00+00:00"))
    b = Event(name="x", at=datetime.fromisoformat("2023-12-31T19:00:00-05:00"))
    assert diff_models(a, b) == {}
    assert "values_changed" in diff_models(a, b, json_mode=True)


def test_float_noise_needs_significant_digits():
    a = Event(name="x", score=0.1 + 0.2, at=NOW)
    b = Event(name="x", score=0.3, at=NOW)
    assert "values_changed" in diff_models(a, b)
    assert diff_models(a, b, significant_digits=6) == {}


def test_exclude_paths_skips_volatile_fields():
    a = Event(name="x", at=NOW)
    b = Event(name="x", at=NOW + timedelta(seconds=1))
    assert "values_changed" in diff_models(a, b)
    assert diff_models(a, b, exclude_paths={"root['at']"}) == {}
pytest.ini
[pytest]
pythonpath = .

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.