Coverage

Coverage answers the question: how much of a nested dictionary does a given set of paths describe?

This is useful when you work with a partial or independently defined CompactPathsView and want to know how much of a target dictionary it accounts for.

Full coverage

A CompactPathsView built directly from a dictionary always covers it completely:

from ndict_tools import NestedDictionary

nd = NestedDictionary({"a": {"b": 1, "c": 2}, "d": 3})
cpaths = nd.compact_paths()

cpaths.is_covering(nd)   # True
cpaths.coverage(nd)      # 1.0

Partial coverage

Assign a reduced structure to simulate partial coverage:

cpaths.structure = [['a', 'b']]   # only paths ['a'] and ['a', 'b']

cpaths.is_covering(nd)   # False
cpaths.coverage(nd)      # 0.5  — 2 out of 4 paths covered

Identifying uncovered paths

uncovered_paths() returns the paths that exist in the dictionary but are absent from the compact structure:

cpaths.uncovered_paths(nd)
# [['a', 'c'], ['d']]

Identifying missing paths

missing_paths() returns the paths present in the compact structure but absent from the dictionary — useful when the structure was set manually and may contain invalid entries:

cpaths.structure = [['a', 'b', 'c'], ['d'], ['e']]   # 'e' does not exist

cpaths.missing_paths(nd)
# [['e']]

Over-coverage

Coverage can exceed 1.0 when the compact structure contains more paths than the dictionary has:

cpaths.structure = [['a', 'b', 'c'], ['d'], ['e']]
cpaths.coverage(nd)   # 1.25  — 5 paths in structure, 4 in nd, 4 match

Practical example

Suppose you receive a specification describing the expected structure of a nested dictionary, and you want to verify that an incoming payload satisfies it:

from ndict_tools import NestedDictionary

# Expected structure
expected = NestedDictionary({
    "user": {"name": None, "email": None},
    "settings": {"theme": None},
})
spec = expected.compact_paths()

# Incoming payload
payload = NestedDictionary({
    "user": {"name": "Alice", "email": "alice@example.com"},
    "settings": {"theme": "dark", "lang": "fr"},
})

spec.is_covering(payload)        # False — 'settings.lang' is extra
spec.uncovered_paths(payload)    # []    — no path from spec is missing
spec.missing_paths(payload)      # []    — no path from spec is absent
payload.compact_paths().coverage(expected)   # 1.0 — payload covers all of spec