Dict Path¶
DictPath is a library for navigating json data.
The DictPath library offers a convenient way to get a specific value out of a structure of nested dicts and lists.
Writing DictPath expressions¶
A DictPath expression is a .
-separated path.
The following elements are supported:
.dkey
: Return the value underdkey
in the dict.dkey
cannot be an empty string. Use the*
character to get all values of the dictionary.lst[lkey=lvalue]
: Find a dictionary in a list of dictionaries. Find the dict withlkey=lvalue
.lvalue
can be an empty string.lst
andlkey
cannot be an empty string. If no or more than one dict matches the filter, a LookupError is raised. The*
character can be used forlkey
andlvalue
to match respectively any key or value.\0
can be used forlvalue
to match against the value``None``.If no single key uniquely identifies an object, multiple keys can be used:
lst[lkey1=lvalue1][lkey2=lvalue2]
.
Each element of the path (keys or values) must escape the following special characters with a single backslash: \
, [
, ]
, .
, *
and =
. Other characters must not be escaped.
A leading .
character represent the entire data structure provided to the dict path library. As such, the following dict paths are logically equivalent to each other: a.b.c
and .a.b.c
. A dict path can also consist of a single dot (.
). This expression represents the identity function.
Using DictPath in code¶
Warning
The dict path library only works correctly when the keys and values, referenced in a dict path expression, are of a primitive type and the type is the same for all keys and values at the same level. For example, {"True": 1, True: 2}
is not a valid dictionary.
To convert a dictpath expression to a
DictPath
instance, usedict_path.to_path
. Usedict_path.to_wild_path
in order to allow wildcards (*
) to be used in the dict path expression.To get the element from a collection use
DictPath.get_element(collection)
To set an element in a collection use
DictPath.set_element(collection, value)
- class inmanta.util.dict_path.DictPath[source]¶
- A base class for all non-wild dict paths segments. The key difference between WildDictPath and DictPath subclasses are:
WildDictPath can only get a list of elements, with get_elements. If no element is found, an empty list is returned, no error is raised.
DictPath can not use get_elements as it is always expected to have exactly one match.
DictPath can use get_element, which will return the matching element, or raise an exception if more or less than one is found.
DictPath can set values, using set_element, and can build the dict structure expected by the path by using the construct flag in the get_element method.
- abstract get_element(container: object, construct: bool = False) object [source]¶
Get the element identified by this Path from the given collection
- Parameters:
container – the container to search in
construct – construct a dict on the location identified by this path in the container if the element doesn’t exist. Return this new dict.
- Raises:
KeyError – if the element is not found or if more than one occurrence was found.
- get_elements(container: object) list[object] [source]¶
Get the elements identified by this Path from the given collection. If no element is matched, an empty list is returned.
- Parameters:
container – the container to search in
- abstract get_key() str [source]¶
Return the dictionary key referenced by this element in the dict path.
- abstract remove(container: object) None [source]¶
- Remove an element if it exists:
On an InDict or a WildInDict: Remove the referenced key from the dictionary.
On a KeyedList or a WildKeyedList: Remove the referenced element from the list.
On a NullPath: This operation is not supported on a NullPath.
- abstract set_element(container: object, value: object, construct: bool = True) None [source]¶
Set the element identified by this Path from the given collection.
If construct is True, all containers on the path towards the value are constructed if absent.
- Raises:
LookupError – if the path leading to the element is not found or if more than one occurrence was found.
Example¶
from inmanta.util import dict_path
container = {
"a": "b",
"c": {
"e": "f"
},
"g": [
{"h": "i", "j": "k"},
{"h": "a", "j": "b"}
]
}
assert dict_path.to_path("a").get_element(container) == "b"
assert dict_path.to_path("c.e").get_element(container) == "f"
assert dict_path.to_path("g[h=i]").get_element(container) == {"h": "i", "j": "k"}
assert dict_path.to_wild_path("c.*").get_elements(container) == ["f"]
assert sorted(dict_path.to_wild_path("g[h=i].*").get_elements(container)) == ["i", "k"]
assert dict_path.to_wild_path("g[*=k]").get_elements(container) == [{"h": "i", "j": "k"}]
dict_path.to_path("g[h=b].i").set_element(container, "z")
assert dict_path.to_path("g[h=b]").get_element(container) == {"h": "b", "i": "z"}
assert dict_path.to_path("g[h=b].i").get_element(container) == "z"