Completed
Push — master ( e335fd...15dce3 )
by Ramon
01:01 queued 47s
created

default_namedtuple_deserializer()   C

Complexity

Conditions 9

Size

Total Lines 39
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

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