1from typing import Any, Dict, List 2from collections.abc import Mapping 3 4from banal.lists import is_sequence, ensure_list 5 6 7def is_mapping(obj: Any) -> bool: 8 return isinstance(obj, Mapping) 9 10 11def ensure_dict(obj: Any) -> Dict: 12 if is_mapping(obj) or hasattr(obj, 'items'): 13 return dict(obj.items()) 14 return {} 15 16 17def clean_dict(data: Mapping) -> Mapping: 18 """Remove None-valued keys from a dictionary, recursively.""" 19 if is_mapping(data): 20 out = {} 21 for k, v in data.items(): 22 if v is not None: 23 out[k] = clean_dict(v) 24 return out 25 elif is_sequence(data): 26 return [clean_dict(d) for d in data if d is not None] # type: ignore 27 return data 28 29 30def keys_values(data: Dict, *keys: str) -> List: 31 """Get an entry as a list from a dict. Provide a fallback key.""" 32 values = [] 33 if is_mapping(data): 34 for key in keys: 35 if key in data: 36 values.extend(ensure_list(data[key])) 37 return values 38