Completed
Push — master ( 8f3758...257d3c )
by Ramon
29s queued 11s
created

jsons._dump_impl._do_dump()   A

Complexity

Conditions 3

Size

Total Lines 9
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 9
rs 9.95
c 0
b 0
f 0
cc 3
nop 5
1
"""
2
PRIVATE MODULE: do not import (from) it directly.
3
4
This module contains functionality for dumping stuff to json.
5
"""
6
import json
7
from typing import Optional, Dict
8
9
from jsons._cache import clear
10
from jsons._common_impl import StateHolder, get_class_name
11
from jsons._extra_impl import announce_class
12
from jsons._lizers_impl import get_serializer
13
from jsons.exceptions import SerializationError, RecursionDetectedError
14
15
16
def dump(obj: object,
17
         cls: Optional[type] = None,
18
         *,
19
         strict: bool = False,
20
         fork_inst: Optional[type] = StateHolder,
21
         **kwargs) -> object:
22
    """
23
    Serialize the given ``obj`` to a JSON equivalent type (e.g. dict, list,
24
    int, ...).
25
26
    The way objects are serialized can be finetuned by setting serializer
27
    functions for the specific type using ``set_serializer``.
28
29
    You can also provide ``cls`` to specify that ``obj`` needs to be serialized
30
    as if it was of type ``cls`` (meaning to only take into account attributes
31
    from ``cls``). The type ``cls`` must have a ``__slots__`` defined. Any type
32
    will do, but in most cases you may want ``cls`` to be a base class of
33
    ``obj``.
34
    :param obj: a Python instance of any sort.
35
    :param cls: if given, ``obj`` will be dumped as if it is of type ``type``.
36
    :param strict: a bool to determine if the serializer should be strict
37
    (i.e. only dumping stuff that is known to ``cls``).
38
    :param fork_inst: if given, it uses this fork of ``JsonSerializable``.
39
    :param kwargs: the keyword args are passed on to the serializer function.
40
    :return: the serialized obj as a JSON type.
41
    """
42
    kwargs = _check_for_recursion(obj, kwargs)
43
    cls_ = cls or obj.__class__
44
    serializer = get_serializer(cls_, fork_inst)
45
46
    # Is this the initial call or a nested?
47
    initial = kwargs.get('_initial', True)
48
49
    kwargs_ = {
50
        'fork_inst': fork_inst,
51
        '_initial': False,
52
        'strict': strict,
53
        **kwargs
54
    }
55
    announce_class(cls_, fork_inst=fork_inst)
56
    kwargs['_objects'].remove(id(obj))
57
    return _do_dump(obj, serializer, cls, initial, kwargs_)
58
59
60
def _do_dump(obj, serializer, cls, initial, kwargs):
61
    try:
62
        result = serializer(obj, cls=cls, **kwargs)
63
        if initial:
64
            clear()
65
        return result
66
    except Exception as err:
67
        clear()
68
        raise SerializationError(str(err))
69
70
71
def dumps(obj: object,
72
          jdkwargs: Optional[Dict[str, object]] = None,
73
          *args,
74
          **kwargs) -> str:
75
    """
76
    Extend ``json.dumps``, allowing any Python instance to be dumped to a
77
    string. Any extra (keyword) arguments are passed on to ``json.dumps``.
78
79
    :param obj: the object that is to be dumped to a string.
80
    :param jdkwargs: extra keyword arguments for ``json.dumps`` (not
81
    ``jsons.dumps``!)
82
    :param args: extra arguments for ``jsons.dumps``.
83
    :param kwargs: Keyword arguments that are passed on through the
84
    serialization process.
85
    passed on to the serializer function.
86
    :return: ``obj`` as a ``str``.
87
    """
88
    jdkwargs = jdkwargs or {}
89
    dumped = dump(obj, *args, **kwargs)
90
    return json.dumps(dumped, **jdkwargs)
91
92
93
def dumpb(obj: object,
94
          encoding: str = 'utf-8',
95
          jdkwargs: Optional[Dict[str, object]] = None,
96
          *args,
97
          **kwargs) -> bytes:
98
    """
99
    Extend ``json.dumps``, allowing any Python instance to be dumped to bytes.
100
    Any extra (keyword) arguments are passed on to ``json.dumps``.
101
102
    :param obj: the object that is to be dumped to bytes.
103
    :param encoding: the encoding that is used to transform to bytes.
104
    :param jdkwargs: extra keyword arguments for ``json.dumps`` (not
105
    ``jsons.dumps``!)
106
    :param args: extra arguments for ``jsons.dumps``.
107
    :param kwargs: Keyword arguments that are passed on through the
108
    serialization process.
109
    passed on to the serializer function.
110
    :return: ``obj`` as ``bytes``.
111
    """
112
    jdkwargs = jdkwargs or {}
113
    dumped_dict = dump(obj, *args, **kwargs)
114
    dumped_str = json.dumps(dumped_dict, **jdkwargs)
115
    return dumped_str.encode(encoding=encoding)
116
117
118
def _check_for_recursion(obj: object, kwargs) -> dict:
119
    kwargs['_objects'] = kwargs.get('_objects', set())
120
    if id(obj) in kwargs['_objects']:
121
        raise RecursionDetectedError('Endless recursion detected')
122
    kwargs['_objects'].add(id(obj))
123
    return kwargs
124