Completed
Push — master ( 919d86...33db6d )
by Ramon
23s queued 10s
created

jsons.serializers.default_iterable._do_dump()   A

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nop 3
1
from collections.abc import Iterable
2
from multiprocessing import Process
3
from typing import Tuple, Optional
4
5
from typish import get_args, get_type
6
7
from jsons._dump_impl import dump
8
from jsons._multitasking import multi_task
9
from jsons.exceptions import SerializationError
10
11
12
def default_iterable_serializer(
13
        obj: Iterable,
14
        cls: type = None,
15
        *,
16
        strict: bool = False,
17
        tasks: int = 1,
18
        task_type: type = Process,
19
        **kwargs) -> list:
20
    """
21
    Serialize the given ``obj`` to a list of serialized objects.
22
    :param obj: the iterable that is to be serialized.
23
    :param cls: the (subscripted) type of the iterable.
24
    :param strict: a bool to determine if the serializer should be strict
25
    (i.e. only dumping stuff that is known to ``cls``).
26
    :param tasks: the allowed number of tasks (threads or processes).
27
    :param task_type: the type that is used for multitasking.
28
    :param kwargs: any keyword arguments that may be given to the serialization
29
    process.
30
    :return: a list of which all elements are serialized.
31
    """
32
    # The meta kwarg store_cls is filtered out, because an iterable should have
33
    # its own -meta attribute.
34
    kwargs_ = {**kwargs, 'strict': strict}
35
    kwargs_.pop('_store_cls', None)
36
    if strict:
37
        cls_ = _determine_cls(obj, cls)
38
        subclasses = _get_subclasses(obj, cls_)
39
    else:
40
        subclasses = _get_subclasses(obj, None)
41
42
    if tasks < 2:
43
        result = [dump(elem, cls=subclasses[i], **kwargs_)
44
                  for i, elem in enumerate(obj)]
45
    else:
46
        zipped_objs = list(zip(obj, subclasses))
47
        result = multi_task(_do_dump, zipped_objs, tasks, task_type, **kwargs_)
48
49
    return result
50
51
52
def _get_subclasses(obj: Iterable, cls: type = None) -> Tuple[type, ...]:
53
    subclasses = (None,) * len(obj)
54
    if cls:
55
        args = get_args(cls)
56
        if len(args) == 1:
57
            # E.g. List[int]
58
            subclasses = args * len(obj)
59
        elif len(args) > 1:
60
            # E.g. Tuple[int, str, str]
61
            subclasses = args
62
    if len(subclasses) != len(obj):
63
        msg = ('Not enough generic types ({}) in {}, expected {} to match '
64
               'the iterable of length {}'
65
               .format(len(subclasses), cls, len(obj), len(obj)))
66
        raise SerializationError(msg)
67
    return subclasses
68
69
70
def _do_dump(obj_cls_tuple: Tuple[object, type], *args, **kwargs):
71
    kwargs_ = {**kwargs}
72
    kwargs_['tasks'] = 1
73
    return dump(*obj_cls_tuple, *args, **kwargs_)
74
75
76
def _determine_cls(obj: Iterable, cls: Optional[type]) -> Optional[type]:
77
    cls_ = cls
78
    if not cls and hasattr(obj, '__getitem__') and len(obj) > 0:
79
        obj_with_only_one_elem = obj.__getitem__(slice(0, 1))
80
        cls_ = get_type(obj_with_only_one_elem)
81
    return cls_
82