deepdiff icon indicating copy to clipboard operation
deepdiff copied to clipboard

(Colored) View: Do not show unchanged keys in changed dictionaries

Open ubmarco opened this issue 6 months ago • 3 comments

Is your feature request related to a problem? Please describe. I have 2 huge root dictionaries (40k keys) and want to run a single comparison on them. Only a couple of keys commonly differ. I want to generate a colored output (or other formats such as .md or html in future) only for the changed keys. If I generate the view for the root dictionaries, I get a huge lot of unchanged keys reported that users are not interested in:

{
  "xxx": {
    "type": "something",
    "status": "other" -> "active",
  },
  "yyy": {...},
  "yyy1": {...},
  "yyy2": {...},
  "yyy3": {...},
  "yyy4": {...},
}

Can I exclude unchanged root keys already now? If not, is there a mechanism for custom views / report types?

Describe the solution you'd like For dictionary comparisons, generate views that exclude unchanged root keys from the report/view.

Describe alternatives you've considered

  • Run the comparison multiple times, first for the root dictionaries to find changed keys, then individual diffs on those. That's a performance nightmare.
  • Post-process the colored output to textually filter the unchanged keys. That's bad engineering.
  • A new option to generate a view from a given diff result for a specific path in the result, that I can call for all changed root keys.
  • Build a custom report from a tree view on my side. Can do that, but would benefit from some guidance / best effort method.

Additional context

ubmarco avatar Sep 15 '25 11:09 ubmarco

Ok, I went and copied https://github.com/seperman/deepdiff/blob/master/deepdiff/colored_view.py to my project. From there I modified it with a new flag hide_unchanged_root_keys that is used in _colorize_json:

    def _path_is_dict_root(self, path: str) -> bool:
        """Check if a path is the root of a dictionary."""
        return path.startswith("root['") and path.endswith("']") and path.count("'") == 2

    def _colorize_json(self, obj: Any, path: str = "root", indent: int = 0) -> str:
        ...
        if isinstance(obj, dict):
            ...
            for key, value in obj.items():
                if (new_path in self.diff_paths and self.diff_paths[new_path][0] == "added"):
                    ...
                else:
                    new_value = self._colorize_json(value, new_path, indent + 1)
                    if not (
                        self.hide_unchanged_root_keys
                        and self._path_is_dict_root(new_path)
                        and new_value == "{...}"
                    ):
                        items.append(f'{next_indent}"{key}": {new_value}')
            ...

Works for me, but the detection of whether I am on the root feels ugly.

ubmarco avatar Sep 16 '25 09:09 ubmarco

Facing the same issue,

Image It would be nice if there was a built-in way to only show the changed items rather than all of them.

Arshadwaqas115 avatar Nov 25 '25 14:11 Arshadwaqas115

yes - working with @Arshadwaqas115 and would love to see an "Ultra Compact" view that shows changes only

e.g. working from you example: https://zepworks.com/deepdiff/current/colored_view.html#colored-compact-view

Current Compact View

from deepdiff import DeepDiff
from deepdiff.helper import COLORED_COMPACT_VIEW

t1 = {"name": "John", "age": 30, "scores": [1, 2, 3], "address": {"city": "New York", "zip": "10001"}}
t2 = {"name": "John", "age": 31, "scores": [1, 2, 4], "address": {"city": "New York", "zip": "10001"}, "new": "value"}

diff = DeepDiff(t1, t2, view=COLORED_COMPACT_VIEW)
print(diff)

{
  "name": "John",
  "age": 30 -> 31,
  "scores": [
    1,
    2,
    3 -> 4
  ],
  "address": {...},
  "new": "value"
}

Proposed Ultra-Compact View

from deepdiff import DeepDiff
from deepdiff.helper import COLORED_ULTRACOMPACT_VIEW

t1 = {"name": "John", "age": 30, "scores": [1, 2, 3], "address": {"city": "New York", "zip": "10001"}}
t2 = {"name": "John", "age": 31, "scores": [1, 2, 4], "address": {"city": "New York", "zip": "10001"}, "new": "value"}

diff = DeepDiff(t1, t2, view=COLORED_ULTRACOMPACT_VIEW)
print(diff)

{
  "age": 30 -> 31,
  "scores": [
    3 -> 4
  ],
  "new": "value"
}

jgunstone avatar Nov 26 '25 11:11 jgunstone