boto3-assist 0.5.2__tar.gz → 0.6.0__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.
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/PKG-INFO +1 -1
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/pyproject.toml +1 -1
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_model_base.py +19 -108
- boto3_assist-0.6.0/src/boto3_assist/models/serializable_model.py +9 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/utilities/serialization_utility.py +148 -6
- boto3_assist-0.6.0/src/boto3_assist/version.py +1 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/models/serializable_model_test.py +14 -0
- boto3_assist-0.5.2/src/boto3_assist/models/serializable_model.py +0 -34
- boto3_assist-0.5.2/src/boto3_assist/version.py +0 -1
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/.env.docker +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/.env.docker.001 +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/.env.docker.nosql.workbench +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/.env.unittest +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/.gitignore +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/.vscode/launch.json +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/.vscode/settings.json +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/.vscode/tasks.json +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/LICENSE-EXPLAINED.txt +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/LICENSE.txt +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/README.md +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/aws_regions_with_status.csv +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/aws_regions_with_status.json +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/devops/build.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/devops/readme.md +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/cloudwatch/log_report.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/models/order_item_model.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/models/order_model.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/models/product_model.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/models/user_model.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/models/user_post_model.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/order_example/main.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/order_example/products.json +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/services/order_item_service.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/services/order_service.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/services/product_service.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/services/table_service.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/services/user_post_service.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/services/user_service.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/services/user_service_client_example.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/services/user_service_resource_example.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/user_post_example/main.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/ec2/regions_report.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/module-headers.txt +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/mypy.ini +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/requirements-dev.txt +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/requirements.txt +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/run-checks.sh +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/aws_lambda/event_info.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/boto3session.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cloudwatch/cloudwatch_connection.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cloudwatch/cloudwatch_log_connection.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cloudwatch/cloudwatch_logs.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cloudwatch/cloudwatch_query.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cognito/cognito_authorizer.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cognito/cognito_connection.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cognito/cognito_utility.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cognito/jwks_cache.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cognito/user.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/connection.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/connection_tracker.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_connection.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_helpers.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_importer.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_index.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_iservice.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_key.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_reindexer.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.txt +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/readme.md +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/troubleshooting.md +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/ec2/ec2_connection.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/environment_services/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/environment_services/environment_loader.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/environment_services/environment_variables.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/errors/custom_exceptions.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/http_status_codes.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/s3/s3.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/s3/s3_connection.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/utilities/datetime_utility.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/utilities/dictionaroy_utility.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/utilities/file_operations.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/utilities/http_utility.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/utilities/logging_utility.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/utilities/numbers_utility.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/utilities/string_utility.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/__top/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/dynamodb_model_base_test.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/dynamodb_model_projections_test.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/dynamodb_model_serializtion_test.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/dynamodb_moto_sorting_test.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/dynamodb_reindex_test.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/models/cms/base.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/models/cms/content_block.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/models/cms/page.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/models/cms/template.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/models/simple_model.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/models/user_model.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/models/user_required_fields_model.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/examples_test/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/examples_test/user_service_test.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/lambda/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/lambda/event_info_test.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/models/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/s3/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/s3/files/test.txt +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/s3/s3_file_upload_test.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/utilities/__init__.py +0 -0
- {boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/utilities/serialization_utility_test.py +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:
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Geek Cafe, LLC
|
|
3
|
+
Maintainers: Eric Wilson
|
|
4
|
+
MIT License. See Project Root for the license information.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
from typing import TypeVar, Dict, Any
|
|
9
|
+
from boto3_assist.utilities.serialization_utility import SerializableModel
|
{boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/utilities/serialization_utility.py
RENAMED
|
@@ -2,17 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
from decimal import Decimal
|
|
5
|
-
from typing import Dict, List, TypeVar
|
|
5
|
+
from typing import Dict, List, TypeVar, Any
|
|
6
6
|
import json
|
|
7
7
|
import jsons
|
|
8
|
+
import datetime as dt
|
|
9
|
+
import decimal
|
|
10
|
+
import inspect
|
|
11
|
+
import uuid
|
|
8
12
|
from aws_lambda_powertools import Logger
|
|
9
13
|
|
|
14
|
+
|
|
10
15
|
T = TypeVar("T")
|
|
11
16
|
|
|
12
17
|
|
|
13
18
|
logger = Logger()
|
|
14
19
|
|
|
15
20
|
|
|
21
|
+
class SerializableModel:
|
|
22
|
+
"""Library to Serialize object to a DynamoDB Format"""
|
|
23
|
+
|
|
24
|
+
T = TypeVar("T", bound="SerializableModel")
|
|
25
|
+
|
|
26
|
+
def __init__(self):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
def map(
|
|
30
|
+
self: T,
|
|
31
|
+
source: Dict[str, Any] | "SerializableModel" | None,
|
|
32
|
+
coerce: bool = True,
|
|
33
|
+
) -> T:
|
|
34
|
+
"""
|
|
35
|
+
Map the source dictionary to the target object.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
- source: The dictionary to map from.
|
|
39
|
+
- target: The object to map to.
|
|
40
|
+
"""
|
|
41
|
+
mapped = Serialization.map(source=source, target=self, coerce=coerce)
|
|
42
|
+
if mapped is None:
|
|
43
|
+
raise ValueError("Unable to map source to target")
|
|
44
|
+
|
|
45
|
+
return mapped
|
|
46
|
+
|
|
47
|
+
def to_dictionary(self) -> Dict[str, Any]:
|
|
48
|
+
"""
|
|
49
|
+
Convert the object to a dictionary.
|
|
50
|
+
"""
|
|
51
|
+
# return Serialization.convert_object_to_dict(self)
|
|
52
|
+
return Serialization.to_dict(
|
|
53
|
+
instance=self, serialize_fn=lambda x: x, include_none=True
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
16
57
|
class JsonEncoder(json.JSONEncoder):
|
|
17
58
|
"""
|
|
18
59
|
This class is used to serialize python generics which implement a __json_encode__ method
|
|
@@ -52,7 +93,7 @@ class JsonEncoder(json.JSONEncoder):
|
|
|
52
93
|
|
|
53
94
|
class Serialization:
|
|
54
95
|
"""
|
|
55
|
-
|
|
96
|
+
Serialization Class
|
|
56
97
|
"""
|
|
57
98
|
|
|
58
99
|
@staticmethod
|
|
@@ -60,11 +101,12 @@ class Serialization:
|
|
|
60
101
|
"""
|
|
61
102
|
Dumps an object to dictionary structure
|
|
62
103
|
"""
|
|
63
|
-
dump = jsons.dump(model, strip_privates=True)
|
|
64
|
-
if isinstance(dump, dict) or isinstance(dump, List):
|
|
65
|
-
return dump
|
|
66
104
|
|
|
67
|
-
|
|
105
|
+
dump = Serialization.to_dict(
|
|
106
|
+
instance=model, serialize_fn=lambda x: x, include_none=True
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return dump
|
|
68
110
|
|
|
69
111
|
@staticmethod
|
|
70
112
|
def map(source: object, target: T, coerce: bool = True) -> T | None:
|
|
@@ -185,3 +227,103 @@ class Serialization:
|
|
|
185
227
|
"This procedure will update the property from False to True while serializing, "
|
|
186
228
|
"then back to False once serialization is complete. "
|
|
187
229
|
) from e
|
|
230
|
+
|
|
231
|
+
@staticmethod
|
|
232
|
+
def to_dict(
|
|
233
|
+
instance: SerializableModel,
|
|
234
|
+
serialize_fn,
|
|
235
|
+
include_none: bool = True,
|
|
236
|
+
) -> Dict[str, Any]:
|
|
237
|
+
"""To Dict / Dictionary"""
|
|
238
|
+
|
|
239
|
+
def is_primitive(value):
|
|
240
|
+
"""Check if the value is a primitive data type."""
|
|
241
|
+
return isinstance(value, (str, int, bool, type(None)))
|
|
242
|
+
|
|
243
|
+
def serialize_value(value):
|
|
244
|
+
"""Serialize the value using the provided function."""
|
|
245
|
+
|
|
246
|
+
if isinstance(value, SerializableModel):
|
|
247
|
+
return serialize_fn(
|
|
248
|
+
Serialization.to_dict(
|
|
249
|
+
instance=value,
|
|
250
|
+
serialize_fn=lambda x: x,
|
|
251
|
+
include_none=include_none,
|
|
252
|
+
)
|
|
253
|
+
)
|
|
254
|
+
if isinstance(value, dt.datetime):
|
|
255
|
+
return serialize_fn(value.isoformat())
|
|
256
|
+
elif isinstance(value, float):
|
|
257
|
+
v = serialize_fn(decimal.Decimal(str(value)))
|
|
258
|
+
return v
|
|
259
|
+
elif isinstance(value, decimal.Decimal):
|
|
260
|
+
return serialize_fn(value)
|
|
261
|
+
elif isinstance(value, uuid.UUID):
|
|
262
|
+
return serialize_fn(str(value))
|
|
263
|
+
elif isinstance(value, (bytes, bytearray)):
|
|
264
|
+
return serialize_fn(value.hex())
|
|
265
|
+
elif is_primitive(value):
|
|
266
|
+
return serialize_fn(value)
|
|
267
|
+
elif isinstance(value, list):
|
|
268
|
+
return serialize_fn([serialize_value(v) for v in value])
|
|
269
|
+
elif isinstance(value, dict):
|
|
270
|
+
return serialize_fn({k: serialize_value(v) for k, v in value.items()})
|
|
271
|
+
else:
|
|
272
|
+
return serialize_fn(
|
|
273
|
+
Serialization.to_dict(
|
|
274
|
+
value,
|
|
275
|
+
serialize_fn,
|
|
276
|
+
include_none=include_none,
|
|
277
|
+
)
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
instance_dict = Serialization._add_properties(
|
|
281
|
+
instance, serialize_value, include_none=include_none
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
return instance_dict
|
|
285
|
+
|
|
286
|
+
@staticmethod
|
|
287
|
+
def _add_properties(
|
|
288
|
+
instance: SerializableModel,
|
|
289
|
+
serialize_value,
|
|
290
|
+
include_none: bool = True,
|
|
291
|
+
) -> dict:
|
|
292
|
+
instance_dict = {}
|
|
293
|
+
|
|
294
|
+
# Add instance variables
|
|
295
|
+
for attr, value in instance.__dict__.items():
|
|
296
|
+
if str(attr) == "T":
|
|
297
|
+
continue
|
|
298
|
+
# don't get the private properties
|
|
299
|
+
if not str(attr).startswith("_"):
|
|
300
|
+
if value is not None or include_none:
|
|
301
|
+
instance_dict[attr] = serialize_value(value)
|
|
302
|
+
|
|
303
|
+
# Add properties
|
|
304
|
+
for name, _ in inspect.getmembers(
|
|
305
|
+
instance.__class__, predicate=inspect.isdatadescriptor
|
|
306
|
+
):
|
|
307
|
+
prop = None
|
|
308
|
+
try:
|
|
309
|
+
prop = getattr(instance.__class__, name)
|
|
310
|
+
except AttributeError:
|
|
311
|
+
continue
|
|
312
|
+
if isinstance(prop, property):
|
|
313
|
+
# Exclude properties marked with the exclude_from_serialization decorator
|
|
314
|
+
# Check if the property should be excluded
|
|
315
|
+
exclude = getattr(prop.fget, "exclude_from_serialization", False)
|
|
316
|
+
if exclude:
|
|
317
|
+
continue
|
|
318
|
+
|
|
319
|
+
# Skip TypeVar T or instances of DynamoDBModelBase
|
|
320
|
+
if str(name) == "T":
|
|
321
|
+
continue
|
|
322
|
+
|
|
323
|
+
# don't get the private properties
|
|
324
|
+
if not str(name).startswith("_"):
|
|
325
|
+
value = getattr(instance, name)
|
|
326
|
+
if value is not None or include_none:
|
|
327
|
+
instance_dict[name] = serialize_value(value)
|
|
328
|
+
|
|
329
|
+
return instance_dict
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.6.0'
|
|
@@ -119,6 +119,20 @@ class TestSerializableModel(unittest.TestCase):
|
|
|
119
119
|
self.assertEqual(result.age, 25)
|
|
120
120
|
self.assertEqual(result.active, True)
|
|
121
121
|
|
|
122
|
+
def test_to_dictionary(self):
|
|
123
|
+
"""
|
|
124
|
+
Test converting an object instance to a dictionary.
|
|
125
|
+
"""
|
|
126
|
+
model = ExampleModel(name="Bob", age=35, active=False)
|
|
127
|
+
|
|
128
|
+
result = model.to_dictionary()
|
|
129
|
+
|
|
130
|
+
self.assertIsInstance(result, dict)
|
|
131
|
+
self.assertEqual(len(result), 3)
|
|
132
|
+
self.assertEqual(result.get("name"), "Bob")
|
|
133
|
+
self.assertEqual(result.get("age"), 35)
|
|
134
|
+
self.assertEqual(result.get("active"), False)
|
|
135
|
+
|
|
122
136
|
|
|
123
137
|
if __name__ == "__main__":
|
|
124
138
|
unittest.main()
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Geek Cafe, LLC
|
|
3
|
-
Maintainers: Eric Wilson
|
|
4
|
-
MIT License. See Project Root for the license information.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
from typing import TypeVar, Dict, Any
|
|
9
|
-
from boto3_assist.utilities.serialization_utility import Serialization
|
|
10
|
-
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.5.2'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{boto3_assist-0.5.2 → boto3_assist-0.6.0}/examples/dynamodb/services/user_service_client_example.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cloudwatch/cloudwatch_connection.py
RENAMED
|
File without changes
|
|
File without changes
|
{boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/cloudwatch/cloudwatch_log_connection.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.py
RENAMED
|
File without changes
|
{boto3_assist-0.5.2 → boto3_assist-0.6.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/dynamodb_model_serializtion_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{boto3_assist-0.5.2 → boto3_assist-0.6.0}/tests/dynamodb/models/user_required_fields_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|