typedpy 2.2.2__tar.gz → 2.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/__pycache__/serialization.cpython-39.pyc +0 -0
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/__pycache__/serialization_wrappers.cpython-39.pyc +0 -0
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/__pycache__/structures.cpython-39.pyc +0 -0
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/serialization.py +129 -52
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/serialization_wrappers.py +23 -3
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/structures.py +55 -50
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/{typedpy-2.2.2-py3.9.egg-info → typedpy-2.2.4-py3.9.egg-info}/PKG-INFO +2 -2
- /home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/{typedpy-2.2.2-py3.9.egg-info → typedpy-2.2.4-py3.9.egg-info}/SOURCES.txt +0 -0
- /home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/{typedpy-2.2.2-py3.9.egg-info → typedpy-2.2.4-py3.9.egg-info}/dependency_links.txt +0 -0
- /home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/{typedpy-2.2.2-py3.9.egg-info → typedpy-2.2.4-py3.9.egg-info}/top_level.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -10,7 +10,7 @@ from typedpy.structures import (
|
|
|
10
10
|
Structure,
|
|
11
11
|
_get_all_fields_by_name,
|
|
12
12
|
ADDITIONAL_PROPERTIES,
|
|
13
|
-
REQUIRED_FIELDS,
|
|
13
|
+
REQUIRED_FIELDS, IGNORE_NONE_VALUES,
|
|
14
14
|
)
|
|
15
15
|
from typedpy.fields import (
|
|
16
16
|
Field,
|
|
@@ -39,7 +39,8 @@ from typedpy.fields import (
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def deserialize_list_like(
|
|
42
|
-
field, content_type, value, name, *, keep_undefined=True, mapper=None
|
|
42
|
+
field, content_type, value, name, *, keep_undefined=True, mapper=None,
|
|
43
|
+
camel_case_convert=False
|
|
43
44
|
):
|
|
44
45
|
if not isinstance(value, (list, tuple, set)):
|
|
45
46
|
raise ValueError("{}: must be list, set, or tuple; got {}".format(name, value))
|
|
@@ -47,11 +48,14 @@ def deserialize_list_like(
|
|
|
47
48
|
values = []
|
|
48
49
|
items = field.items
|
|
49
50
|
if isinstance(items, Field):
|
|
51
|
+
ignore_none = getattr(items, IGNORE_NONE_VALUES, False)
|
|
50
52
|
for i, v in enumerate(value):
|
|
51
53
|
item_name = "{}_{}".format(name, i)
|
|
52
54
|
try:
|
|
53
55
|
list_item = deserialize_single_field(
|
|
54
|
-
items, v, item_name, keep_undefined=keep_undefined, mapper=mapper
|
|
56
|
+
items, v, item_name, keep_undefined=keep_undefined, mapper=mapper,
|
|
57
|
+
camel_case_convert=camel_case_convert,
|
|
58
|
+
ignore_none=ignore_none
|
|
55
59
|
)
|
|
56
60
|
except (ValueError, TypeError) as e:
|
|
57
61
|
prefix = (
|
|
@@ -62,8 +66,11 @@ def deserialize_list_like(
|
|
|
62
66
|
elif isinstance(items, (list, tuple)):
|
|
63
67
|
for i, item in enumerate(items):
|
|
64
68
|
try:
|
|
69
|
+
ignore_none = getattr(item, IGNORE_NONE_VALUES, False)
|
|
65
70
|
res = deserialize_single_field(
|
|
66
|
-
item, value[i], name, keep_undefined=keep_undefined, mapper=mapper
|
|
71
|
+
item, value[i], name, keep_undefined=keep_undefined, mapper=mapper,
|
|
72
|
+
camel_case_convert=camel_case_convert,
|
|
73
|
+
ignore_none=ignore_none
|
|
67
74
|
)
|
|
68
75
|
except (ValueError, TypeError) as e:
|
|
69
76
|
raise ValueError("{}_{}: {}".format(name, i, str(e))) from e
|
|
@@ -74,13 +81,14 @@ def deserialize_list_like(
|
|
|
74
81
|
return content_type(values)
|
|
75
82
|
|
|
76
83
|
|
|
77
|
-
def deserialize_array(array_field, value, name, *, keep_undefined=True, mapper):
|
|
84
|
+
def deserialize_array(array_field, value, name, *, keep_undefined=True, mapper,camel_case_convert=False):
|
|
78
85
|
return deserialize_list_like(
|
|
79
|
-
array_field, list, value, name, keep_undefined=keep_undefined, mapper=mapper
|
|
86
|
+
array_field, list, value, name, keep_undefined=keep_undefined, mapper=mapper,
|
|
87
|
+
camel_case_convert=camel_case_convert
|
|
80
88
|
)
|
|
81
89
|
|
|
82
90
|
|
|
83
|
-
def deserialize_deque(array_field, value, name, *, keep_undefined=True, mapper):
|
|
91
|
+
def deserialize_deque(array_field, value, name, *, keep_undefined=True, mapper, camel_case_convert=False):
|
|
84
92
|
return deserialize_list_like(
|
|
85
93
|
array_field,
|
|
86
94
|
collections.deque,
|
|
@@ -88,23 +96,27 @@ def deserialize_deque(array_field, value, name, *, keep_undefined=True, mapper):
|
|
|
88
96
|
name,
|
|
89
97
|
keep_undefined=keep_undefined,
|
|
90
98
|
mapper=mapper,
|
|
99
|
+
camel_case_convert=camel_case_convert
|
|
91
100
|
)
|
|
92
101
|
|
|
93
102
|
|
|
94
|
-
def deserialize_tuple(tuple_field, value, name, *, keep_undefined=True, mapper):
|
|
103
|
+
def deserialize_tuple(tuple_field, value, name, *, keep_undefined=True, mapper, camel_case_convert=False):
|
|
95
104
|
return deserialize_list_like(
|
|
96
|
-
tuple_field, tuple, value, name, keep_undefined=keep_undefined, mapper=mapper
|
|
105
|
+
tuple_field, tuple, value, name, keep_undefined=keep_undefined, mapper=mapper,
|
|
106
|
+
camel_case_convert=camel_case_convert
|
|
97
107
|
)
|
|
98
108
|
|
|
99
109
|
|
|
100
|
-
def deserialize_set(set_field, value, name, *, keep_undefined=True, mapper):
|
|
110
|
+
def deserialize_set(set_field, value, name, *, keep_undefined=True, mapper, camel_case_convert=False):
|
|
101
111
|
return deserialize_list_like(
|
|
102
|
-
set_field, set, value, name, keep_undefined=keep_undefined, mapper=mapper
|
|
112
|
+
set_field, set, value, name, keep_undefined=keep_undefined, mapper=mapper,
|
|
113
|
+
camel_case_convert=camel_case_convert
|
|
103
114
|
)
|
|
104
115
|
|
|
105
116
|
|
|
106
117
|
def deserialize_multifield_wrapper(
|
|
107
|
-
field, source_val, name, *, keep_undefined=True, mapper=None
|
|
118
|
+
field, source_val, name, *, keep_undefined=True, mapper=None,
|
|
119
|
+
camel_case_convert=False
|
|
108
120
|
):
|
|
109
121
|
"""
|
|
110
122
|
Only primitive values are supported, otherwise deserialization is ambiguous,
|
|
@@ -114,12 +126,16 @@ def deserialize_multifield_wrapper(
|
|
|
114
126
|
found_previous_match = False
|
|
115
127
|
for field_option in field.get_fields():
|
|
116
128
|
try:
|
|
129
|
+
ignore_none = getattr(field_option, IGNORE_NONE_VALUES, False)
|
|
130
|
+
|
|
117
131
|
deserialized = deserialize_single_field(
|
|
118
132
|
field_option,
|
|
119
133
|
source_val,
|
|
120
134
|
name,
|
|
121
135
|
keep_undefined=keep_undefined,
|
|
122
136
|
mapper=mapper,
|
|
137
|
+
camel_case_convert=camel_case_convert,
|
|
138
|
+
ignore_none=ignore_none
|
|
123
139
|
)
|
|
124
140
|
if isinstance(field, AnyOf):
|
|
125
141
|
return deserialized
|
|
@@ -146,7 +162,7 @@ def deserialize_multifield_wrapper(
|
|
|
146
162
|
return deserialized
|
|
147
163
|
|
|
148
164
|
|
|
149
|
-
def deserialize_map(map_field, source_val, name):
|
|
165
|
+
def deserialize_map(map_field, source_val, name, camel_case_convert=False):
|
|
150
166
|
if not isinstance(source_val, dict):
|
|
151
167
|
raise TypeError(
|
|
152
168
|
"{}: expected a dict. Got {}".format(name, wrap_val(source_val))
|
|
@@ -157,15 +173,26 @@ def deserialize_map(map_field, source_val, name):
|
|
|
157
173
|
key_field, value_field = None, None
|
|
158
174
|
res = {}
|
|
159
175
|
for key, val in source_val.items():
|
|
160
|
-
|
|
161
|
-
|
|
176
|
+
ignore_none = getattr(value_field, IGNORE_NONE_VALUES, False)
|
|
177
|
+
|
|
178
|
+
res[deserialize_single_field(key_field, key, name,
|
|
179
|
+
camel_case_convert=camel_case_convert)] = deserialize_single_field(
|
|
180
|
+
value_field, val, name,
|
|
181
|
+
camel_case_convert=camel_case_convert,
|
|
182
|
+
ignore_none=ignore_none
|
|
162
183
|
)
|
|
163
184
|
return res
|
|
164
185
|
|
|
165
186
|
|
|
166
187
|
def deserialize_single_field(
|
|
167
|
-
field, source_val, name, *,
|
|
188
|
+
field, source_val, name, *,
|
|
189
|
+
mapper=None,
|
|
190
|
+
keep_undefined=True,
|
|
191
|
+
camel_case_convert=False,
|
|
192
|
+
ignore_none=False,
|
|
168
193
|
):
|
|
194
|
+
if source_val is None and ignore_none:
|
|
195
|
+
return source_val
|
|
169
196
|
if isinstance(field, (Number, String, Enum, Boolean)):
|
|
170
197
|
field._validate(source_val)
|
|
171
198
|
value = source_val
|
|
@@ -177,23 +204,28 @@ def deserialize_single_field(
|
|
|
177
204
|
value = source_val
|
|
178
205
|
elif isinstance(field, Array):
|
|
179
206
|
value = deserialize_array(
|
|
180
|
-
field, source_val, name, keep_undefined=keep_undefined, mapper=mapper
|
|
207
|
+
field, source_val, name, keep_undefined=keep_undefined, mapper=mapper,
|
|
208
|
+
camel_case_convert=camel_case_convert
|
|
181
209
|
)
|
|
182
210
|
elif isinstance(field, Deque):
|
|
183
211
|
value = deserialize_deque(
|
|
184
|
-
field, source_val, name, keep_undefined=keep_undefined, mapper=mapper
|
|
212
|
+
field, source_val, name, keep_undefined=keep_undefined, mapper=mapper,
|
|
213
|
+
camel_case_convert=camel_case_convert
|
|
185
214
|
)
|
|
186
215
|
elif isinstance(field, Tuple):
|
|
187
216
|
value = deserialize_tuple(
|
|
188
|
-
field, source_val, name, keep_undefined=keep_undefined, mapper=mapper
|
|
217
|
+
field, source_val, name, keep_undefined=keep_undefined, mapper=mapper,
|
|
218
|
+
camel_case_convert=camel_case_convert
|
|
189
219
|
)
|
|
190
220
|
elif isinstance(field, Set):
|
|
191
221
|
value = deserialize_set(
|
|
192
|
-
field, source_val, name, keep_undefined=keep_undefined, mapper=mapper
|
|
222
|
+
field, source_val, name, keep_undefined=keep_undefined, mapper=mapper,
|
|
223
|
+
camel_case_convert=camel_case_convert
|
|
193
224
|
)
|
|
194
225
|
elif isinstance(field, MultiFieldWrapper):
|
|
195
226
|
value = deserialize_multifield_wrapper(
|
|
196
|
-
field, source_val, name, keep_undefined=keep_undefined, mapper=mapper
|
|
227
|
+
field, source_val, name, keep_undefined=keep_undefined, mapper=mapper,
|
|
228
|
+
camel_case_convert=camel_case_convert
|
|
197
229
|
)
|
|
198
230
|
elif isinstance(field, ClassReference):
|
|
199
231
|
value = deserialize_structure_internal(
|
|
@@ -202,6 +234,7 @@ def deserialize_single_field(
|
|
|
202
234
|
name,
|
|
203
235
|
keep_undefined=keep_undefined,
|
|
204
236
|
mapper=mapper,
|
|
237
|
+
camel_case_convert=camel_case_convert
|
|
205
238
|
)
|
|
206
239
|
elif isinstance(field, StructureReference):
|
|
207
240
|
value = deserialize_structure_reference(
|
|
@@ -209,9 +242,10 @@ def deserialize_single_field(
|
|
|
209
242
|
source_val,
|
|
210
243
|
keep_undefined=keep_undefined,
|
|
211
244
|
mapper=mapper,
|
|
245
|
+
camel_case_convert=camel_case_convert
|
|
212
246
|
)
|
|
213
247
|
elif isinstance(field, Map):
|
|
214
|
-
value = deserialize_map(field, source_val, name)
|
|
248
|
+
value = deserialize_map(field, source_val, name, camel_case_convert=camel_case_convert)
|
|
215
249
|
elif isinstance(field, SerializableField):
|
|
216
250
|
value = field.deserialize(source_val)
|
|
217
251
|
elif isinstance(field, Anything) or field is None:
|
|
@@ -231,7 +265,7 @@ def deserialize_single_field(
|
|
|
231
265
|
return value
|
|
232
266
|
|
|
233
267
|
|
|
234
|
-
def deserialize_structure_reference(cls, the_dict: dict, *, keep_undefined, mapper):
|
|
268
|
+
def deserialize_structure_reference(cls, the_dict: dict, *, keep_undefined, mapper, camel_case_convert=False):
|
|
235
269
|
field_by_name = {k: v for k, v in cls.__dict__.items() if isinstance(v, Field)}
|
|
236
270
|
kwargs = dict(
|
|
237
271
|
[
|
|
@@ -241,30 +275,36 @@ def deserialize_structure_reference(cls, the_dict: dict, *, keep_undefined, mapp
|
|
|
241
275
|
]
|
|
242
276
|
)
|
|
243
277
|
|
|
244
|
-
kwargs.update(construct_fields_map(field_by_name, keep_undefined, mapper, the_dict
|
|
278
|
+
kwargs.update(construct_fields_map(field_by_name, keep_undefined, mapper, the_dict,
|
|
279
|
+
camel_case_convert=camel_case_convert))
|
|
245
280
|
cls(**kwargs)
|
|
246
281
|
return kwargs
|
|
247
282
|
|
|
248
283
|
|
|
249
|
-
def construct_fields_map(field_by_name, keep_undefined, mapper,
|
|
284
|
+
def construct_fields_map(field_by_name, keep_undefined, mapper, input_dict,
|
|
285
|
+
camel_case_convert=False,
|
|
286
|
+
ignore_none=False):
|
|
250
287
|
result = {}
|
|
251
288
|
for key, field in field_by_name.items():
|
|
289
|
+
converted_key = _convert_to_camel_case_if_required(key, camel_case_convert=camel_case_convert)
|
|
252
290
|
process = False
|
|
253
291
|
processed_input = None
|
|
254
|
-
if
|
|
255
|
-
processed_input =
|
|
292
|
+
if converted_key in input_dict and key not in mapper:
|
|
293
|
+
processed_input = input_dict[converted_key]
|
|
256
294
|
process = True
|
|
257
295
|
elif key in mapper:
|
|
258
|
-
processed_input = get_processed_input(key, mapper,
|
|
296
|
+
processed_input = get_processed_input(key, mapper, input_dict)
|
|
259
297
|
process = True
|
|
260
298
|
if process:
|
|
261
|
-
sub_mapper = mapper.get(f"{
|
|
299
|
+
sub_mapper = mapper.get(f"{converted_key}._mapper", {})
|
|
262
300
|
result[key] = deserialize_single_field(
|
|
263
301
|
field,
|
|
264
302
|
processed_input,
|
|
265
303
|
key,
|
|
266
304
|
mapper=sub_mapper,
|
|
267
305
|
keep_undefined=keep_undefined,
|
|
306
|
+
camel_case_convert=camel_case_convert,
|
|
307
|
+
ignore_none=ignore_none
|
|
268
308
|
)
|
|
269
309
|
return result
|
|
270
310
|
|
|
@@ -288,7 +328,10 @@ class FunctionCall(Structure):
|
|
|
288
328
|
|
|
289
329
|
|
|
290
330
|
def deserialize_structure_internal(
|
|
291
|
-
cls, the_dict, name=None, *,
|
|
331
|
+
cls, the_dict, name=None, *,
|
|
332
|
+
mapper=None,
|
|
333
|
+
keep_undefined=True,
|
|
334
|
+
camel_case_convert=False
|
|
292
335
|
):
|
|
293
336
|
"""
|
|
294
337
|
Deserialize a dict to a Structure instance, Jackson style.
|
|
@@ -314,6 +357,7 @@ def deserialize_structure_internal(
|
|
|
314
357
|
"""
|
|
315
358
|
if mapper is None:
|
|
316
359
|
mapper = {}
|
|
360
|
+
ignore_none = getattr(cls, IGNORE_NONE_VALUES, False)
|
|
317
361
|
if not isinstance(mapper, (collections.abc.Mapping,)):
|
|
318
362
|
raise TypeError("Mapper must be a mapping")
|
|
319
363
|
field_by_name = _get_all_fields_by_name(cls)
|
|
@@ -326,7 +370,7 @@ def deserialize_structure_internal(
|
|
|
326
370
|
if len(fields) == 1 and required == fields and additional_props is False:
|
|
327
371
|
field_name = fields[0]
|
|
328
372
|
return cls(
|
|
329
|
-
deserialize_single_field(getattr(cls, field_name), the_dict, field_name)
|
|
373
|
+
deserialize_single_field(getattr(cls, field_name), the_dict, field_name, ignore_none=ignore_none)
|
|
330
374
|
)
|
|
331
375
|
raise TypeError(
|
|
332
376
|
"{}: Expected a dictionary; Got {}".format(name, wrap_val(the_dict))
|
|
@@ -339,12 +383,17 @@ def deserialize_structure_internal(
|
|
|
339
383
|
if k not in field_by_name and keep_undefined
|
|
340
384
|
]
|
|
341
385
|
)
|
|
342
|
-
kwargs.update(construct_fields_map(field_by_name, keep_undefined, mapper, the_dict
|
|
386
|
+
kwargs.update(construct_fields_map(field_by_name, keep_undefined, mapper, the_dict,
|
|
387
|
+
camel_case_convert=camel_case_convert,
|
|
388
|
+
ignore_none=ignore_none))
|
|
343
389
|
|
|
344
390
|
return cls(**kwargs)
|
|
345
391
|
|
|
346
392
|
|
|
347
|
-
def deserialize_structure(cls, the_dict, *,
|
|
393
|
+
def deserialize_structure(cls, the_dict, *,
|
|
394
|
+
mapper=None,
|
|
395
|
+
keep_undefined=True,
|
|
396
|
+
camel_case_convert=False):
|
|
348
397
|
"""
|
|
349
398
|
Deserialize a dict to a Structure instance, Jackson style.
|
|
350
399
|
Note the top level must be a python dict - which implies that a JSON of
|
|
@@ -370,7 +419,9 @@ def deserialize_structure(cls, the_dict, *, mapper=None, keep_undefined=True):
|
|
|
370
419
|
an instance of the provided :class:`Structure` deserialized
|
|
371
420
|
"""
|
|
372
421
|
return deserialize_structure_internal(
|
|
373
|
-
cls, the_dict, mapper=mapper,
|
|
422
|
+
cls, the_dict, mapper=mapper,
|
|
423
|
+
keep_undefined=keep_undefined,
|
|
424
|
+
camel_case_convert=camel_case_convert
|
|
374
425
|
)
|
|
375
426
|
|
|
376
427
|
|
|
@@ -399,7 +450,7 @@ def get_processed_input(key, mapper, the_dict):
|
|
|
399
450
|
return processed_input
|
|
400
451
|
|
|
401
452
|
|
|
402
|
-
def serialize_val(field_definition, name, val, mapper=None):
|
|
453
|
+
def serialize_val(field_definition, name, val, mapper=None, camel_case_convert=False):
|
|
403
454
|
if isinstance(field_definition, SerializableField) and isinstance(
|
|
404
455
|
field_definition, Field
|
|
405
456
|
):
|
|
@@ -416,32 +467,37 @@ def serialize_val(field_definition, name, val, mapper=None):
|
|
|
416
467
|
):
|
|
417
468
|
key_type, value_type = field_definition.items
|
|
418
469
|
return {
|
|
419
|
-
serialize_val(key_type, name, k
|
|
470
|
+
serialize_val(key_type, name, k, camel_case_convert=camel_case_convert):
|
|
471
|
+
serialize_val(value_type, name, v, camel_case_convert=camel_case_convert)
|
|
420
472
|
for (k, v) in val.items()
|
|
421
473
|
}
|
|
422
474
|
else:
|
|
423
475
|
return {
|
|
424
|
-
serialize_val(Anything, name, k
|
|
476
|
+
serialize_val(Anything, name, k, camel_case_convert=camel_case_convert):
|
|
477
|
+
serialize_val(Anything, name, v, camel_case_convert=camel_case_convert)
|
|
425
478
|
for (k, v) in val.items()
|
|
426
479
|
}
|
|
427
480
|
if isinstance(field_definition.items, list):
|
|
428
481
|
return [
|
|
429
|
-
serialize_val(field_definition.items[ind], name, v, mapper=mapper
|
|
482
|
+
serialize_val(field_definition.items[ind], name, v, mapper=mapper,
|
|
483
|
+
camel_case_convert=camel_case_convert)
|
|
430
484
|
for ind, v in enumerate(val)
|
|
431
485
|
]
|
|
432
486
|
elif isinstance(field_definition.items, Field):
|
|
433
487
|
return [
|
|
434
|
-
serialize_val(field_definition.items, name, i, mapper=mapper
|
|
488
|
+
serialize_val(field_definition.items, name, i, mapper=mapper,
|
|
489
|
+
camel_case_convert=camel_case_convert)
|
|
435
490
|
for i in val
|
|
436
491
|
]
|
|
437
492
|
else:
|
|
438
|
-
return [serialize_val(None, name, i, mapper=mapper)
|
|
493
|
+
return [serialize_val(None, name, i, mapper=mapper, camel_case_convert=camel_case_convert)
|
|
494
|
+
for i in val]
|
|
439
495
|
if isinstance(val, (list, set, tuple)):
|
|
440
|
-
return [serialize_val(None, name, i) for i in val]
|
|
496
|
+
return [serialize_val(None, name, i, camel_case_convert=camel_case_convert) for i in val]
|
|
441
497
|
if isinstance(field_definition, Anything) and isinstance(val, Structure):
|
|
442
|
-
return serialize(val, mapper=mapper)
|
|
498
|
+
return serialize(val, mapper=mapper, camel_case_convert=camel_case_convert)
|
|
443
499
|
if isinstance(val, Structure) or isinstance(field_definition, Field):
|
|
444
|
-
return serialize_internal(val, mapper=mapper)
|
|
500
|
+
return serialize_internal(val, mapper=mapper, camel_case_convert=camel_case_convert)
|
|
445
501
|
|
|
446
502
|
# nothing worked. Not a typedpy field. Last ditch effort.
|
|
447
503
|
try:
|
|
@@ -450,7 +506,7 @@ def serialize_val(field_definition, name, val, mapper=None):
|
|
|
450
506
|
raise ValueError(f"{name}: cannot serialize value: {ex}") from ex
|
|
451
507
|
|
|
452
508
|
|
|
453
|
-
def serialize_field(field_definition: Field, value):
|
|
509
|
+
def serialize_field(field_definition: Field, value, camel_case_convert=False):
|
|
454
510
|
"""
|
|
455
511
|
Serialize a specific :class:`Field` from a structure to a JSON-like dict.
|
|
456
512
|
Example:
|
|
@@ -479,7 +535,8 @@ def serialize_field(field_definition: Field, value):
|
|
|
479
535
|
Returns:
|
|
480
536
|
a serialized Python object that can be directly converted to JSON
|
|
481
537
|
"""
|
|
482
|
-
return serialize_val(field_definition, field_definition._name, value
|
|
538
|
+
return serialize_val(field_definition, field_definition._name, value,
|
|
539
|
+
camel_case_convert=camel_case_convert)
|
|
483
540
|
|
|
484
541
|
|
|
485
542
|
def _get_mapped_value(mapper, key, items):
|
|
@@ -498,7 +555,23 @@ def _get_mapped_value(mapper, key, items):
|
|
|
498
555
|
return None
|
|
499
556
|
|
|
500
557
|
|
|
501
|
-
def
|
|
558
|
+
def _convert_to_camel_case_if_required(key, camel_case_convert):
|
|
559
|
+
if camel_case_convert:
|
|
560
|
+
words = key.split('_')
|
|
561
|
+
return words[0] + ''.join(w.title() for w in words[1:])
|
|
562
|
+
else:
|
|
563
|
+
return key
|
|
564
|
+
|
|
565
|
+
def _convert_to_snake_case_if_required(key, camel_case_convert):
|
|
566
|
+
if camel_case_convert:
|
|
567
|
+
return ''.join(['_' + char.lower() if char.isupper()
|
|
568
|
+
else char for char in key]).lstrip('_')
|
|
569
|
+
else:
|
|
570
|
+
return key
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def serialize_internal(structure, mapper=None, compact=False, camel_case_convert=False):
|
|
502
575
|
if mapper is None:
|
|
503
576
|
mapper = {}
|
|
504
577
|
field_by_name = _get_all_fields_by_name(structure.__class__)
|
|
@@ -520,7 +593,8 @@ def serialize_internal(structure, mapper=None, compact=False):
|
|
|
520
593
|
):
|
|
521
594
|
key = fields[0]
|
|
522
595
|
result = serialize_val(
|
|
523
|
-
field_by_name.get(key, None), key, getattr(structure, key)
|
|
596
|
+
field_by_name.get(key, None), key, getattr(structure, key),
|
|
597
|
+
camel_case_convert=camel_case_convert
|
|
524
598
|
)
|
|
525
599
|
else:
|
|
526
600
|
result = {}
|
|
@@ -531,7 +605,7 @@ def serialize_internal(structure, mapper=None, compact=False):
|
|
|
531
605
|
mapped_key = (
|
|
532
606
|
mapper[key]
|
|
533
607
|
if key in mapper and isinstance(mapper[key], (str,))
|
|
534
|
-
else key
|
|
608
|
+
else _convert_to_camel_case_if_required(key, camel_case_convert)
|
|
535
609
|
)
|
|
536
610
|
mapped_value = _get_mapped_value(mapper, key, items_map)
|
|
537
611
|
the_field_definition = (
|
|
@@ -539,12 +613,14 @@ def serialize_internal(structure, mapper=None, compact=False):
|
|
|
539
613
|
)
|
|
540
614
|
sub_mapper = mapper.get(f"{key}._mapper", {})
|
|
541
615
|
result[mapped_key] = serialize_val(
|
|
542
|
-
the_field_definition, key, mapped_value or val,
|
|
616
|
+
the_field_definition, key, mapped_value or val,
|
|
617
|
+
mapper=sub_mapper,
|
|
618
|
+
camel_case_convert=camel_case_convert
|
|
543
619
|
)
|
|
544
620
|
return result
|
|
545
621
|
|
|
546
622
|
|
|
547
|
-
def serialize(value, *, mapper: Dict = None, compact=False):
|
|
623
|
+
def serialize(value, *, mapper: Dict = None, compact=False, camel_case_convert=False):
|
|
548
624
|
"""
|
|
549
625
|
Serialize an instance of :class:`Structure` to a JSON-like dict.
|
|
550
626
|
`See working examples in test. <https://github.com/loyada/typedpy/tree/master/tests/test_serialization.py>`_
|
|
@@ -580,11 +656,12 @@ def serialize(value, *, mapper: Dict = None, compact=False):
|
|
|
580
656
|
return value
|
|
581
657
|
if isinstance(value, (_ListStruct, _DictStruct)):
|
|
582
658
|
field_definition = value._field_definition
|
|
583
|
-
return serialize_val(field_definition, field_definition._name, value
|
|
659
|
+
return serialize_val(field_definition, field_definition._name, value,
|
|
660
|
+
camel_case_convert=camel_case_convert)
|
|
584
661
|
if isinstance(value, (enum.Enum,)):
|
|
585
662
|
return value.name
|
|
586
663
|
raise TypeError(
|
|
587
664
|
"serialize: Not a Structure or Field that with an obvious serialization. Got: {}."
|
|
588
665
|
" Maybe try serialize_field() instead?".format(value)
|
|
589
666
|
)
|
|
590
|
-
return serialize_internal(value, mapper=mapper, compact=compact)
|
|
667
|
+
return serialize_internal(value, mapper=mapper, compact=compact, camel_case_convert=camel_case_convert)
|
home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/serialization_wrappers.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from typedpy import Structure
|
|
2
|
-
from typedpy.fields import StructureClass, Map, String, OneOf
|
|
2
|
+
from typedpy.fields import StructureClass, Map, String, OneOf, Boolean
|
|
3
3
|
from typedpy.serialization import FunctionCall, deserialize_structure, serialize
|
|
4
4
|
from typedpy.structures import _get_all_fields_by_name
|
|
5
5
|
|
|
@@ -49,11 +49,15 @@ class Deserializer(Structure):
|
|
|
49
49
|
}
|
|
50
50
|
Deserializer(target_class=Foo, mapper = mapper).deserializer(the_input_dict)
|
|
51
51
|
|
|
52
|
+
camel_case_convert(bool): Optional
|
|
53
|
+
If true, will convert any camelCase key that does not have explicit mapping to a snake_case attribute
|
|
54
|
+
name. Default is False.
|
|
52
55
|
|
|
53
56
|
"""
|
|
54
57
|
|
|
55
58
|
target_class = StructureClass
|
|
56
59
|
mapper = Map[String, OneOf[String, FunctionCall, Map]]
|
|
60
|
+
camel_case_convert = Boolean(default = False)
|
|
57
61
|
|
|
58
62
|
_required = ["target_class"]
|
|
59
63
|
|
|
@@ -74,6 +78,7 @@ class Deserializer(Structure):
|
|
|
74
78
|
input_data,
|
|
75
79
|
mapper=self.mapper,
|
|
76
80
|
keep_undefined=keep_undefined,
|
|
81
|
+
camel_case_convert=self.camel_case_convert
|
|
77
82
|
)
|
|
78
83
|
|
|
79
84
|
|
|
@@ -155,5 +160,20 @@ class Serializer(Structure):
|
|
|
155
160
|
for key in self.mapper:
|
|
156
161
|
verify_key_in_mapper(key, valid_keys, source_class)
|
|
157
162
|
|
|
158
|
-
def serialize(self, compact=True):
|
|
159
|
-
|
|
163
|
+
def serialize(self, compact=True, camel_case_convert=False):
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
Arguments:
|
|
167
|
+
compact(boolean): optional
|
|
168
|
+
whether to use a compact form for Structure that is a simple wrapper of a field.
|
|
169
|
+
for example: if a Structure has only one field of an int, if compact is True
|
|
170
|
+
it will serialize the structure as an int instead of a dictionary.
|
|
171
|
+
Default is False.
|
|
172
|
+
|
|
173
|
+
camel_case_convert(dict): optional
|
|
174
|
+
If True, convert any camel-case key that does not have a mapping in the mapper to a snake-case
|
|
175
|
+
attribute.
|
|
176
|
+
Default is False.
|
|
177
|
+
"""
|
|
178
|
+
return serialize(self.source, mapper=self.mapper, compact=compact,
|
|
179
|
+
camel_case_convert=camel_case_convert)
|
|
@@ -145,7 +145,7 @@ def _check_for_final_violations(classes):
|
|
|
145
145
|
)
|
|
146
146
|
)
|
|
147
147
|
if "ImmutableStructure" in globals() and is_sub_class(
|
|
148
|
-
|
|
148
|
+
c, ImmutableStructure
|
|
149
149
|
):
|
|
150
150
|
raise TypeError(
|
|
151
151
|
"Tried to extend {}, which is an ImmutableStructure. This is forbidden".format(
|
|
@@ -210,9 +210,9 @@ class UniqueMixin:
|
|
|
210
210
|
def __manage_uniqueness__(self):
|
|
211
211
|
myclass = self.__class__
|
|
212
212
|
if (
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
getattr(myclass, MUST_BE_UNIQUE, False)
|
|
214
|
+
and len(getattr(myclass, "_ALL_INSTANCES", set()))
|
|
215
|
+
< MAX_NUMBER_OF_INSTANCES_TO_VERIFY_UNIQUENESS
|
|
216
216
|
):
|
|
217
217
|
hash_of_instance = self.__hash__()
|
|
218
218
|
if hash_of_instance in getattr(myclass, "_ALL_INSTANCES", set()):
|
|
@@ -236,14 +236,14 @@ class UniqueMixin:
|
|
|
236
236
|
structure_class_name
|
|
237
237
|
]
|
|
238
238
|
if (
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
239
|
+
getattr(self, MUST_BE_UNIQUE, False)
|
|
240
|
+
and len(instance_by_value_for_current_struct)
|
|
241
|
+
< MAX_NUMBER_OF_INSTANCES_TO_VERIFY_UNIQUENESS
|
|
242
242
|
):
|
|
243
243
|
hash_of_field_val = value.__hash__()
|
|
244
244
|
if (
|
|
245
|
-
|
|
246
|
-
|
|
245
|
+
instance_by_value_for_current_struct.get(hash_of_field_val, instance)
|
|
246
|
+
!= instance
|
|
247
247
|
):
|
|
248
248
|
raise ValueError(
|
|
249
249
|
"Instance copy of field {} in {}, which is defined as unique. Instance is {}".format(
|
|
@@ -320,13 +320,13 @@ class Field(UniqueMixin, metaclass=_FieldMeta):
|
|
|
320
320
|
else owner.__dict__[self._name]
|
|
321
321
|
)
|
|
322
322
|
is_immutable = (
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
323
|
+
instance is not None
|
|
324
|
+
and getattr(instance, IS_IMMUTABLE, False)
|
|
325
|
+
or getattr(self, IS_IMMUTABLE, False)
|
|
326
326
|
)
|
|
327
327
|
needs_defensive_copy = (
|
|
328
|
-
|
|
329
|
-
|
|
328
|
+
not isinstance(res, (ImmutableMixin, int, float, str, bool, enum.Enum))
|
|
329
|
+
or res is None
|
|
330
330
|
)
|
|
331
331
|
return deepcopy(res) if (is_immutable and needs_defensive_copy) else res
|
|
332
332
|
|
|
@@ -334,7 +334,7 @@ class Field(UniqueMixin, metaclass=_FieldMeta):
|
|
|
334
334
|
if getattr(self, IS_IMMUTABLE, False) and self._name in instance.__dict__:
|
|
335
335
|
raise ValueError("{}: Field is immutable".format(self._name))
|
|
336
336
|
if getattr(self, IS_IMMUTABLE, False) and not getattr(
|
|
337
|
-
|
|
337
|
+
self, "_custom_deep_copy_implementation", False
|
|
338
338
|
):
|
|
339
339
|
try:
|
|
340
340
|
instance.__dict__[self._name] = deepcopy(value)
|
|
@@ -349,7 +349,7 @@ class Field(UniqueMixin, metaclass=_FieldMeta):
|
|
|
349
349
|
instance.__dict__[self._name] = value
|
|
350
350
|
instance.__manage__uniqueness_of_all_fields__()
|
|
351
351
|
if getattr(instance, "_instantiated", False) and not getattr(
|
|
352
|
-
|
|
352
|
+
instance, "_skip_validation", False
|
|
353
353
|
):
|
|
354
354
|
instance.__validate__()
|
|
355
355
|
|
|
@@ -413,34 +413,34 @@ def _get_all_fields_by_name(cls):
|
|
|
413
413
|
def _instantiate_fields_if_needed(cls_dict: dict, defaults: dict):
|
|
414
414
|
for key, val in cls_dict.items():
|
|
415
415
|
if (
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
416
|
+
key
|
|
417
|
+
not in {
|
|
418
|
+
REQUIRED_FIELDS,
|
|
419
|
+
ADDITIONAL_PROPERTIES,
|
|
420
|
+
IS_IMMUTABLE,
|
|
421
|
+
DEFAULTS,
|
|
422
|
+
OPTIONAL_FIELDS,
|
|
423
|
+
IGNORE_NONE_VALUES,
|
|
424
|
+
}
|
|
425
|
+
and not isinstance(val, Field)
|
|
426
|
+
and not key.startswith("__")
|
|
427
|
+
and (
|
|
428
428
|
Field in getattr(val, "__mro__", []) or is_function_returning_field(val)
|
|
429
|
-
|
|
429
|
+
)
|
|
430
430
|
):
|
|
431
431
|
new_val = val(default=defaults[key]) if key in defaults else val()
|
|
432
432
|
cls_dict[key] = new_val
|
|
433
433
|
|
|
434
434
|
|
|
435
435
|
def _apply_default_and_update_required_not_to_include_fields_with_defaults(
|
|
436
|
-
|
|
436
|
+
cls_dict: dict, defaults: dict, fields: list
|
|
437
437
|
):
|
|
438
438
|
required_fields = set(cls_dict.get(REQUIRED_FIELDS, []))
|
|
439
439
|
optional_fields = set(cls_dict.get(OPTIONAL_FIELDS, []))
|
|
440
440
|
required_fields_predefined = REQUIRED_FIELDS in cls_dict
|
|
441
441
|
for field_name in fields:
|
|
442
442
|
if field_name in defaults and not getattr(
|
|
443
|
-
|
|
443
|
+
cls_dict[field_name], "_default", None
|
|
444
444
|
):
|
|
445
445
|
cls_dict[field_name]._try_default_value(defaults[field_name])
|
|
446
446
|
cls_dict[field_name]._default = defaults[field_name]
|
|
@@ -547,15 +547,15 @@ def _type_is_generic(v):
|
|
|
547
547
|
generic_alias = getattr(typing, "_GenericAlias", Foo)
|
|
548
548
|
special_generic_alias = getattr(typing, "_SpecialGenericAlias", Foo)
|
|
549
549
|
return (
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
550
|
+
(python_ver_36 and isinstance(v, typing_base))
|
|
551
|
+
or (
|
|
552
|
+
python_ver_atleast_than_37
|
|
553
|
+
and isinstance(v, (generic_alias, special_generic_alias))
|
|
554
|
+
)
|
|
555
|
+
or (
|
|
556
|
+
python_ver_atleast_39
|
|
557
|
+
and origin in {list, dict, tuple, set, frozenset, deque, typing.Union}
|
|
558
|
+
)
|
|
559
559
|
)
|
|
560
560
|
|
|
561
561
|
|
|
@@ -614,7 +614,7 @@ def add_annotations_to_class_dict(cls_dict):
|
|
|
614
614
|
from .fields import AnyOf
|
|
615
615
|
|
|
616
616
|
if isinstance(the_type, AnyOf) and getattr(
|
|
617
|
-
|
|
617
|
+
the_type, "_is_optional", False
|
|
618
618
|
):
|
|
619
619
|
optional_fields.add(k)
|
|
620
620
|
if k in cls_dict:
|
|
@@ -691,6 +691,7 @@ class Structure(UniqueMixin, metaclass=StructMeta):
|
|
|
691
691
|
_ignore_none(bool): optional
|
|
692
692
|
Ignore assignment to None for any field value.
|
|
693
693
|
Default is False.
|
|
694
|
+
Required fields never ignore None (since they are required)
|
|
694
695
|
|
|
695
696
|
Decorating it with @unique ensures that no all instances of this structure will be unique. It
|
|
696
697
|
will raise an exception otherwise (see "Uniqueness" section).
|
|
@@ -723,14 +724,18 @@ class Structure(UniqueMixin, metaclass=StructMeta):
|
|
|
723
724
|
if key in self.__dict__:
|
|
724
725
|
raise ValueError("Structure is immutable")
|
|
725
726
|
value = deepcopy(value)
|
|
726
|
-
if getattr(self, IGNORE_NONE_VALUES, False)
|
|
727
|
+
if all([getattr(self, IGNORE_NONE_VALUES, False),
|
|
728
|
+
value is None,
|
|
729
|
+
key not in getattr(self.__class__, REQUIRED_FIELDS, [])]
|
|
730
|
+
):
|
|
727
731
|
return
|
|
732
|
+
|
|
728
733
|
super().__setattr__(key, value)
|
|
729
734
|
|
|
730
735
|
if (
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
736
|
+
getattr(self, "_instantiated", False)
|
|
737
|
+
and not _is_dunder(key)
|
|
738
|
+
and not _is_sunder(key)
|
|
734
739
|
):
|
|
735
740
|
self.__manage_uniqueness__()
|
|
736
741
|
|
|
@@ -766,7 +771,7 @@ class Structure(UniqueMixin, metaclass=StructMeta):
|
|
|
766
771
|
|
|
767
772
|
name = self.__class__.__name__
|
|
768
773
|
if name.startswith("StructureReference_") and self.__class__.__bases__ == (
|
|
769
|
-
|
|
774
|
+
Structure,
|
|
770
775
|
):
|
|
771
776
|
name = "Structure"
|
|
772
777
|
props = []
|
|
@@ -797,7 +802,7 @@ class Structure(UniqueMixin, metaclass=StructMeta):
|
|
|
797
802
|
|
|
798
803
|
def __delitem__(self, key):
|
|
799
804
|
if isinstance(getattr(self, REQUIRED_FIELDS), list) and key in getattr(
|
|
800
|
-
|
|
805
|
+
self, REQUIRED_FIELDS
|
|
801
806
|
):
|
|
802
807
|
raise ValueError("{} is mandatory".format(key))
|
|
803
808
|
del self.__dict__[key]
|
|
@@ -842,9 +847,9 @@ class Structure(UniqueMixin, metaclass=StructMeta):
|
|
|
842
847
|
required = props.get(REQUIRED_FIELDS, field_names)
|
|
843
848
|
additional_props = props.get(ADDITIONAL_PROPERTIES, True)
|
|
844
849
|
if (
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
850
|
+
len(field_names) == 1
|
|
851
|
+
and required == field_names
|
|
852
|
+
and additional_props is False
|
|
848
853
|
):
|
|
849
854
|
return item in getattr(self, field_names[0], {})
|
|
850
855
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: typedpy
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.4
|
|
4
4
|
Summary: Type-safe Python
|
|
5
5
|
Home-page: http://github.com/loyada/typedpy
|
|
6
6
|
Author: Danny Loya
|
|
7
7
|
Author-email: dan.loya@gmail.com
|
|
8
8
|
License: MIT
|
|
9
|
-
Download-URL: https://github.com/loyada/typedpy/archive/v2.2.
|
|
9
|
+
Download-URL: https://github.com/loyada/typedpy/archive/v2.2.4.tar.gz
|
|
10
10
|
Description: [![][travis img]][travis]
|
|
11
11
|
[![][docs img]][docs]
|
|
12
12
|
|
|
File without changes
|
|
File without changes
|