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