# # Copyright (c) 2022 Airbyte, Inc., all rights reserved. # from functools import reduce from typing import Any, Iterable, List, Mapping, Optional, Tuple def all_key_pairs_dot_notation(dict_obj: Mapping) -> Mapping[str, Any]: """ Recursively iterate through a dictionary and return a dictionary of all key-value pairs in dot notation. keys are prefixed with the list of keys passed in as prefix. """ def _all_key_pairs_dot_notation(_dict_obj: Mapping, prefix: List[str] = []) -> Iterable[Tuple[str, Any]]: for key, value in _dict_obj.items(): if isinstance(value, dict): prefix.append(str(key)) yield from _all_key_pairs_dot_notation(value, prefix) prefix.pop() else: prefix.append(str(key)) yield ".".join(prefix), value prefix.pop() return {k: v for k, v in _all_key_pairs_dot_notation(dict_obj)} def get_value_by_dot_notation(dict_obj: Mapping, key: str, default: Optional[Any] = ...) -> Any: """ Return the value of a key in dot notation in a arbitrarily nested Mapping. dict_obj: Mapping key: str default: Any raises: KeyError if default is not provided and the key is not found ex.: dict_obj = {"nested": {"key": "value"}} get_value_by_dot_notation(dict_obj, "nested.key") == "value" -> True """ return reduce(lambda d, key_name: d[key_name] if default is ... else d.get(key_name, default), key.split("."), dict_obj)