Completed
Push — master ( 4d0ec5...ba9245 )
by Ramon
12s
created

jsons._dump_impl._check_for_recursion()   A

Complexity

Conditions 2

Size

Total Lines 6
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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