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

jsons.deserializers.default_dict._deserialize()   A

Complexity

Conditions 5

Size

Total Lines 22
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 18
dl 0
loc 22
rs 9.0333
c 0
b 0
f 0
cc 5
nop 5
1
from typing import Callable, Optional, Tuple
2
3
from typish import get_args
4
5
from jsons._load_impl import load
6
from jsons.exceptions import DeserializationError
7
8
9
def default_dict_deserializer(
10
        obj: dict,
11
        cls: type,
12
        *,
13
        key_transformer: Optional[Callable[[str], str]] = None,
14
        **kwargs) -> dict:
15
    """
16
    Deserialize a dict by deserializing all instances of that dict.
17
    :param obj: the dict that needs deserializing.
18
    :param key_transformer: a function that transforms the keys to a different
19
    style (e.g. PascalCase).
20
    :param cls: not used.
21
    :param kwargs: any keyword arguments.
22
    :return: a deserialized dict instance.
23
    """
24
    cls_args = get_args(cls)
25
26
    obj_, keys_were_hashed = _load_hashed_keys(
27
        obj, cls, cls_args, key_transformer=key_transformer, **kwargs)
28
29
    return _deserialize(obj_, cls_args, key_transformer, keys_were_hashed, kwargs)
30
31
32
def _load_hashed_keys(
33
        obj: dict,
34
        cls: type,
35
        cls_args: tuple,
36
        **kwargs) -> Tuple[dict, bool]:
37
    # Load any hashed keys and return a copy of the given obj if any hashed
38
    # keys are unpacked.
39
    result = obj
40
41
    stored_keys = set(obj.get('-keys', set()))
42
    if stored_keys:
43
        # Apparently, there are stored hashed keys, we need to unpack them.
44
        if len(cls_args) != 2:
45
            raise DeserializationError('A detailed type is needed for cls of '
46
                                       'the form Dict[<type>, <type>] to '
47
                                       'deserialize a dict with hashed keys.',
48
                                       obj, cls)
49
        result = {**obj}
50
        key_type = cls_args[0]
51
        for key in stored_keys:
52
            # Get the original (unhashed) key and load it.
53
            original_key = result['-keys'][key]
54
            loaded_key = load(original_key, cls=key_type, **kwargs)
55
56
            # Replace the hashed key by the loaded key entirely.
57
            result[loaded_key] = result[key]
58
            del result['-keys'][key]
59
            del result[key]
60
61
        del result['-keys']
62
    return result, len(stored_keys) > 0
63
64
65
def _deserialize(
66
        obj: dict,
67
        cls_args: tuple,
68
        key_transformer: Callable[[str], str],
69
        keys_were_hashed: bool,
70
        kwargs: dict) -> dict:
71
    key_transformer = key_transformer or (lambda key: key)
72
    key_func = key_transformer
73
    kwargs_ = {**kwargs, 'key_transformer': key_transformer}
74
75
    if len(cls_args) == 2:
76
        cls_k, cls_v = cls_args
77
        kwargs_['cls'] = cls_v
78
        if not keys_were_hashed:
79
            # In case of cls is something like Dict[<key>, <value>], we need to
80
            # ensure that the keys in the result are <key>. If the keys were
81
            # hashed though, they have been loaded already.
82
            kwargs_k = {**kwargs, 'cls': cls_k}
83
            key_func = lambda key: load(key_transformer(key), **kwargs_k)
0 ignored issues
show
introduced by
The variable kwargs_k does not seem to be defined for all execution paths.
Loading history...
84
    return {
85
        key_func(key): load(obj[key], **kwargs_)
86
        for key in obj
87
    }
88