sprig.dictutils module¶
A collection of convenient methods when working with dicts
-
sprig.dictutils.
deflate
(inflated: Dict[str, Any], sep: str = '/') → Dict[str, Any]¶ Walk the tree provided as a nested dict and for every leaf node add its path and value as a key: value mapping in the returned dictionary.
Trees of depth one produce themselves
>>> deflate({'a': 13}) {'a': 13}
Deep trees produce long paths
>>> deflate({'a': {'i': {'x': 13}}}) {'a/i/x': 13}
Children can be internal nodes and leaf nodes both
>>> (deflate({'a': {'i': {'x': 13}, 'j': 17}}) ... == {'a/i/x': 13, 'a/j': 17}) True
Every leaf node must have a value
>>> deflate({'a': {}}) Traceback (most recent call last): ... ValueError: Nodes must have at least one child or a value
Keys must not contain sep
>>> deflate({'a': {'i': 13}, 'a/i': 17}) Traceback (most recent call last): ... ValueError: Key must not contain path separator
Dicts inside non-dict objects are ignored
>>> (deflate({'a': {'i': ({'x': 13},)}}) ... == {'a/i': ({'x': 13},)}) True
Leaves input unchanged
>>> i = {'a': {'i': {'x': 13}, 'j': 17}} >>> d = deflate(i) >>> i == {'a': {'i': {'x': 13}, 'j': 17}} True
Input and output are untangled
>>> i['bar'] = 23; 'bar' in d False >>> d['foo'] = 19; 'foo' in i False
Keys must be strings
>>> deflate({b'1': 13}) Traceback (most recent call last): ... TypeError: Key must be a string
Lists are left intact by default
>>> deflate({'a': [13, {'i': 17}]}) {'a': [13, {'i': 17}]}
-
sprig.dictutils.
group_by
(iterable: Iterable[T], keyfunc: Callable[[T], V]) → Dict[V, List[T]]¶ Group items by key
Similar to itertools.groupby except * consumes input eagerly, * order of input does not matter, * returned type is different.
-
sprig.dictutils.
inflate
(deflated: Dict[str, Any], sep: str = '/') → Dict[str, Any]¶ Interpret the keys as paths in a tree to its leaf nodes, the values as the corresponding value and return a nested dict representation of that tree.
Keys without sep are not inflated
>>> inflate({'aix': 13}) {'aix': 13}
Keys with sep produce nested dict
>>> inflate({'a/i/x': 13}) {'a': {'i': {'x': 13}}}
Children can be internal nodes and leaf nodes both
>>> (inflate({'a/i/x': 13, 'a/j': 17}) ... == {'a': {'i': {'x': 13}, 'j': 17}}) True
Only leaf nodes can have values
>>> from collections import OrderedDict >>> inflate(OrderedDict([('a/i', 13), ('a', 17)])) Traceback (most recent call last): ... RuntimeError: Internal node must not be assigned a value.
>>> inflate(OrderedDict([('a', 13), ('a/i', 17)])) Traceback (most recent call last): ... RuntimeError: Leaf node must not be assigned children.
Every leaf node must have a value
>>> inflate({'a': {}}) Traceback (most recent call last): ... TypeError: Value must not be another dict
Input must be flat
>>> inflate({'a': {'i': 13}}) Traceback (most recent call last): ... TypeError: Value must not be another dict
Dicts inside non-dict objects are ignored
>>> (inflate({'a/i': ({'x': 13},)}) ... == {'a': {'i': ({'x': 13},)}}) True
Leaves input unchanged
>>> d = {'a/i/x': 13, 'a/j': 17} >>> i = inflate(d) >>> d == {'a/i/x': 13, 'a/j': 17} True
Input and output are untangled
>>> d['foo'] = 19; 'foo' in i False >>> i['bar'] = 23; 'bar' in d False
Keys must be unicode
>>> inflate({b'1': 13}) Traceback (most recent call last): ... TypeError: Key must be a string
-
sprig.dictutils.
invert
(mapping: Dict[T, V]) → Dict[V, T]¶ Invert dictionary
Trivial function but good for two reasons: * it gives the operation a name, and * it catches an edge case that is easily forgotten.