How to make DeepDiff output human readable?

3.1k views Asked by At

DeepDiff results look like:

{'dictionary_item_added': [root[5], root[6]], 'dictionary_item_removed': [root[4]]}

For human review of changes, this only works for small examples. I need something like the code file differences displayed in GitHub commits and pull requests but for json.

So here is my question:

How to convert DeepDiff output to something like human readable diff?

Why I don't want to drop DeepDiff and use git-diff

Unlike in code, json does not care about format and json doesn't care about order of keys in dictionaries.

I could get around not using DeepDiff by pre-sorting all dictionaries in json and then comparing them with git-diff. Yet writing files to disk and shelling out to git-diff is messy. Just doing DeepDiff(t1, t2) is very clean.

The example I'm looking at is:

from deepdiff import DeepDiff
t1 = {1:1, 3:3, 4:4}
t2 = {1:1, 3:3, 5:5, 6:6}
ddiff = DeepDiff(t1, t2)
print(ddiff)

Specifics that I'm looking for

I'd like to see words highlighted within values that got changed, like so:

diff with words highlighted With a few differences:

  • This is an example of code but it works for json just as well
  • I only need this for text-based terminals that support ANSI colors
  • I'm looking on how to do this in Python or C++
  • The GitHub screenshot has the idea that I like: show lines with - / + and highlight words within each line
1

There are 1 answers

9
LeoDog896 On

difflib's ndiff may be what you're trying to accomplish:

import difflib
import json
from typing import Callable

t1 = {1:1, 3:3, 4:4}
t2 = {1:1, 3:3, 5:5, 6:6}

RED: Callable[[str], str] = lambda text: f"\u001b[31m{text}\033\u001b[0m"
GREEN: Callable[[str], str] = lambda text: f"\u001b[32m{text}\033\u001b[0m"

def get_edits_string(old: str, new: str) -> str:
    result = ""

    lines = difflib.ndiff(old.splitlines(keepends=True), new.splitlines(keepends=True))
    
    for line in lines:
        line = line.rstrip()
        if line.startswith("+"):
            result += GREEN(line) + "\n"
        elif line.startswith("-"):
            result += RED(line) + "\n"
        elif line.startswith("?"):
            continue
        else:
            result += line + "\n"

    return result

print(
    get_edits_string(
        json.dumps(t1, indent=4, sort_keys=True),
        json.dumps(t2, indent=4, sort_keys=True)
    )
)

enter image description here

The benefit for this can also be helpful in the case of CLIs -- I've filtered it in the code, but it also has color-less diffs with a ? marking where the changes are.