Skip to content

Instantly share code, notes, and snippets.

@Menziess
Created June 15, 2024 15:25
Show Gist options
  • Save Menziess/6063960bf1f9f25a533c96dbff83667d to your computer and use it in GitHub Desktop.
Save Menziess/6063960bf1f9f25a533c96dbff83667d to your computer and use it in GitHub Desktop.
from typing import Iterable
def dict_diff(
old: dict,
new: dict,
ignore_keys: Iterable[str] = [],
include_keys: Iterable[str] = []
) -> dict:
"""Capture changes between dictionaries.
Additions, updates and deletions respectively:
>>> dict_diff({}, {'b': 2})
{'b': 2}
>>> dict_diff({'a': 1}, {'a': 2})
{'a': 2}
>>> dict_diff({'a': 1}, {})
{'a': None}
"""
ignore_keys, include_keys = list(ignore_keys), list(include_keys)
if include_keys:
if both := set(ignore_keys).intersection(include_keys):
raise ValueError(
f"Keys can't be in both ignore_keys and include_keys: {both}")
ignore_keys = list(
set(old)
.union(new)
.difference(set(include_keys))
)
fz_old = frozenset(sorted([
(k, v) for k, v in old.items()
if k not in ignore_keys
]))
fz_new = frozenset(sorted([
(k, v) for k, v in new.items()
if k not in ignore_keys
]))
old_updated_or_deleted = dict(fz_old.difference(fz_new))
new_updates = dict(fz_new.difference(fz_old))
deleted = {
k: None for k, _ in old_updated_or_deleted.items()
if k not in new_updates
}
new_updates |= deleted
return new_updates
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment