Passed
Pull Request — master (#99)
by
unknown
59s
created

default_namedtuple_deserializer()   C

Complexity

Conditions 10

Size

Total Lines 43
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 43
rs 5.9999
c 0
b 0
f 0
cc 10
nop 5

How to fix   Complexity   

Complexity

Complex classes like jsons.deserializers.default_tuple.default_namedtuple_deserializer() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
from typing import Callable, Optional, 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
                               *,
12
                               key_transformer: Optional[Callable[[str], str]] = None,
13
                               **kwargs) -> object:
14
    """
15
    Deserialize a (JSON) list into a tuple by deserializing all items of that
16
    list.
17
    :param obj: the tuple that needs deserializing.
18
    :param cls: the type optionally with a generic (e.g. Tuple[str, int]).
19
    :param kwargs: any keyword arguments.
20
    :return: a deserialized tuple instance.
21
    """
22
    if hasattr(cls, '_fields'):
23
        return default_namedtuple_deserializer(obj, cls, key_transformer=key_transformer, **kwargs)
24
    cls_args = get_args(cls)
25
    if cls_args:
26
        tuple_types = getattr(cls, '__tuple_params__', cls_args)
27
        if tuple_with_ellipsis(cls):
28
            tuple_types = [tuple_types[0]] * len(obj)
29
        list_ = [load(value, tuple_types[i], **kwargs)
30
                 for i, value in enumerate(obj)]
31
    else:
32
        list_ = [load(value, **kwargs) for i, value in enumerate(obj)]
33
    return tuple(list_)
34
35
36
def default_namedtuple_deserializer(
37
        obj: Union[list, dict],
38
        cls: type,
39
        *,
40
        key_transformer: Optional[Callable[[str], str]] = None,
41
        **kwargs) -> object:
42
    """
43
    Deserialize a (JSON) list or dict into a named tuple by deserializing all
44
    items of that list/dict.
45
    :param obj: the tuple that needs deserializing.
46
    :param cls: the NamedTuple.
47
    :param kwargs: any keyword arguments.
48
    :return: a deserialized named tuple (i.e. an instance of a class).
49
    """
50
    is_dict = isinstance(obj, dict)
51
    key_tfr = key_transformer or (lambda key: key)
52
53
    if is_dict:
54
        tfm_obj = {key_tfr(k): v for k, v in obj.items()}
55
56
    args = []
57
    for index, field_name in enumerate(cls._fields):
58
        if index < len(obj):
59
            if is_dict:
60
                field = tfm_obj[field_name]
0 ignored issues
show
introduced by
The variable tfm_obj does not seem to be defined in case is_dict on line 53 is False. Are you sure this can never be the case?
Loading history...
61
            else:
62
                field = obj[index]
63
        else:
64
            field = cls._field_defaults.get(field_name, None)
65
66
        if field is None:
67
            hint = getattr(cls, '_field_types', {}).get(field_name)
68
            if NoneType not in (get_union_params(hint) or []):
69
                # The value 'None' is not permitted here.
70
                msg = ('No value present in {} for argument "{}"'
71
                       .format(obj, field_name))
72
                raise UnfulfilledArgumentError(msg, field_name, obj, cls)
73
        field_types = getattr(cls, '_field_types', None)
74
        cls_ = field_types.get(field_name) if field_types else None
75
        loaded_field = load(field, cls_, key_transformer=key_transformer, **kwargs)
76
        args.append(loaded_field)
77
    inst = cls(*args)
78
    return inst
79