Created
June 15, 2024 15:25
-
-
Save Menziess/6063960bf1f9f25a533c96dbff83667d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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