Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Iterative Dvc Utils Diff

From Leeroopedia


Knowledge Sources
Domains Utilities, Data_Comparison
Last Updated 2026-02-10 10:00 GMT

Overview

Concrete tool for computing structured differences between old and new data dictionaries using XPath-based flattening, provided by the DVC library.

Description

The diff function in dvc/utils/diff.py is the main entry point for comparing two versioned data dictionaries. It is used primarily by the dvc diff, dvc params diff, and dvc metrics diff commands to produce human-readable difference reports between revisions.

The function accepts two dictionaries (old and new) keyed by file path. Each value is expected to be a dictionary with a "data" key containing the actual metrics or parameters. The function iterates over the union of all paths in both dictionaries and calls _diff for each path to compute per-path differences.

The internal _diff function first parses raw values via _parse, which handles None, native Python types (dict, list, int, float), and JSON-encoded strings. It then dispatches to _diff_dicts for dictionary values or _diff_vals for scalar values.

_diff_dicts is the core comparison engine. It flattens both old and new dictionaries into dot-separated XPath-style keys using flatten from dvc.utils.flatten (which delegates to the flatten_dict library with a dot reducer). Both flattened dictionaries are wrapped in defaultdict(lambda: None) so that missing keys return None rather than raising KeyError. The function then iterates over the union of all XPaths and calls _diff_vals for each pair of old and new values.

_diff_vals produces a result dictionary with old and new keys. When both values are numeric (int or float), it also computes a diff key containing the arithmetic difference (new - old). If with_unchanged is False (the default), identical old and new values produce an empty dictionary, effectively filtering them from the output. A special case handles single-element lists by unwrapping them before comparison.

The format_dict utility function recursively converts a nested dictionary for display purposes, converting list values to their string representations while leaving other types unchanged.

Usage

Import diff when you need to programmatically compare metrics or parameters between two DVC revisions. Import format_dict when you need to prepare diff results for display in tabular or JSON output formats.

Code Reference

Source Location

  • Repository: DVC
  • File: dvc/utils/diff.py
  • Lines: 100 total
  • Function: diff (L73-86)
  • Function: format_dict (L89-99)
  • Supporting module: dvc/utils/flatten.py

Signatures

def diff(old, new, with_unchanged=False):
    ...

def format_dict(d):
    ...

Import

from dvc.utils.diff import diff, format_dict

I/O Contract

diff

Inputs:

Name Type Required Description
old dict[str, dict] Yes A dictionary keyed by file path. Each value must contain a "data" key with the metrics/parameters data for the old revision. Missing paths are treated as empty.
new dict[str, dict] Yes A dictionary keyed by file path, structured identically to old, representing the new revision.
with_unchanged bool No If True, include entries where old and new values are identical. Defaults to False (only changed entries are returned).

Outputs:

Name Type Description
return dict[str, dict[str, dict]] A nested dictionary indexed first by file path, then by dot-separated XPath. Each leaf value is a dictionary with keys: old (the previous value or None), new (the current value or None), and optionally diff (numeric difference when both values are numeric). Empty paths (scalar diffs) use an empty string as the XPath key.

format_dict

Inputs:

Name Type Required Description
d dict Yes A nested dictionary to format for display.

Outputs:

Name Type Description
return dict A new dictionary where list values are converted to their string representations and nested dicts are recursively formatted. Other types are preserved unchanged.

Internal Functions

Function Description
_parse(raw) Parses a raw value: returns None, native types (dict, list, int, float) as-is, attempts JSON deserialization for strings, and falls back to the raw string on decode failure.
_diff_vals(old, new, with_unchanged) Compares two scalar values. Returns {"old": old, "new": new} with an optional "diff" key for numeric types. Returns empty dict if values are equal and with_unchanged is False. Unwraps single-element lists.
_flatten(d) Flattens a dictionary using dot-separated keys via flatten_dict. Returns a defaultdict with None as the default for missing keys. Returns "unable to parse" as default if input is not a dict.
_diff_dicts(old_dict, new_dict, with_unchanged) Flattens both dicts, computes the union of XPaths, and diffs each XPath pair using _diff_vals.
_diff(old_raw, new_raw, with_unchanged) Top-level dispatch: parses raw values, delegates to _diff_dicts for dict types or _diff_vals for scalars.

Usage Examples

Basic Metrics Diff

from dvc.utils.diff import diff

old = {
    "metrics.json": {
        "data": {"acc": 0.85, "loss": 0.45}
    }
}
new = {
    "metrics.json": {
        "data": {"acc": 0.91, "loss": 0.32}
    }
}

result = diff(old, new)
# result:
# {
#     "metrics.json": {
#         "acc": {"old": 0.85, "new": 0.91, "diff": 0.06},
#         "loss": {"old": 0.45, "new": 0.32, "diff": -0.13}
#     }
# }

Nested Parameters Diff

from dvc.utils.diff import diff

old = {
    "params.yaml": {
        "data": {"train": {"lr": 0.001, "epochs": 10}}
    }
}
new = {
    "params.yaml": {
        "data": {"train": {"lr": 0.01, "epochs": 10, "batch_size": 32}}
    }
}

result = diff(old, new)
# result:
# {
#     "params.yaml": {
#         "train.lr": {"old": 0.001, "new": 0.01, "diff": 0.009},
#         "train.batch_size": {"old": None, "new": 32}
#     }
# }
# Note: "train.epochs" is omitted because it is unchanged

Including Unchanged Values

from dvc.utils.diff import diff

old = {"metrics.json": {"data": {"acc": 0.9, "loss": 0.3}}}
new = {"metrics.json": {"data": {"acc": 0.9, "loss": 0.2}}}

result = diff(old, new, with_unchanged=True)
# result:
# {
#     "metrics.json": {
#         "acc": {"old": 0.9, "new": 0.9, "diff": 0.0},
#         "loss": {"old": 0.3, "new": 0.2, "diff": -0.1}
#     }
# }

Formatting Diff Results

from dvc.utils.diff import diff, format_dict

old = {"metrics.json": {"data": {"tags": ["v1", "v2"]}}}
new = {"metrics.json": {"data": {"tags": ["v1", "v2", "v3"]}}}

result = diff(old, new)
formatted = format_dict(result)
# Lists are converted to string representations for display

Related Pages

Implements Principle

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment