Passed
Push — master ( 390ea4...159fed )
by Ramon
01:02
created

_is_valid_json_key()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
cc 1
nop 1
1
from typing import Callable, Dict, Optional, Tuple
2
3
from jsons._common_impl import JSON_KEYS
4
from jsons._dump_impl import dump
5
6
7
def default_dict_serializer(
8
        obj: dict,
9
        cls: Optional[type] = None,
10
        *,
11
        strict: bool = False,
12
        strip_nulls: bool = False,
13
        key_transformer: Optional[Callable[[str], str]] = None,
14
        types: Optional[Dict[str, type]] = None,
15
        **kwargs) -> dict:
16
    """
17
    Serialize the given ``obj`` to a dict of serialized objects.
18
    :param obj: the dict that is to be serialized.
19
    :param cls: not used.
20
    :param strict: if ``True`` the serialization will raise upon any the
21
    failure of any attribute. Otherwise it continues with a warning.
22
    :param strict: a bool to determine if the serializer should be strict
23
    (i.e. only dumping stuff that is known to ``cls``).
24
    :param strip_nulls: if ``True`` the resulting dict will not contain null
25
    values.
26
    :param key_transformer: a function that will be applied to all keys in the
27
    resulting dict.
28
    :param types: a ``dict`` with attribute names (keys) and their types
29
    (values).
30
    :param kwargs: any keyword arguments that may be given to the serialization
31
    process.
32
    :return: a dict of which all elements are serialized.
33
    """
34
    result = dict()
35
    types = types or dict()
36
    for key in obj:
37
        obj_ = obj[key]
38
        cls_ = types.get(key, None)
39
40
        # If key is not a valid json type, use the hash as key and store the
41
        # original key in a separate section.
42
        dict_and_key = _store_and_hash(result, key,
43
                                       key_transformer=key_transformer,
44
                                       strip_nulls=strip_nulls, strict=strict,
45
                                       types=types, **kwargs)
46
        if dict_and_key:
47
            result, key = dict_and_key
48
49
        dumped_elem = dump(obj_,
50
                           cls=cls_,
51
                           key_transformer=key_transformer,
52
                           strip_nulls=strip_nulls,
53
                           strict=strict,
54
                           **kwargs)
55
        if not (strip_nulls and dumped_elem is None):
56
            if key_transformer:
57
                key = key_transformer(key)
58
            result[key] = dumped_elem
59
    return result
60
61
62
def _store_and_hash(
63
        obj: dict,
64
        key: object,
65
        **kwargs
66
) -> Optional[Tuple[dict, int]]:
67
    # Store the given key in the given dict under a special section if that
68
    # key is not a valid json key. Return a hash of that key.
69
    result = None
70
    if not _is_valid_json_key(key):
71
        # First try to dump the key, that might be enough already.
72
        dumped_key = dump(key, **kwargs)
73
        result = obj, dumped_key
74
        if not _is_valid_json_key(dumped_key):
75
            # Apparently, this was not enough; the key is still not "jsonable".
76
            key_hash = hash(key)
77
            obj_ = {**obj}
78
            obj_.setdefault('-keys', {})
79
            obj_['-keys'][key_hash] = dumped_key
80
            result = obj_, key_hash
81
    return result
82
83
84
def _is_valid_json_key(key: object) -> bool:
85
    return any(issubclass(type(key), json_key) for json_key in JSON_KEYS)
86