Completed
Push — master ( ef07d1...eaea1b )
by Ramon
11s
created

default_namedtuple_deserializer()   B

Complexity

Conditions 6

Size

Total Lines 30
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 30
rs 8.4426
c 0
b 0
f 0
cc 6
nop 3
1
from typing import Union
2
from jsons._compatibility_impl import tuple_with_ellipsis
3
from jsons.exceptions import UnfulfilledArgumentError
4
from jsons._main_impl import load
5
6
7
def default_tuple_deserializer(obj: list,
8
                               cls: type = None,
9
                               **kwargs) -> object:
10
    """
11
    Deserialize a (JSON) list into a tuple by deserializing all items of that
12
    list.
13
    :param obj: the tuple that needs deserializing.
14
    :param cls: the type optionally with a generic (e.g. Tuple[str, int]).
15
    :param kwargs: any keyword arguments.
16
    :return: a deserialized tuple instance.
17
    """
18
    if hasattr(cls, '_fields'):
19
        return default_namedtuple_deserializer(obj, cls, **kwargs)
20
    tuple_types = getattr(cls, '__tuple_params__', getattr(cls, '__args__', []))
21
    if tuple_with_ellipsis(cls):
22
        tuple_types = [tuple_types[0]] * len(obj)
23
    list_ = [load(value, tuple_types[i], **kwargs)
24
             for i, value in enumerate(obj)]
25
    return tuple(list_)
26
27
28
def default_namedtuple_deserializer(
29
        obj: Union[list, dict],
30
        cls: type,
31
        **kwargs) -> object:
32
    """
33
    Deserialize a (JSON) list or dict into a named tuple by deserializing all
34
    items of that list/dict.
35
    :param obj: the tuple that needs deserializing.
36
    :param cls: the NamedTuple.
37
    :param kwargs: any keyword arguments.
38
    :return: a deserialized named tuple (i.e. an instance of a class).
39
    """
40
    is_dict = isinstance(obj, dict)
41
    args = []
42
    for index, field_name in enumerate(cls._fields):
43
        if index < len(obj):
44
            key = field_name if is_dict else index
45
            field = obj[key]
46
        else:
47
            field = cls._field_defaults.get(field_name, None)
48
        if field is None:
49
            msg = ('No value present in {} for argument "{}"'
50
                   .format(obj, field_name))
51
            raise UnfulfilledArgumentError(msg, field_name, obj, cls)
52
        field_types = getattr(cls, '_field_types', None)
53
        cls_ = field_types.get(field_name) if field_types else None
54
        loaded_field = load(field, cls_, **kwargs)
55
        args.append(loaded_field)
56
    inst = cls(*args)
57
    return inst
58