Part 2 — Working with Paths¶
This part shows how to enumerate, navigate, filter, and analyse the paths
of a NestedDictionary. For the underlying concepts,
see Paths and Compact Paths.
Listing all paths¶
Call paths() to obtain a
PathsView — a lazy view that enumerates every node
in the tree, from root to leaves:
from ndict_tools import NestedDictionary
nd = NestedDictionary({
"config": {"host": "localhost", "port": 5432},
"debug": True,
})
pv = nd.paths()
for path in pv:
print(path)
# ['config']
# ['config', 'host']
# ['config', 'port']
# ['debug']
len(pv) # 4
['debug'] in pv # True
['config', 'db'] in pv # False
The view is computed once on first access and cached — subsequent iterations and membership tests reuse the same internal tree.
Filtering paths¶
Pass a predicate to filter_paths() to
select a subset:
# Only paths deeper than one level
pv.filter_paths(lambda p: len(p) > 1)
# [['config', 'host'], ['config', 'port']]
# Paths that contain the key 'host'
pv.filter_paths(lambda p: 'host' in p)
# [['config', 'host']]
# Leaf paths under 'config'
pv.filter_paths(lambda p: p[0] == 'config' and not pv.has_children(p))
# [['config', 'host'], ['config', 'port']]
Searching by key name¶
When you don’t know the exact path but know the key name, use the search methods directly on the dictionary:
nd = NestedDictionary({
"prod": {"db": {"host": "prod.db", "port": 5432}},
"staging": {"db": {"host": "stg.db", "port": 5432}},
})
nd.is_key("host") # True — exists somewhere
nd.occurrences("host") # 2 — found at two paths
nd.key_list("host")
# [('prod', 'db', 'host'), ('staging', 'db', 'host')]
nd.items_list("host")
# ['prod.db', 'stg.db']
Working with compact paths¶
A CompactPathsView groups siblings under their
shared parent. It is useful for inspecting structure at a glance and for
coverage analysis.
cpv = nd.compact_paths()
cpv.structure
# [['prod', ['db', 'host', 'port']], ['staging', ['db', 'host', 'port']]]
Convert between the two views freely:
# PathsView → CompactPathsView
cpv = nd.paths().to_compact()
# CompactPathsView → PathsView
pv2 = cpv.to_paths()
Checking coverage¶
Use a CompactPathsView to measure how much of a
nested dictionary a given path set describes.
A typical use case is validating that an incoming payload covers all keys required by a template:
from ndict_tools import NestedDictionary
# Required structure — values are irrelevant, keys matter
template = NestedDictionary({
"user": {"name": None, "email": None},
"settings": {"theme": None},
})
spec = template.compact_paths()
# Incoming payload
payload = NestedDictionary({
"user": {"name": "Alice", "email": "alice@example.com"},
"settings": {"theme": "dark"},
})
spec.is_covering(payload) # True — all required paths present
spec.coverage(payload) # 1.0
spec.uncovered_paths(payload) # []
spec.missing_paths(payload) # []
If the payload is incomplete:
incomplete = NestedDictionary({
"user": {"name": "Bob"}, # missing 'email'
"settings": {"theme": "light"},
})
spec.is_covering(incomplete) # False
spec.coverage(incomplete) # 0.8 — 4 of 5 paths covered
spec.uncovered_paths(incomplete) # [['user', 'email']]