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