Skip to content

Instantly share code, notes, and snippets.

@euccas
Last active March 5, 2022 02:46
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save euccas/273764b6ec57142655ef6ff01bc8d83b to your computer and use it in GitHub Desktop.
Save euccas/273764b6ec57142655ef6ff01bc8d83b to your computer and use it in GitHub Desktop.
compare yaml files, report diff in tags, recursively
def rdiff(yamla, yamlb, path='', key=getkey):
if isinstance(yamla, list) and isinstance(yamlb, list):
for d in listdiff(yamla, yamlb, path=path, key=key):
yield d
elif isinstance(yamla, dict) and isinstance(yamlb, dict):
for d in dictdiff(yamla, yamlb, path=path, key=key):
yield d
else:
if yamla != yamlb:
yield (path, 'value_difference', yamla, '-->', yamlb)
def listdiff(yamla, yamlb, path, key):
""" compute the differences between two lists, as a generator
:param list yamla: list of python objects
:param list yamlb: list of python objects
:param str path: path of current node (same idea as XPath)
:param callable key: key lambda used for sorting
"""
yamla = {key(v, i): v for i, v in enumerate(yamla)}
yamlb = {key(v, i): v for i, v in enumerate(yamlb)}
keysa = set(yamla.keys())
keysb = set(yamlb.keys())
for a in [k for k in keysb.difference(keysa)]:
yield (path + '/' + a, 'added')
for m in [k for k in keysa.difference(keysb)]:
yield (path + '/' + m, 'missing')
common = [k for k in keysa.intersection(keysb) if k]
for k in common:
if (isinstance(yamla[k], list) and isinstance(yamlb, list)) \
or (isinstance(yamla[k], dict) and isinstance(yamlb, dict)):
for d in rdiff(yamla[k], yamlb[k], path + '/' + k):
yield d
else:
for d in rdiff(yamla[k], yamlb[k], path + '/' + k, key):
yield d
def dictdiff(yamla, yamlb, path, key):
"""compute the difference between two dictionaries, as a generator
:param dict yamla: first dictionary
:param dict yamlb: second dictionary to compare with first one
:param str path: path of current node (same idea as XPath)
:param callable key: key lambda used for sorting
"""
keysa = set(yamla.keys())
keysb = set(yamlb.keys())
for a in [k for k in keysb.difference(keysa)]:
yield (path + '/' + a, 'added')
for m in [k for k in keysa.difference(keysb)]:
yield (path + '/' + m, 'missing')
common = [k for k in keysa.intersection(keysb) if k]
for k in common:
if (isinstance(yamla[k], list) and isinstance(yamlb[k], list)) \
or (isinstance(yamla[k], dict) and isinstance(yamlb[k], dict)):
for d in rdiff(yamla[k], yamlb[k], path + '/' + k, key):
yield d
else:
for d in rdiff(yamla[k], yamlb[k], path + '/' + k, key):
yield d
@usedToCode
Copy link

i am using your code to help learn python. Can you let me know what the getkey function looks like. This way i can run it to see how it works and what it does

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment