dictutils¶
Utilities for manipulating dicts.
add(d, key, value)
¶
Append key-value pair to dict d
.
If key
already exists in d
, its value is converted to a list
and value
is appended to it. value
may also be a list. Values
are not duplicated.
Source code in tripper/datadoc/dictutils.py
def add(d: dict, key: str, value: "Any") -> None:
"""Append key-value pair to dict `d`.
If `key` already exists in `d`, its value is converted to a list
and `value` is appended to it. `value` may also be a list. Values
are not duplicated.
"""
if key not in d:
d[key] = value
else:
klst = d[key] if isinstance(d[key], list) else [d[key]]
if isinstance(value, dict):
v = klst if value in klst else klst + [value]
else:
vlst = value if isinstance(value, list) else [value]
try:
v = list(set(klst).union(vlst))
except TypeError: # klst contains unhashable dicts
v = klst + [x for x in vlst if x not in klst]
d[key] = (
v[0]
if len(v) == 1
else sorted(
# Sort dicts at end, by representing them with a huge
# unicode character
v,
key=lambda x: "\uffff" if isinstance(x, dict) else str(x),
)
)
addnested(d, key, value)
¶
Like add(), but allows key
to be a dot-separated list of sub-keys.
Returns the updated d
.
Each sub-key will be added to d
as a corresponding sub-dict.
Examples:
>>> d = {}
>>> addnested(d, "a.b.c", "val") == {'a': {'b': {'c': 'val'}}}
True
Source code in tripper/datadoc/dictutils.py
def addnested(
d: "Union[dict, list]", key: str, value: "Any"
) -> "Union[dict, list]":
"""Like add(), but allows `key` to be a dot-separated list of sub-keys.
Returns the updated `d`.
Each sub-key will be added to `d` as a corresponding sub-dict.
Example:
>>> d = {}
>>> addnested(d, "a.b.c", "val") == {'a': {'b': {'c': 'val'}}}
True
"""
if "." in key:
first, rest = key.split(".", 1)
if isinstance(d, list):
for ele in d:
if isinstance(ele, dict):
addnested(ele, key, value)
break
else:
d.append(addnested({}, key, value))
elif first in d and isinstance(d[first], (dict, list)):
addnested(d[first], rest, value)
else:
addnested(d, first, addnested(AttrDict(), rest, value))
elif isinstance(d, list):
for ele in d:
if isinstance(ele, dict):
add(ele, key, value)
break
else:
d.append({key: value})
else:
add(d, key, value)
return d
get(d, key, default=None, aslist=True)
¶
Like d.get(key, default)
but returns the value as a list if
aslist
is True and value is not already a list.
An empty list is returned in the special case that key
is not in
d
and default
is None.
Source code in tripper/datadoc/dictutils.py
def get(
d: dict, key: str, default: "Any" = None, aslist: bool = True
) -> "Any":
"""Like `d.get(key, default)` but returns the value as a list if
`aslist` is True and value is not already a list.
An empty list is returned in the special case that `key` is not in
`d` and `default` is None.
"""
value = d.get(key, default)
if aslist:
return (
value
if isinstance(value, list)
else [] if value is None else [value]
)
return value
merge(a, b)
¶
Return the merged result of a
and b
, where a
and b
can be
None, string or a sequence of strings.
The result will be None if both a
and b
are None and a string if one
is None and the other is a string or both are the same string. Otherwise,
the result will be a list with the unique strings from a
and b
.
Source code in tripper/datadoc/dictutils.py
def merge(a: "MergeType", b: "MergeType") -> "MergeType":
"""Return the merged result of `a` and `b`, where `a` and `b` can be
None, string or a sequence of strings.
The result will be None if both `a` and `b` are None and a string if one
is None and the other is a string or both are the same string. Otherwise,
the result will be a list with the unique strings from `a` and `b`.
"""
# pylint: disable=too-many-return-statements
if a is None and b is None:
return None
if a is None:
return b
if b is None:
return a
if isinstance(a, str) and isinstance(b, str):
return a if b == a else [a, b]
if isinstance(a, str) and isinstance(b, Sequence):
return [a] + [x for x in b if x != a]
if isinstance(a, Sequence) and isinstance(b, str):
return a if b in a else list(a) + [b]
if isinstance(a, Sequence) and isinstance(b, Sequence):
return list(a) + [x for x in b if x not in a]
raise TypeError("input must be None, string or a sequence")