boto3-assist 0.5.2__py3-none-any.whl → 0.6.1__py3-none-any.whl
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.
- boto3_assist/dynamodb/dynamodb_model_base.py +19 -108
- boto3_assist/models/serializable_model.py +1 -26
- boto3_assist/utilities/serialization_utility.py +274 -12
- boto3_assist/version.py +1 -1
- {boto3_assist-0.5.2.dist-info → boto3_assist-0.6.1.dist-info}/METADATA +1 -1
- {boto3_assist-0.5.2.dist-info → boto3_assist-0.6.1.dist-info}/RECORD +9 -9
- {boto3_assist-0.5.2.dist-info → boto3_assist-0.6.1.dist-info}/WHEEL +0 -0
- {boto3_assist-0.5.2.dist-info → boto3_assist-0.6.1.dist-info}/licenses/LICENSE-EXPLAINED.txt +0 -0
- {boto3_assist-0.5.2.dist-info → boto3_assist-0.6.1.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -6,9 +6,10 @@ MIT License. See Project Root for the license information.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
import datetime as dt
|
|
9
|
-
|
|
10
|
-
import
|
|
11
|
-
import
|
|
9
|
+
|
|
10
|
+
# import decimal
|
|
11
|
+
# import inspect
|
|
12
|
+
# import uuid
|
|
12
13
|
from typing import TypeVar, List, Dict, Any
|
|
13
14
|
from boto3.dynamodb.types import TypeSerializer
|
|
14
15
|
from boto3_assist.utilities.serialization_utility import Serialization
|
|
@@ -19,6 +20,7 @@ from boto3_assist.dynamodb.dynamodb_index import (
|
|
|
19
20
|
)
|
|
20
21
|
from boto3_assist.dynamodb.dynamodb_reserved_words import DynamoDBReservedWords
|
|
21
22
|
from boto3_assist.utilities.datetime_utility import DatetimeUtility
|
|
23
|
+
from boto3_assist.models.serializable_model import SerializableModel
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
def exclude_from_serialization(method):
|
|
@@ -37,7 +39,7 @@ def exclude_indexes_from_serialization(method):
|
|
|
37
39
|
return method
|
|
38
40
|
|
|
39
41
|
|
|
40
|
-
class DynamoDBModelBase:
|
|
42
|
+
class DynamoDBModelBase(SerializableModel):
|
|
41
43
|
"""DyanmoDb Model Base"""
|
|
42
44
|
|
|
43
45
|
T = TypeVar("T", bound="DynamoDBModelBase")
|
|
@@ -270,7 +272,9 @@ class DynamoDBSerializer:
|
|
|
270
272
|
return mapped
|
|
271
273
|
|
|
272
274
|
@staticmethod
|
|
273
|
-
def to_client_dictionary(
|
|
275
|
+
def to_client_dictionary(
|
|
276
|
+
instance: DynamoDBModelBase, include_indexes: bool = True
|
|
277
|
+
) -> Dict[str, Any]:
|
|
274
278
|
"""
|
|
275
279
|
Convert a Python class instance to a dictionary suitable for DynamoDB client.
|
|
276
280
|
|
|
@@ -281,16 +285,19 @@ class DynamoDBSerializer:
|
|
|
281
285
|
- dict: A dictionary representation of the class instance suitable for DynamoDB client.
|
|
282
286
|
"""
|
|
283
287
|
serializer = TypeSerializer()
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
288
|
+
d = Serialization.to_dict(instance, serializer.serialize)
|
|
289
|
+
|
|
290
|
+
if include_indexes:
|
|
291
|
+
d = DynamoDBSerializer._add_indexes(instance=instance, instance_dict=d)
|
|
292
|
+
|
|
293
|
+
return d
|
|
287
294
|
|
|
288
295
|
@staticmethod
|
|
289
296
|
def to_resource_dictionary(
|
|
290
297
|
instance: DynamoDBModelBase,
|
|
291
298
|
include_indexes: bool = True,
|
|
292
299
|
include_none: bool = False,
|
|
293
|
-
):
|
|
300
|
+
) -> Dict[str, Any]:
|
|
294
301
|
"""
|
|
295
302
|
Convert a Python class instance to a dictionary suitable for DynamoDB resource.
|
|
296
303
|
|
|
@@ -300,112 +307,16 @@ class DynamoDBSerializer:
|
|
|
300
307
|
Returns:
|
|
301
308
|
- dict: A dictionary representation of the class instance suitable for DynamoDB resource.
|
|
302
309
|
"""
|
|
303
|
-
|
|
310
|
+
d = Serialization.to_dict(
|
|
304
311
|
instance,
|
|
305
312
|
lambda x: x,
|
|
306
|
-
include_indexes=include_indexes,
|
|
307
313
|
include_none=include_none,
|
|
308
314
|
)
|
|
309
315
|
|
|
310
|
-
@staticmethod
|
|
311
|
-
def _serialize(
|
|
312
|
-
instance: DynamoDBModelBase,
|
|
313
|
-
serialize_fn,
|
|
314
|
-
include_indexes: bool = True,
|
|
315
|
-
include_none: bool = True,
|
|
316
|
-
):
|
|
317
|
-
def is_primitive(value):
|
|
318
|
-
"""Check if the value is a primitive data type."""
|
|
319
|
-
return isinstance(value, (str, int, bool, type(None)))
|
|
320
|
-
|
|
321
|
-
def serialize_value(value):
|
|
322
|
-
"""Serialize the value using the provided function."""
|
|
323
|
-
|
|
324
|
-
if isinstance(value, DynamoDBModelBase):
|
|
325
|
-
return serialize_fn(
|
|
326
|
-
value.to_resource_dictionary(
|
|
327
|
-
include_indexes=False, include_none=include_none
|
|
328
|
-
)
|
|
329
|
-
)
|
|
330
|
-
if isinstance(value, dt.datetime):
|
|
331
|
-
return serialize_fn(value.isoformat())
|
|
332
|
-
elif isinstance(value, float):
|
|
333
|
-
v = serialize_fn(decimal.Decimal(str(value)))
|
|
334
|
-
return v
|
|
335
|
-
elif isinstance(value, decimal.Decimal):
|
|
336
|
-
return serialize_fn(value)
|
|
337
|
-
elif isinstance(value, uuid.UUID):
|
|
338
|
-
return serialize_fn(str(value))
|
|
339
|
-
elif isinstance(value, (bytes, bytearray)):
|
|
340
|
-
return serialize_fn(value.hex())
|
|
341
|
-
elif is_primitive(value):
|
|
342
|
-
return serialize_fn(value)
|
|
343
|
-
elif isinstance(value, list):
|
|
344
|
-
return serialize_fn([serialize_value(v) for v in value])
|
|
345
|
-
elif isinstance(value, dict):
|
|
346
|
-
return serialize_fn({k: serialize_value(v) for k, v in value.items()})
|
|
347
|
-
else:
|
|
348
|
-
return serialize_fn(
|
|
349
|
-
DynamoDBSerializer._serialize(
|
|
350
|
-
value,
|
|
351
|
-
serialize_fn,
|
|
352
|
-
include_indexes=include_indexes,
|
|
353
|
-
include_none=include_none,
|
|
354
|
-
)
|
|
355
|
-
)
|
|
356
|
-
|
|
357
|
-
instance_dict = DynamoDBSerializer._add_properties(
|
|
358
|
-
instance, serialize_value, include_none=include_none
|
|
359
|
-
)
|
|
360
|
-
|
|
361
316
|
if include_indexes:
|
|
362
|
-
|
|
363
|
-
return instance_dict
|
|
317
|
+
d = DynamoDBSerializer._add_indexes(instance=instance, instance_dict=d)
|
|
364
318
|
|
|
365
|
-
|
|
366
|
-
def _add_properties(
|
|
367
|
-
instance: DynamoDBModelBase,
|
|
368
|
-
serialize_value,
|
|
369
|
-
include_none: bool = True,
|
|
370
|
-
) -> dict:
|
|
371
|
-
instance_dict = {}
|
|
372
|
-
|
|
373
|
-
# Add instance variables
|
|
374
|
-
for attr, value in instance.__dict__.items():
|
|
375
|
-
if str(attr) == "T":
|
|
376
|
-
continue
|
|
377
|
-
# don't get the private properties
|
|
378
|
-
if not str(attr).startswith("_"):
|
|
379
|
-
if value is not None or include_none:
|
|
380
|
-
instance_dict[attr] = serialize_value(value)
|
|
381
|
-
|
|
382
|
-
# Add properties
|
|
383
|
-
for name, _ in inspect.getmembers(
|
|
384
|
-
instance.__class__, predicate=inspect.isdatadescriptor
|
|
385
|
-
):
|
|
386
|
-
prop = None
|
|
387
|
-
try:
|
|
388
|
-
prop = getattr(instance.__class__, name)
|
|
389
|
-
except AttributeError:
|
|
390
|
-
continue
|
|
391
|
-
if isinstance(prop, property):
|
|
392
|
-
# Exclude properties marked with the exclude_from_serialization decorator
|
|
393
|
-
# Check if the property should be excluded
|
|
394
|
-
exclude = getattr(prop.fget, "exclude_from_serialization", False)
|
|
395
|
-
if exclude:
|
|
396
|
-
continue
|
|
397
|
-
|
|
398
|
-
# Skip TypeVar T or instances of DynamoDBModelBase
|
|
399
|
-
if str(name) == "T":
|
|
400
|
-
continue
|
|
401
|
-
|
|
402
|
-
# don't get the private properties
|
|
403
|
-
if not str(name).startswith("_"):
|
|
404
|
-
value = getattr(instance, name)
|
|
405
|
-
if value is not None or include_none:
|
|
406
|
-
instance_dict[name] = serialize_value(value)
|
|
407
|
-
|
|
408
|
-
return instance_dict
|
|
319
|
+
return d
|
|
409
320
|
|
|
410
321
|
@staticmethod
|
|
411
322
|
def _add_indexes(instance: DynamoDBModelBase, instance_dict: dict) -> dict:
|
|
@@ -5,30 +5,5 @@ MIT License. See Project Root for the license information.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
|
-
from typing import TypeVar, Dict, Any
|
|
9
|
-
from boto3_assist.utilities.serialization_utility import Serialization
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
class SerializableModel:
|
|
13
|
-
"""Library to Serialize object to a DynamoDB Format"""
|
|
14
|
-
|
|
15
|
-
T = TypeVar("T", bound="SerializableModel")
|
|
16
|
-
|
|
17
|
-
def __init__(self):
|
|
18
|
-
pass
|
|
19
|
-
|
|
20
|
-
def map(
|
|
21
|
-
self: T, source: Dict[str, Any] | SerializableModel | None, coerce: bool = True
|
|
22
|
-
) -> T:
|
|
23
|
-
"""
|
|
24
|
-
Map the source dictionary to the target object.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
- source: The dictionary to map from.
|
|
28
|
-
- target: The object to map to.
|
|
29
|
-
"""
|
|
30
|
-
mapped = Serialization.map(source=source, target=self, coerce=coerce)
|
|
31
|
-
if mapped is None:
|
|
32
|
-
raise ValueError("Unable to map source to target")
|
|
33
|
-
|
|
34
|
-
return mapped
|
|
9
|
+
from boto3_assist.utilities.serialization_utility import SerializableModel # noqa: F401 # pylint: disable=unused-import
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"""Serialization Utility"""
|
|
2
2
|
|
|
3
|
+
import datetime as dt
|
|
4
|
+
import decimal
|
|
5
|
+
import inspect
|
|
6
|
+
import json
|
|
7
|
+
import uuid
|
|
3
8
|
from datetime import datetime
|
|
4
9
|
from decimal import Decimal
|
|
5
|
-
from typing import Dict, List, TypeVar
|
|
6
|
-
|
|
7
|
-
import jsons
|
|
10
|
+
from typing import Any, Dict, List, TypeVar
|
|
11
|
+
|
|
8
12
|
from aws_lambda_powertools import Logger
|
|
9
13
|
|
|
10
14
|
T = TypeVar("T")
|
|
@@ -13,6 +17,51 @@ T = TypeVar("T")
|
|
|
13
17
|
logger = Logger()
|
|
14
18
|
|
|
15
19
|
|
|
20
|
+
class SerializableModel:
|
|
21
|
+
"""Library to Serialize object to a DynamoDB Format"""
|
|
22
|
+
|
|
23
|
+
T = TypeVar("T", bound="SerializableModel")
|
|
24
|
+
|
|
25
|
+
def __init__(self):
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
def map(
|
|
29
|
+
self: T,
|
|
30
|
+
source: Dict[str, Any] | "SerializableModel" | None,
|
|
31
|
+
coerce: bool = True,
|
|
32
|
+
) -> T:
|
|
33
|
+
"""
|
|
34
|
+
Map the source dictionary to the target object.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
- source: The dictionary to map from.
|
|
38
|
+
- target: The object to map to.
|
|
39
|
+
"""
|
|
40
|
+
mapped = Serialization.map(source=source, target=self, coerce=coerce)
|
|
41
|
+
if mapped is None:
|
|
42
|
+
raise ValueError("Unable to map source to target")
|
|
43
|
+
|
|
44
|
+
return mapped
|
|
45
|
+
|
|
46
|
+
def to_dictionary(self) -> Dict[str, Any]:
|
|
47
|
+
"""
|
|
48
|
+
Convert the object to a dictionary.
|
|
49
|
+
"""
|
|
50
|
+
# return Serialization.convert_object_to_dict(self)
|
|
51
|
+
return Serialization.to_dict(
|
|
52
|
+
instance=self, serialize_fn=lambda x: x, include_none=True
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def to_wide_dictionary(self) -> Dict:
|
|
56
|
+
"""
|
|
57
|
+
Dumps an object to dictionary structure
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
dump = Serialization.to_wide_dictionary(model=self)
|
|
61
|
+
|
|
62
|
+
return dump
|
|
63
|
+
|
|
64
|
+
|
|
16
65
|
class JsonEncoder(json.JSONEncoder):
|
|
17
66
|
"""
|
|
18
67
|
This class is used to serialize python generics which implement a __json_encode__ method
|
|
@@ -52,7 +101,7 @@ class JsonEncoder(json.JSONEncoder):
|
|
|
52
101
|
|
|
53
102
|
class Serialization:
|
|
54
103
|
"""
|
|
55
|
-
|
|
104
|
+
Serialization Class
|
|
56
105
|
"""
|
|
57
106
|
|
|
58
107
|
@staticmethod
|
|
@@ -60,11 +109,38 @@ class Serialization:
|
|
|
60
109
|
"""
|
|
61
110
|
Dumps an object to dictionary structure
|
|
62
111
|
"""
|
|
63
|
-
dump = jsons.dump(model, strip_privates=True)
|
|
64
|
-
if isinstance(dump, dict) or isinstance(dump, List):
|
|
65
|
-
return dump
|
|
66
112
|
|
|
67
|
-
|
|
113
|
+
dump = Serialization.to_dict(
|
|
114
|
+
instance=model, serialize_fn=lambda x: x, include_none=True
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return dump
|
|
118
|
+
|
|
119
|
+
@staticmethod
|
|
120
|
+
def to_wide_dictionary(model: object) -> Dict:
|
|
121
|
+
"""
|
|
122
|
+
Dumps an object to dictionary structure
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
dump = Serialization.to_dict(
|
|
126
|
+
instance=model, serialize_fn=lambda x: x, include_none=True
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# have a dictionary now let's flatten out
|
|
130
|
+
flat_dict = {}
|
|
131
|
+
for key, value in dump.items():
|
|
132
|
+
if isinstance(value, dict):
|
|
133
|
+
for sub_key, sub_value in value.items():
|
|
134
|
+
flat_dict[f"{key}_{sub_key}"] = sub_value
|
|
135
|
+
elif isinstance(value, list):
|
|
136
|
+
for i, sub_value in enumerate(value):
|
|
137
|
+
sub_dict = Serialization.to_wide_dictionary(sub_value)
|
|
138
|
+
for sub_key, sub_value in sub_dict.items():
|
|
139
|
+
flat_dict[f"{key}_{i}_{sub_key}"] = sub_value
|
|
140
|
+
else:
|
|
141
|
+
flat_dict[key] = value
|
|
142
|
+
|
|
143
|
+
return flat_dict
|
|
68
144
|
|
|
69
145
|
@staticmethod
|
|
70
146
|
def map(source: object, target: T, coerce: bool = True) -> T | None:
|
|
@@ -76,12 +152,92 @@ class Serialization:
|
|
|
76
152
|
source_dict = Serialization.convert_object_to_dict(source)
|
|
77
153
|
if not isinstance(source_dict, dict):
|
|
78
154
|
return None
|
|
79
|
-
return Serialization.
|
|
155
|
+
return Serialization._load_properties(
|
|
80
156
|
source=source_dict, target=target, coerce=coerce
|
|
81
157
|
)
|
|
82
158
|
|
|
83
159
|
@staticmethod
|
|
84
|
-
def
|
|
160
|
+
def to_wide_dictionary_list(
|
|
161
|
+
data: Dict[str, Any] | List[Dict[str, Any]],
|
|
162
|
+
remove_collisions: bool = True,
|
|
163
|
+
raise_error_on_collision: bool = False,
|
|
164
|
+
) -> List[Dict[str, Any]]:
|
|
165
|
+
"""
|
|
166
|
+
Converts a dictionary or list of dictionaries to a list of dictionaries.
|
|
167
|
+
|
|
168
|
+
:param data: Dictionary or list of dictionaries to be converted
|
|
169
|
+
:param remove_collisions: If True, removes duplicate keys from the dictionaries
|
|
170
|
+
:return: List of dictionaries
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
collisions = []
|
|
174
|
+
|
|
175
|
+
def recursive_flatten(prefix, obj):
|
|
176
|
+
"""
|
|
177
|
+
Recursively flattens a JSON object.
|
|
178
|
+
|
|
179
|
+
:param prefix: Current key prefix
|
|
180
|
+
:param obj: Object to flatten
|
|
181
|
+
:return: List of flattened dictionaries
|
|
182
|
+
"""
|
|
183
|
+
if isinstance(obj, list):
|
|
184
|
+
result = []
|
|
185
|
+
for _, item in enumerate(obj):
|
|
186
|
+
x = recursive_flatten("", item)
|
|
187
|
+
result.extend(x)
|
|
188
|
+
return result
|
|
189
|
+
elif isinstance(obj, dict):
|
|
190
|
+
result = [{}]
|
|
191
|
+
for key, value in obj.items():
|
|
192
|
+
sub_result = recursive_flatten(
|
|
193
|
+
f"{prefix}_{key}" if prefix else key, value
|
|
194
|
+
)
|
|
195
|
+
new_result = []
|
|
196
|
+
for entry in result:
|
|
197
|
+
for sub_entry in sub_result:
|
|
198
|
+
# remove any collisions
|
|
199
|
+
|
|
200
|
+
for k in entry:
|
|
201
|
+
if k in sub_entry:
|
|
202
|
+
if k not in collisions:
|
|
203
|
+
logger.debug(f"Collision detected: {k}")
|
|
204
|
+
collisions.append(k)
|
|
205
|
+
merged = entry.copy()
|
|
206
|
+
merged.update(sub_entry)
|
|
207
|
+
new_result.append(merged)
|
|
208
|
+
result = new_result
|
|
209
|
+
return result
|
|
210
|
+
else:
|
|
211
|
+
return [{prefix: obj}] if prefix else []
|
|
212
|
+
|
|
213
|
+
results = recursive_flatten("", data)
|
|
214
|
+
if remove_collisions:
|
|
215
|
+
results = Serialization.remove_collisions(results, collisions)
|
|
216
|
+
|
|
217
|
+
if raise_error_on_collision and len(collisions) > 0:
|
|
218
|
+
raise ValueError(f"Duplicate keys detected: {collisions}")
|
|
219
|
+
|
|
220
|
+
return results
|
|
221
|
+
|
|
222
|
+
@staticmethod
|
|
223
|
+
def remove_collisions(
|
|
224
|
+
data: List[Dict[str, Any]], collisions: List[str]
|
|
225
|
+
) -> List[Dict[str, Any]]:
|
|
226
|
+
"""
|
|
227
|
+
Removes collisions from a list of dictionaries.
|
|
228
|
+
|
|
229
|
+
:param data: List of dictionaries
|
|
230
|
+
:param collisions: List of collision keys
|
|
231
|
+
:return: List of dictionaries with collisions removed
|
|
232
|
+
"""
|
|
233
|
+
for c in collisions:
|
|
234
|
+
for r in data:
|
|
235
|
+
if c in r:
|
|
236
|
+
del r[c]
|
|
237
|
+
return data
|
|
238
|
+
|
|
239
|
+
@staticmethod
|
|
240
|
+
def _load_properties(
|
|
85
241
|
source: dict,
|
|
86
242
|
target: T,
|
|
87
243
|
coerce: bool = True,
|
|
@@ -141,9 +297,9 @@ class Serialization:
|
|
|
141
297
|
attr.clear()
|
|
142
298
|
attr.extend(value)
|
|
143
299
|
elif isinstance(attr, dict) and isinstance(value, dict):
|
|
144
|
-
Serialization.
|
|
300
|
+
Serialization._load_properties(value, attr, coerce=coerce)
|
|
145
301
|
elif hasattr(attr, "__dict__") and isinstance(value, dict):
|
|
146
|
-
Serialization.
|
|
302
|
+
Serialization._load_properties(value, attr, coerce=coerce)
|
|
147
303
|
else:
|
|
148
304
|
setattr(target, key, value)
|
|
149
305
|
except ValueError as e:
|
|
@@ -185,3 +341,109 @@ class Serialization:
|
|
|
185
341
|
"This procedure will update the property from False to True while serializing, "
|
|
186
342
|
"then back to False once serialization is complete. "
|
|
187
343
|
) from e
|
|
344
|
+
|
|
345
|
+
@staticmethod
|
|
346
|
+
def to_dict(
|
|
347
|
+
instance: SerializableModel | dict,
|
|
348
|
+
serialize_fn,
|
|
349
|
+
include_none: bool = True,
|
|
350
|
+
) -> Dict[str, Any]:
|
|
351
|
+
"""To Dict / Dictionary"""
|
|
352
|
+
|
|
353
|
+
if instance is None:
|
|
354
|
+
return {}
|
|
355
|
+
|
|
356
|
+
if isinstance(instance, dict):
|
|
357
|
+
return instance
|
|
358
|
+
|
|
359
|
+
def is_primitive(value):
|
|
360
|
+
"""Check if the value is a primitive data type."""
|
|
361
|
+
return isinstance(value, (str, int, bool, type(None)))
|
|
362
|
+
|
|
363
|
+
def serialize_value(value):
|
|
364
|
+
"""Serialize the value using the provided function."""
|
|
365
|
+
|
|
366
|
+
if isinstance(value, SerializableModel):
|
|
367
|
+
return serialize_fn(
|
|
368
|
+
Serialization.to_dict(
|
|
369
|
+
instance=value,
|
|
370
|
+
serialize_fn=lambda x: x,
|
|
371
|
+
include_none=include_none,
|
|
372
|
+
)
|
|
373
|
+
)
|
|
374
|
+
if isinstance(value, dt.datetime):
|
|
375
|
+
return serialize_fn(value.isoformat())
|
|
376
|
+
elif isinstance(value, float):
|
|
377
|
+
v = serialize_fn(decimal.Decimal(str(value)))
|
|
378
|
+
return v
|
|
379
|
+
elif isinstance(value, decimal.Decimal):
|
|
380
|
+
return serialize_fn(value)
|
|
381
|
+
elif isinstance(value, uuid.UUID):
|
|
382
|
+
return serialize_fn(str(value))
|
|
383
|
+
elif isinstance(value, (bytes, bytearray)):
|
|
384
|
+
return serialize_fn(value.hex())
|
|
385
|
+
elif is_primitive(value):
|
|
386
|
+
return serialize_fn(value)
|
|
387
|
+
elif isinstance(value, list):
|
|
388
|
+
return serialize_fn([serialize_value(v) for v in value])
|
|
389
|
+
elif isinstance(value, dict):
|
|
390
|
+
return serialize_fn({k: serialize_value(v) for k, v in value.items()})
|
|
391
|
+
else:
|
|
392
|
+
return serialize_fn(
|
|
393
|
+
Serialization.to_dict(
|
|
394
|
+
value,
|
|
395
|
+
serialize_fn,
|
|
396
|
+
include_none=include_none,
|
|
397
|
+
)
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
instance_dict = Serialization._add_properties(
|
|
401
|
+
instance, serialize_value, include_none=include_none
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
return instance_dict
|
|
405
|
+
|
|
406
|
+
@staticmethod
|
|
407
|
+
def _add_properties(
|
|
408
|
+
instance: SerializableModel,
|
|
409
|
+
serialize_value,
|
|
410
|
+
include_none: bool = True,
|
|
411
|
+
) -> dict:
|
|
412
|
+
instance_dict = {}
|
|
413
|
+
|
|
414
|
+
# Add instance variables
|
|
415
|
+
for attr, value in instance.__dict__.items():
|
|
416
|
+
if str(attr) == "T":
|
|
417
|
+
continue
|
|
418
|
+
# don't get the private properties
|
|
419
|
+
if not str(attr).startswith("_"):
|
|
420
|
+
if value is not None or include_none:
|
|
421
|
+
instance_dict[attr] = serialize_value(value)
|
|
422
|
+
|
|
423
|
+
# Add properties
|
|
424
|
+
for name, _ in inspect.getmembers(
|
|
425
|
+
instance.__class__, predicate=inspect.isdatadescriptor
|
|
426
|
+
):
|
|
427
|
+
prop = None
|
|
428
|
+
try:
|
|
429
|
+
prop = getattr(instance.__class__, name)
|
|
430
|
+
except AttributeError:
|
|
431
|
+
continue
|
|
432
|
+
if isinstance(prop, property):
|
|
433
|
+
# Exclude properties marked with the exclude_from_serialization decorator
|
|
434
|
+
# Check if the property should be excluded
|
|
435
|
+
exclude = getattr(prop.fget, "exclude_from_serialization", False)
|
|
436
|
+
if exclude:
|
|
437
|
+
continue
|
|
438
|
+
|
|
439
|
+
# Skip TypeVar T or instances of DynamoDBModelBase
|
|
440
|
+
if str(name) == "T":
|
|
441
|
+
continue
|
|
442
|
+
|
|
443
|
+
# don't get the private properties
|
|
444
|
+
if not str(name).startswith("_"):
|
|
445
|
+
value = getattr(instance, name)
|
|
446
|
+
if value is not None or include_none:
|
|
447
|
+
instance_dict[name] = serialize_value(value)
|
|
448
|
+
|
|
449
|
+
return instance_dict
|
boto3_assist/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '0.
|
|
1
|
+
__version__ = '0.6.1'
|
|
@@ -3,7 +3,7 @@ boto3_assist/boto3session.py,sha256=Q9sByNC0r_aMQfHnIEnxtTaiCMUqikm8UeSTxV7-Np0,
|
|
|
3
3
|
boto3_assist/connection.py,sha256=CNGkAIRyfrELoWrV0ziQBA3oHacNFuLL3i8faUPRiO0,3486
|
|
4
4
|
boto3_assist/connection_tracker.py,sha256=bfImvNVX-0Lhb-ombOurWUpNLdI0qVDil-kokBdIFkY,4345
|
|
5
5
|
boto3_assist/http_status_codes.py,sha256=G0zRSWenwavYKETvDF9tNVUXQz3Ae2gXdBETYbjvJe8,3284
|
|
6
|
-
boto3_assist/version.py,sha256=
|
|
6
|
+
boto3_assist/version.py,sha256=gd3s3RotD0_KL90Tua-YkOr60Jm2C2_wvlEhAT08068,22
|
|
7
7
|
boto3_assist/aws_lambda/event_info.py,sha256=OkZ4WzuGaHEu_T8sB188KBgShAJhZpWASALKRGBOhMg,14648
|
|
8
8
|
boto3_assist/cloudwatch/cloudwatch_connection.py,sha256=mnGWaLSQpHh5EeY7Ek_2o9JKHJxOELIYtQVMX1IaHn4,2480
|
|
9
9
|
boto3_assist/cloudwatch/cloudwatch_connection_tracker.py,sha256=mzRtO1uHrcfJNh1XrGEiXdTqxwEP8d1RqJkraMNkgK0,410
|
|
@@ -22,7 +22,7 @@ boto3_assist/dynamodb/dynamodb_importer.py,sha256=nCKsyRQeMqDSf0Q5mQ_X_oVIg4PRnu
|
|
|
22
22
|
boto3_assist/dynamodb/dynamodb_index.py,sha256=D0Lq121qk1cXeMetPeqnzvv6CXd0XfEygfdUXaljLG8,8551
|
|
23
23
|
boto3_assist/dynamodb/dynamodb_iservice.py,sha256=O9Aj0PFEvcuk2vhARifWTFnUwcQW5EXzwZS478Hm-N0,796
|
|
24
24
|
boto3_assist/dynamodb/dynamodb_key.py,sha256=YD7o1EUlwVBQ55p9YCTKqAUU_np4nqtLIHnmp-BeolM,1803
|
|
25
|
-
boto3_assist/dynamodb/dynamodb_model_base.py,sha256=
|
|
25
|
+
boto3_assist/dynamodb/dynamodb_model_base.py,sha256=Jmy0GAblYqdLlVOT7H-1li50bacemeduocgNs75Yvt8,11910
|
|
26
26
|
boto3_assist/dynamodb/dynamodb_model_base_interfaces.py,sha256=yT4zDRI8vP15WVOHnCvY3FsEy_QSIta5-bnUby70Xow,747
|
|
27
27
|
boto3_assist/dynamodb/dynamodb_reindexer.py,sha256=bCj6KIU0fQOgjkkiq9yF51PFZZr4Y9Lu3-hPlmsPG0Y,6164
|
|
28
28
|
boto3_assist/dynamodb/dynamodb_reserved_words.py,sha256=p0irNBSqGe4rd2FwWQqbRJWrNr4svdbWiyIXmz9lj4c,1937
|
|
@@ -34,7 +34,7 @@ boto3_assist/environment_services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
|
|
|
34
34
|
boto3_assist/environment_services/environment_loader.py,sha256=zCA4mRdVWMLKzjDRvrJbhQfRVP4HAMGpuQFi07zzULk,3396
|
|
35
35
|
boto3_assist/environment_services/environment_variables.py,sha256=4ccBKdPt6O7hcRT3zBHd8vqu8yQU8udmoD5RLAT3iMs,6801
|
|
36
36
|
boto3_assist/errors/custom_exceptions.py,sha256=zC2V2Y4PUtKj3uLPn8mB-JessksKWJWvKM9kp1dmvt8,760
|
|
37
|
-
boto3_assist/models/serializable_model.py,sha256=
|
|
37
|
+
boto3_assist/models/serializable_model.py,sha256=ZMrRJRvJWLY8PBSKK_nPCgYKv1qUxDPEVdcADKbIHsI,266
|
|
38
38
|
boto3_assist/s3/s3.py,sha256=DFCJs5z1mMIT8nZfnqPyr_cvhi9-FePuYH--tzD7b5E,17104
|
|
39
39
|
boto3_assist/s3/s3_connection.py,sha256=FI1AhZV4UbTXQRTb4TqL9mv88Gt018rPZVFBvLetVAw,2163
|
|
40
40
|
boto3_assist/utilities/datetime_utility.py,sha256=dgAMB9VqakrYIPXlSoVQiLSsc_yhrJK4gMfJO9mX90w,11112
|
|
@@ -43,10 +43,10 @@ boto3_assist/utilities/file_operations.py,sha256=Zy8fu8fpuVNf7U9NimrLdy5FRF71XSI
|
|
|
43
43
|
boto3_assist/utilities/http_utility.py,sha256=koFv7Va-8ng-47Nt1K2Sh7Ti95e62IYs9VMLlGh9Kt4,1173
|
|
44
44
|
boto3_assist/utilities/logging_utility.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
45
|
boto3_assist/utilities/numbers_utility.py,sha256=KIiNkBSRbfNWvtXG5SdHp625LTiW12VtADUa4ZlWMFo,8709
|
|
46
|
-
boto3_assist/utilities/serialization_utility.py,sha256=
|
|
46
|
+
boto3_assist/utilities/serialization_utility.py,sha256=KJhit0lI1lr8hhndW6UhKQSZD3c2RH555Ni7eP-e5Ms,16557
|
|
47
47
|
boto3_assist/utilities/string_utility.py,sha256=sBY80aQO-fTRanlHryZFMQBxdo6OvLRvnZjZrQepHlI,9283
|
|
48
|
-
boto3_assist-0.
|
|
49
|
-
boto3_assist-0.
|
|
50
|
-
boto3_assist-0.
|
|
51
|
-
boto3_assist-0.
|
|
52
|
-
boto3_assist-0.
|
|
48
|
+
boto3_assist-0.6.1.dist-info/METADATA,sha256=MVB3qF040hI48bRH8xhXXkyX9aewgYUUiGtUubi2l-0,1728
|
|
49
|
+
boto3_assist-0.6.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
50
|
+
boto3_assist-0.6.1.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
|
|
51
|
+
boto3_assist-0.6.1.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
|
|
52
|
+
boto3_assist-0.6.1.dist-info/RECORD,,
|
|
File without changes
|
{boto3_assist-0.5.2.dist-info → boto3_assist-0.6.1.dist-info}/licenses/LICENSE-EXPLAINED.txt
RENAMED
|
File without changes
|
|
File without changes
|