Passed
Pull Request — master (#17)
by Ramon
50s
created

JsonSerializable.fork()   A

Complexity

Conditions 1

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 12
dl 0
loc 18
rs 9.8
c 0
b 0
f 0
cc 1
nop 2
1
from typing import Optional
2
from jsons._common_impl import get_class_name
3
from jsons._main_impl import (
4
    _StateHolder,
5
    dump,
6
    dumps,
7
    dumpb,
8
    load,
9
    loads,
10
    loadb,
11
    set_serializer,
12
    set_deserializer
13
)
14
15
16
class JsonSerializable(_StateHolder):
17
    """
18
    This class offers an alternative to using the ``jsons.load`` and
19
    ``jsons.dump`` methods. An instance of a class that inherits from
20
    ``JsonSerializable`` has the ``json`` property, which value is equivalent
21
    to calling ``jsons.dump`` on that instance. Furthermore, you can call
22
    ``from_json`` on that class, which is equivalent to calling ``json.load``
23
    with that class as an argument.
24
    """
25
    _fork_counter = 0
26
27
    @classmethod
28
    def fork(cls, name: Optional[str] = None) -> type:
29
        """
30
        Create a 'fork' of ``JsonSerializable``: a new ``type`` with a separate
31
        configuration of serializers and deserializers.
32
        :param name: the ``__name__`` of the new ``type``.
33
        :return: a new ``type`` based on ``JsonSerializable``.
34
        """
35
        cls._fork_counter += 1
36
        class_name = name or '{}_fork{}'.format(get_class_name(cls),
37
                                                cls._fork_counter)
38
        result = type(class_name, (cls,), {})
39
        result._classes_serializers = cls._classes_serializers.copy()
40
        result._classes_deserializers = cls._classes_deserializers.copy()
41
        result._serializers = cls._serializers.copy()
42
        result._deserializers = cls._deserializers.copy()
43
        result._fork_counter = 0
44
        return result
45
46
    @classmethod
47
    def with_dump(cls, fork: Optional[bool] = False, **kwargs) -> type:
48
        """
49
        Return a class (``type``) that is based on JsonSerializable with the
50
        ``dump`` method being automatically provided the given ``kwargs``.
51
52
        **Example:**
53
54
        >>> custom_serializable = JsonSerializable\
55
                .with_dump(key_transformer=KEY_TRANSFORMER_CAMELCASE)
56
        >>> class Person(custom_serializable):
57
        ...     def __init__(self, my_name):
58
        ...         self.my_name = my_name
59
        >>> p = Person('John')
60
        >>> p.json
61
        {'myName': 'John'}
62
63
        :param kwargs: the keyword args that are automatically provided to the
64
        ``dump`` method.
65
        :param fork: determines that a new fork is to be created.
66
        :return: a class with customized behavior.
67
        """
68
        def _wrapper(inst, **kwargs_):
69
            return dump(inst, **{**kwargs_, **kwargs})
70
71
        type_ = cls.fork() if fork else cls
72
        type_.dump = _wrapper
73
        return type_
74
75
    @classmethod
76
    def with_load(cls, fork: Optional[bool] = False, **kwargs) -> type:
77
        """
78
        Return a class (``type``) that is based on JsonSerializable with the
79
        ``load`` method being automatically provided the given ``kwargs``.
80
81
        **Example:**
82
83
        >>> custom_serializable = JsonSerializable\
84
                .with_load(key_transformer=KEY_TRANSFORMER_SNAKECASE)
85
        >>> class Person(custom_serializable):
86
        ...     def __init__(self, my_name):
87
        ...         self.my_name = my_name
88
        >>> p_json = {'myName': 'John'}
89
        >>> p = Person.from_json(p_json)
90
        >>> p.my_name
91
        'John'
92
93
        :param kwargs: the keyword args that are automatically provided to the
94
        ``load`` method.
95
        :param fork: determines that a new fork is to be created.
96
        :return: a class with customized behavior.
97
        """
98
        @classmethod
99
        def _wrapper(cls_, inst, **kwargs_):
100
            return load(inst, cls_, **{**kwargs_, **kwargs})
101
        type_ = cls.fork() if fork else cls
102
        type_.load = _wrapper
103
        return type_
104
105
    @property
106
    def json(self) -> object:
107
        """
108
        See ``jsons.dump``.
109
        :return: this instance in a JSON representation (dict).
110
        """
111
        return self.dump()
112
113
    def __str__(self) -> str:
114
        """
115
        See ``jsons.dumps``.
116
        :return: this instance as a JSON string.
117
        """
118
        return self.dumps()
119
120
    @classmethod
121
    def from_json(cls: type, json_obj: object, **kwargs) -> object:
122
        """
123
        See ``jsons.load``.
124
        :param json_obj: a JSON representation of an instance of the inheriting
125
        class
126
        :param kwargs: the keyword args are passed on to the deserializer
127
        function.
128
        :return: an instance of the inheriting class.
129
        """
130
        return cls.load(json_obj, **kwargs)
131
132
    def dump(self, **kwargs) -> object:
133
        """
134
        See ``jsons.dump``.
135
        :param kwargs: the keyword args are passed on to the serializer
136
        function.
137
        :return: this instance in a JSON representation (dict).
138
        """
139
        return dump(self, fork_inst=self.__class__, **kwargs)
140
141
    @classmethod
142
    def load(cls: type, json_obj: object, **kwargs) -> object:
143
        """
144
        See ``jsons.load``.
145
        :param kwargs: the keyword args are passed on to the serializer
146
        function.
147
        :param json_obj: the object that is loaded into an instance of `cls`.
148
        :return: this instance in a JSON representation (dict).
149
        """
150
        return load(json_obj, cls, fork_inst=cls, **kwargs)
151
152
    def dumps(self, **kwargs) -> str:
153
        """
154
        See ``jsons.dumps``.
155
        :param kwargs: the keyword args are passed on to the serializer
156
        function.
157
        :return: this instance as a JSON string.
158
        """
159
        return dumps(self, fork_inst=self.__class__, **kwargs)
160
161
    @classmethod
162
    def loads(cls: type, json_obj: str, **kwargs) -> object:
163
        """
164
        See ``jsons.loads``.
165
        :param kwargs: the keyword args are passed on to the serializer
166
        function.
167
        :param json_obj: the object that is loaded into an instance of `cls`.
168
        :return: this instance in a JSON representation (dict).
169
        """
170
        return loads(json_obj, cls, fork_inst=cls, **kwargs)
171
172
    def dumpb(self, **kwargs) -> bytes:
173
        """
174
        See ``jsons.dumpb``.
175
        :param kwargs: the keyword args are passed on to the serializer
176
        function.
177
        :return: this instance as a JSON string.
178
        """
179
        return dumpb(self, fork_inst=self.__class__, **kwargs)
180
181
    @classmethod
182
    def loadb(cls: type, json_obj: bytes, **kwargs) -> object:
183
        """
184
        See ``jsons.loadb``.
185
        :param kwargs: the keyword args are passed on to the serializer
186
        function.
187
        :param json_obj: the object that is loaded into an instance of `cls`.
188
        :return: this instance in a JSON representation (dict).
189
        """
190
        return loadb(json_obj, cls, fork_inst=cls, **kwargs)
191
192
    @classmethod
193
    def set_serializer(cls: type,
194
                       func: callable,
195
                       cls_: type,
196
                       high_prio: Optional[bool] = True,
197
                       fork: Optional[bool] = False) -> type:
198
        """
199
        See ``jsons.set_serializer``.
200
        :param func: the serializer function.
201
        :param cls_: the type this serializer can handle.
202
        :param high_prio: determines the order in which is looked for the
203
        callable.
204
        :param fork: determines that a new fork is to be created.
205
        :return: the type on which this method is invoked or its fork.
206
        """
207
        type_ = cls.fork() if fork else cls
208
        set_serializer(func, cls_, high_prio, type_)
209
        return type_
210
211
    @classmethod
212
    def set_deserializer(cls: type,
213
                         func: callable,
214
                         cls_: type,
215
                         high_prio: Optional[bool] = True,
216
                         fork: Optional[bool] = False) -> type:
217
        """
218
        See ``jsons.set_deserializer``.
219
        :param func: the deserializer function.
220
        :param cls_: the type this serializer can handle.
221
        :param high_prio: determines the order in which is looked for the
222
        callable.
223
        :param fork: determines that a new fork is to be created.
224
        :return: the type on which this method is invoked or its fork.
225
        """
226
        type_ = cls.fork() if fork else cls
227
        set_deserializer(func, cls_, high_prio, type_)
228
        return type_
229