boto3-assist 0.6.0__tar.gz → 0.6.1__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.6.0 → boto3_assist-0.6.1}/.gitignore +2 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/.vscode/settings.json +1 -2
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/PKG-INFO +1 -1
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/pyproject.toml +1 -1
- boto3_assist-0.6.1/run_unit_tests.sh +22 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/models/serializable_model.py +2 -2
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/utilities/serialization_utility.py +131 -11
- boto3_assist-0.6.1/src/boto3_assist/version.py +1 -0
- {boto3_assist-0.6.0/tests/utilities → boto3_assist-0.6.1/tests/__top}/__init__.py +4 -1
- {boto3_assist-0.6.0/tests/dynamodb/models → boto3_assist-0.6.1/tests/dynamodb/dbmodels}/cms/page.py +1 -1
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/dynamodb/dynamodb_model_base_test.py +3 -4
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/dynamodb/dynamodb_model_projections_test.py +2 -2
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/dynamodb/dynamodb_model_serializtion_test.py +2 -2
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/dynamodb/dynamodb_moto_sorting_test.py +3 -5
- boto3_assist-0.6.1/tests/models/serializable_model_wide_test.py +246 -0
- boto3_assist-0.6.1/tests/utilities/__init__.py +0 -0
- boto3_assist-0.6.0/src/boto3_assist/version.py +0 -1
- boto3_assist-0.6.0/tests/__top/__init__.py +0 -16
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/.env.docker +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/.env.docker.001 +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/.env.docker.nosql.workbench +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/.env.unittest +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/.vscode/launch.json +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/.vscode/tasks.json +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/LICENSE-EXPLAINED.txt +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/LICENSE.txt +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/README.md +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/aws_regions_with_status.csv +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/aws_regions_with_status.json +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/devops/build.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/devops/readme.md +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/__init__.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/cloudwatch/log_report.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/models/order_item_model.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/models/order_model.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/models/product_model.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/models/user_model.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/models/user_post_model.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/order_example/main.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/order_example/products.json +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/services/order_item_service.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/services/order_service.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/services/product_service.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/services/table_service.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/services/user_post_service.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/services/user_service.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/services/user_service_client_example.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/services/user_service_resource_example.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/dynamodb/user_post_example/main.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/examples/ec2/regions_report.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/module-headers.txt +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/mypy.ini +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/requirements-dev.txt +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/requirements.txt +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/run-checks.sh +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/__init__.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/aws_lambda/event_info.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/boto3session.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cloudwatch/cloudwatch_connection.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cloudwatch/cloudwatch_log_connection.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cloudwatch/cloudwatch_logs.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cloudwatch/cloudwatch_query.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cognito/cognito_authorizer.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cognito/cognito_connection.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cognito/cognito_utility.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cognito/jwks_cache.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cognito/user.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/connection.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/connection_tracker.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_connection.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_helpers.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_importer.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_index.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_iservice.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_key.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_model_base.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_reindexer.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_reserved_words.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_reserved_words.txt +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/readme.md +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/troubleshooting.md +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/ec2/ec2_connection.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/environment_services/__init__.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/environment_services/environment_loader.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/environment_services/environment_variables.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/errors/custom_exceptions.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/http_status_codes.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/s3/s3.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/s3/s3_connection.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/utilities/datetime_utility.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/utilities/dictionaroy_utility.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/utilities/file_operations.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/utilities/http_utility.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/utilities/logging_utility.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/utilities/numbers_utility.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/utilities/string_utility.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/__init__.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/dynamodb/__init__.py +0 -0
- {boto3_assist-0.6.0/tests/dynamodb/models → boto3_assist-0.6.1/tests/dynamodb/dbmodels}/cms/base.py +0 -0
- {boto3_assist-0.6.0/tests/dynamodb/models → boto3_assist-0.6.1/tests/dynamodb/dbmodels}/cms/content_block.py +0 -0
- {boto3_assist-0.6.0/tests/dynamodb/models → boto3_assist-0.6.1/tests/dynamodb/dbmodels}/cms/template.py +0 -0
- {boto3_assist-0.6.0/tests/dynamodb/models → boto3_assist-0.6.1/tests/dynamodb/dbmodels}/simple_model.py +0 -0
- {boto3_assist-0.6.0/tests/dynamodb/models → boto3_assist-0.6.1/tests/dynamodb/dbmodels}/user_model.py +0 -0
- {boto3_assist-0.6.0/tests/dynamodb/models → boto3_assist-0.6.1/tests/dynamodb/dbmodels}/user_required_fields_model.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/dynamodb/dynamodb_reindex_test.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/examples_test/__init__.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/examples_test/user_service_test.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/lambda/__init__.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/lambda/event_info_test.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/models/__init__.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/models/serializable_model_test.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/s3/__init__.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/s3/files/test.txt +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/s3/s3_file_upload_test.py +0 -0
- {boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/utilities/serialization_utility_test.py +0 -0
|
@@ -12,8 +12,7 @@
|
|
|
12
12
|
"python.analysis.extraPaths": [
|
|
13
13
|
"${workspaceFolder}",
|
|
14
14
|
"${workspaceFolder}/examples",
|
|
15
|
-
"${workspaceFolder}/src",
|
|
16
|
-
"${workspaceFolder}/src/boto3_assist",
|
|
15
|
+
"${workspaceFolder}/src",
|
|
17
16
|
"${workspaceFolder}/tests",
|
|
18
17
|
"${workspaceFolder}/devops",
|
|
19
18
|
"${workspaceFolder}/devops/cdk",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
python --version
|
|
4
|
+
python -m venv .unittest
|
|
5
|
+
source ./.unittest/bin/activate
|
|
6
|
+
which python
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
pip install --upgrade pip
|
|
10
|
+
pip install -r ./requirements.txt
|
|
11
|
+
pip install -r ./requirements-dev.txt
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
echo "running unit test"
|
|
15
|
+
python -m unittest discover -s tests -p "*_test.py"
|
|
16
|
+
|
|
17
|
+
if [ $? -eq 0 ]; then
|
|
18
|
+
echo "Tests passed successfully"
|
|
19
|
+
else
|
|
20
|
+
echo "No tests found or tests failed"
|
|
21
|
+
exit 1
|
|
22
|
+
fi
|
|
@@ -5,5 +5,5 @@ MIT License. See Project Root for the license information.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from boto3_assist.utilities.serialization_utility import SerializableModel
|
|
8
|
+
|
|
9
|
+
from boto3_assist.utilities.serialization_utility import SerializableModel # noqa: F401 # pylint: disable=unused-import
|
{boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/utilities/serialization_utility.py
RENAMED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
"""Serialization Utility"""
|
|
2
2
|
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from decimal import Decimal
|
|
5
|
-
from typing import Dict, List, TypeVar, Any
|
|
6
|
-
import json
|
|
7
|
-
import jsons
|
|
8
3
|
import datetime as dt
|
|
9
4
|
import decimal
|
|
10
5
|
import inspect
|
|
6
|
+
import json
|
|
11
7
|
import uuid
|
|
12
|
-
from
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from decimal import Decimal
|
|
10
|
+
from typing import Any, Dict, List, TypeVar
|
|
13
11
|
|
|
12
|
+
from aws_lambda_powertools import Logger
|
|
14
13
|
|
|
15
14
|
T = TypeVar("T")
|
|
16
15
|
|
|
@@ -53,6 +52,15 @@ class SerializableModel:
|
|
|
53
52
|
instance=self, serialize_fn=lambda x: x, include_none=True
|
|
54
53
|
)
|
|
55
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
|
+
|
|
56
64
|
|
|
57
65
|
class JsonEncoder(json.JSONEncoder):
|
|
58
66
|
"""
|
|
@@ -108,6 +116,32 @@ class Serialization:
|
|
|
108
116
|
|
|
109
117
|
return dump
|
|
110
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
|
|
144
|
+
|
|
111
145
|
@staticmethod
|
|
112
146
|
def map(source: object, target: T, coerce: bool = True) -> T | None:
|
|
113
147
|
"""Map an object from one object to another"""
|
|
@@ -118,12 +152,92 @@ class Serialization:
|
|
|
118
152
|
source_dict = Serialization.convert_object_to_dict(source)
|
|
119
153
|
if not isinstance(source_dict, dict):
|
|
120
154
|
return None
|
|
121
|
-
return Serialization.
|
|
155
|
+
return Serialization._load_properties(
|
|
122
156
|
source=source_dict, target=target, coerce=coerce
|
|
123
157
|
)
|
|
124
158
|
|
|
125
159
|
@staticmethod
|
|
126
|
-
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(
|
|
127
241
|
source: dict,
|
|
128
242
|
target: T,
|
|
129
243
|
coerce: bool = True,
|
|
@@ -183,9 +297,9 @@ class Serialization:
|
|
|
183
297
|
attr.clear()
|
|
184
298
|
attr.extend(value)
|
|
185
299
|
elif isinstance(attr, dict) and isinstance(value, dict):
|
|
186
|
-
Serialization.
|
|
300
|
+
Serialization._load_properties(value, attr, coerce=coerce)
|
|
187
301
|
elif hasattr(attr, "__dict__") and isinstance(value, dict):
|
|
188
|
-
Serialization.
|
|
302
|
+
Serialization._load_properties(value, attr, coerce=coerce)
|
|
189
303
|
else:
|
|
190
304
|
setattr(target, key, value)
|
|
191
305
|
except ValueError as e:
|
|
@@ -230,12 +344,18 @@ class Serialization:
|
|
|
230
344
|
|
|
231
345
|
@staticmethod
|
|
232
346
|
def to_dict(
|
|
233
|
-
instance: SerializableModel,
|
|
347
|
+
instance: SerializableModel | dict,
|
|
234
348
|
serialize_fn,
|
|
235
349
|
include_none: bool = True,
|
|
236
350
|
) -> Dict[str, Any]:
|
|
237
351
|
"""To Dict / Dictionary"""
|
|
238
352
|
|
|
353
|
+
if instance is None:
|
|
354
|
+
return {}
|
|
355
|
+
|
|
356
|
+
if isinstance(instance, dict):
|
|
357
|
+
return instance
|
|
358
|
+
|
|
239
359
|
def is_primitive(value):
|
|
240
360
|
"""Check if the value is a primitive data type."""
|
|
241
361
|
return isinstance(value, (str, int, bool, type(None)))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.6.1'
|
|
@@ -9,8 +9,11 @@ import sys
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
|
|
11
11
|
## needed for discovery based top level execution
|
|
12
|
+
print("👋 init test paths for __top")
|
|
12
13
|
root_directory = Path(__file__).resolve().parent.parent.parent
|
|
13
14
|
src_directory = os.path.join(root_directory, "src")
|
|
14
15
|
|
|
15
16
|
sys.path.insert(0, src_directory)
|
|
16
|
-
print(
|
|
17
|
+
print("")
|
|
18
|
+
for p in sys.path:
|
|
19
|
+
print(f"👉 {p}")
|
{boto3_assist-0.6.0/tests/dynamodb/models → boto3_assist-0.6.1/tests/dynamodb/dbmodels}/cms/page.py
RENAMED
|
@@ -7,7 +7,7 @@ MIT License. See Project Root for the license information.
|
|
|
7
7
|
from typing import List, Dict, Any
|
|
8
8
|
import datetime as dt
|
|
9
9
|
from boto3_assist.dynamodb.dynamodb_index import DynamoDBIndex, DynamoDBKey
|
|
10
|
-
from tests.dynamodb.
|
|
10
|
+
from tests.dynamodb.dbmodels.cms.base import BaseCMSDBModel
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class Page(BaseCMSDBModel):
|
|
@@ -5,12 +5,11 @@ MIT License. See Project Root for the license information.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import unittest
|
|
8
|
-
from typing import
|
|
9
|
-
|
|
8
|
+
from typing import Dict, List
|
|
10
9
|
|
|
11
10
|
from boto3_assist.dynamodb.dynamodb_index import DynamoDBIndex
|
|
12
|
-
from
|
|
13
|
-
from tests.dynamodb.
|
|
11
|
+
from boto3_assist.dynamodb.dynamodb_key import DynamoDBKey
|
|
12
|
+
from tests.dynamodb.dbmodels.user_model import User
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
class DynamoDBModelUnitTest(unittest.TestCase):
|
|
@@ -7,8 +7,8 @@ MIT License. See Project Root for the license information.
|
|
|
7
7
|
import unittest
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
from tests.dynamodb.
|
|
11
|
-
from tests.dynamodb.
|
|
10
|
+
from tests.dynamodb.dbmodels.user_model import User
|
|
11
|
+
from tests.dynamodb.dbmodels.simple_model import Simple
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class DynamoDBModeProjectionlUnitTest(unittest.TestCase):
|
{boto3_assist-0.6.0 → boto3_assist-0.6.1}/tests/dynamodb/dynamodb_model_serializtion_test.py
RENAMED
|
@@ -7,8 +7,8 @@ MIT License. See Project Root for the license information.
|
|
|
7
7
|
import unittest
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
from tests.dynamodb.
|
|
11
|
-
from tests.dynamodb.
|
|
10
|
+
from tests.dynamodb.dbmodels.user_model import User
|
|
11
|
+
from tests.dynamodb.dbmodels.user_required_fields_model import User as User2
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class DynamoDBModelSerializationUnitTest(unittest.TestCase):
|
|
@@ -4,17 +4,15 @@ Maintainers: Eric Wilson
|
|
|
4
4
|
MIT License. See Project Root for the license information.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import os
|
|
8
7
|
import unittest
|
|
9
|
-
import moto
|
|
10
8
|
from typing import List
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
import moto
|
|
13
11
|
from mypy_boto3_dynamodb import DynamoDBClient
|
|
14
12
|
|
|
15
|
-
from dynamodb.models.cms.page import Page
|
|
16
|
-
from boto3_assist.environment_services.environment_loader import EnvironmentLoader
|
|
17
13
|
from boto3_assist.dynamodb.dynamodb import DynamoDB
|
|
14
|
+
from boto3_assist.environment_services.environment_loader import EnvironmentLoader
|
|
15
|
+
from tests.dynamodb.dbmodels.cms.page import Page
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
@moto.mock_aws
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Geek Cafe, LLC
|
|
3
|
+
Maintainers: Eric Wilson
|
|
4
|
+
MIT License. See Project Root for the license information.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import unittest
|
|
8
|
+
|
|
9
|
+
from boto3_assist.models.serializable_model import SerializableModel
|
|
10
|
+
from boto3_assist.utilities.serialization_utility import Serialization
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Address(SerializableModel):
|
|
14
|
+
"""A model that inherits the serializable"""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
*,
|
|
19
|
+
id: str | None = None, # pylint: disable=redefined-builtin
|
|
20
|
+
street: str | None = None,
|
|
21
|
+
city: str | None = None,
|
|
22
|
+
state: str | None = None,
|
|
23
|
+
zip: str | None = None, # pylint: disable=redefined-builtin
|
|
24
|
+
):
|
|
25
|
+
self.id: str | None = id
|
|
26
|
+
self.street: str | None = street
|
|
27
|
+
self.city: str | None = city
|
|
28
|
+
self.state: str | None = state
|
|
29
|
+
self.zip: str | None = zip
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class User(SerializableModel):
|
|
33
|
+
"""A model that inherits the serializable"""
|
|
34
|
+
|
|
35
|
+
def __init__(self):
|
|
36
|
+
self.__id: str | None = None
|
|
37
|
+
self.first_name: str = ""
|
|
38
|
+
self.last_name: str = ""
|
|
39
|
+
self.addresses: list[Address] = []
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def id(self) -> str:
|
|
43
|
+
"""The id of the order"""
|
|
44
|
+
return self.__id
|
|
45
|
+
|
|
46
|
+
@id.setter
|
|
47
|
+
def id(self, value: str) -> None:
|
|
48
|
+
self.__id = value
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class TestSerializableModel(unittest.TestCase):
|
|
52
|
+
"""Testing Serialzing Models"""
|
|
53
|
+
|
|
54
|
+
def setUp(self) -> None:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
def test_map_valid_data(self):
|
|
58
|
+
"""
|
|
59
|
+
Test mapping a valid dictionary to an object instance.
|
|
60
|
+
"""
|
|
61
|
+
user: User = User()
|
|
62
|
+
user.id = "1"
|
|
63
|
+
user.first_name = "John"
|
|
64
|
+
user.last_name = "Smith"
|
|
65
|
+
for i in range(3):
|
|
66
|
+
user.addresses.append(
|
|
67
|
+
Address(
|
|
68
|
+
id=str(i),
|
|
69
|
+
street=f"10{i} S. Main St.",
|
|
70
|
+
city="Anytown",
|
|
71
|
+
state="AnyWhere",
|
|
72
|
+
zip="00001",
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
flat = user.to_wide_dictionary()
|
|
77
|
+
|
|
78
|
+
self.assertIsNotNone(flat)
|
|
79
|
+
self.assertEqual(flat["id"], "1")
|
|
80
|
+
self.assertEqual(flat["first_name"], "John")
|
|
81
|
+
self.assertEqual(flat["last_name"], "Smith")
|
|
82
|
+
self.assertEqual(flat["addresses_0_id"], "0")
|
|
83
|
+
self.assertEqual(flat["addresses_0_street"], "100 S. Main St.")
|
|
84
|
+
self.assertEqual(flat["addresses_0_city"], "Anytown")
|
|
85
|
+
self.assertEqual(flat["addresses_0_state"], "AnyWhere")
|
|
86
|
+
self.assertEqual(flat["addresses_0_zip"], "00001")
|
|
87
|
+
|
|
88
|
+
def test_dict_wide(self):
|
|
89
|
+
model = {
|
|
90
|
+
"id": "1",
|
|
91
|
+
"first_name": "John",
|
|
92
|
+
"last_name": "Smith",
|
|
93
|
+
"addresses": [
|
|
94
|
+
{
|
|
95
|
+
"id": "0",
|
|
96
|
+
"street": "100 S. Main St.",
|
|
97
|
+
"city": "Anytown",
|
|
98
|
+
"state": "AnyWhere",
|
|
99
|
+
"zip": "00001",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "1",
|
|
103
|
+
"street": "101 S. Main St.",
|
|
104
|
+
"city": "Anytown",
|
|
105
|
+
"state": "AnyWhere",
|
|
106
|
+
"zip": "00001",
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
flat = Serialization.to_wide_dictionary(model)
|
|
112
|
+
|
|
113
|
+
self.assertIsNotNone(flat)
|
|
114
|
+
self.assertEqual(flat["id"], "1")
|
|
115
|
+
self.assertEqual(flat["first_name"], "John")
|
|
116
|
+
self.assertEqual(flat["last_name"], "Smith")
|
|
117
|
+
self.assertEqual(flat["addresses_0_id"], "0")
|
|
118
|
+
self.assertEqual(flat["addresses_0_street"], "100 S. Main St.")
|
|
119
|
+
self.assertEqual(flat["addresses_0_city"], "Anytown")
|
|
120
|
+
self.assertEqual(flat["addresses_0_state"], "AnyWhere")
|
|
121
|
+
self.assertEqual(flat["addresses_0_zip"], "00001")
|
|
122
|
+
|
|
123
|
+
def test_dict_multi_level_array(self):
|
|
124
|
+
model = {
|
|
125
|
+
"id": "1",
|
|
126
|
+
"level_one_array": [
|
|
127
|
+
{
|
|
128
|
+
"id": "1",
|
|
129
|
+
"level_two_array": [
|
|
130
|
+
{
|
|
131
|
+
"id": "1",
|
|
132
|
+
"level_three_array": [
|
|
133
|
+
{
|
|
134
|
+
"id": "1",
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
flat = Serialization.to_wide_dictionary(model)
|
|
144
|
+
|
|
145
|
+
self.assertIsNotNone(flat)
|
|
146
|
+
self.assertEqual(flat["id"], "1")
|
|
147
|
+
self.assertEqual(flat["level_one_array_0_id"], "1")
|
|
148
|
+
self.assertEqual(flat["level_one_array_0_level_two_array_0_id"], "1")
|
|
149
|
+
self.assertEqual(
|
|
150
|
+
flat["level_one_array_0_level_two_array_0_level_three_array_0_id"], "1"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def test_dict_wide_list_happy_path(self):
|
|
154
|
+
model = {
|
|
155
|
+
"first_name": "John",
|
|
156
|
+
"last_name": "Smith",
|
|
157
|
+
"addresses": [
|
|
158
|
+
{
|
|
159
|
+
"street": "100 S. Main St.",
|
|
160
|
+
"city": "Anytown",
|
|
161
|
+
"state": "AnyWhere",
|
|
162
|
+
"zip": "00001",
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"street": "101 S. Main St.",
|
|
166
|
+
"city": "Anytown",
|
|
167
|
+
"state": "AnyWhere",
|
|
168
|
+
"zip": "00001",
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
expected_results = [
|
|
174
|
+
{
|
|
175
|
+
"first_name": "John",
|
|
176
|
+
"last_name": "Smith",
|
|
177
|
+
"street": "100 S. Main St.",
|
|
178
|
+
"city": "Anytown",
|
|
179
|
+
"state": "AnyWhere",
|
|
180
|
+
"zip": "00001",
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"first_name": "John",
|
|
184
|
+
"last_name": "Smith",
|
|
185
|
+
"street": "101 S. Main St.",
|
|
186
|
+
"city": "Anytown",
|
|
187
|
+
"state": "AnyWhere",
|
|
188
|
+
"zip": "00001",
|
|
189
|
+
},
|
|
190
|
+
]
|
|
191
|
+
|
|
192
|
+
flat = Serialization.to_wide_dictionary_list(model)
|
|
193
|
+
|
|
194
|
+
self.assertIsNotNone(flat)
|
|
195
|
+
self.assertEqual(flat, expected_results)
|
|
196
|
+
|
|
197
|
+
def test_dict_wide_list_duplicate_keys(self):
|
|
198
|
+
model = {
|
|
199
|
+
"id": "1",
|
|
200
|
+
"first_name": "John",
|
|
201
|
+
"last_name": "Smith",
|
|
202
|
+
"addresses": [
|
|
203
|
+
{
|
|
204
|
+
"id": "a",
|
|
205
|
+
"street": "100 S. Main St.",
|
|
206
|
+
"city": "Anytown",
|
|
207
|
+
"state": "AnyWhere",
|
|
208
|
+
"zip": "00001",
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"id": "b",
|
|
212
|
+
"street": "101 S. Main St.",
|
|
213
|
+
"city": "Anytown",
|
|
214
|
+
"state": "AnyWhere",
|
|
215
|
+
"zip": "00001",
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
expected_results = [
|
|
221
|
+
{
|
|
222
|
+
"first_name": "John",
|
|
223
|
+
"last_name": "Smith",
|
|
224
|
+
"street": "100 S. Main St.",
|
|
225
|
+
"city": "Anytown",
|
|
226
|
+
"state": "AnyWhere",
|
|
227
|
+
"zip": "00001",
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"first_name": "John",
|
|
231
|
+
"last_name": "Smith",
|
|
232
|
+
"street": "101 S. Main St.",
|
|
233
|
+
"city": "Anytown",
|
|
234
|
+
"state": "AnyWhere",
|
|
235
|
+
"zip": "00001",
|
|
236
|
+
},
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
flat = Serialization.to_wide_dictionary_list(model)
|
|
240
|
+
|
|
241
|
+
self.assertIsNotNone(flat)
|
|
242
|
+
self.assertEqual(flat, expected_results)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
if __name__ == "__main__":
|
|
246
|
+
unittest.main()
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.6.0'
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Geek Cafe, LLC
|
|
3
|
-
Maintainers: Eric Wilson
|
|
4
|
-
MIT License. See Project Root for the license information.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import os
|
|
8
|
-
import sys
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
|
|
11
|
-
## needed for discovery based top level execution
|
|
12
|
-
root_directory = Path(__file__).resolve().parent.parent.parent
|
|
13
|
-
src_directory = os.path.join(root_directory, "src")
|
|
14
|
-
|
|
15
|
-
sys.path.insert(0, src_directory)
|
|
16
|
-
print(sys.path)
|
|
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.6.0 → boto3_assist-0.6.1}/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.6.0 → boto3_assist-0.6.1}/src/boto3_assist/cloudwatch/cloudwatch_connection.py
RENAMED
|
File without changes
|
|
File without changes
|
{boto3_assist-0.6.0 → boto3_assist-0.6.1}/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
|
|
File without changes
|
{boto3_assist-0.6.0 → boto3_assist-0.6.1}/src/boto3_assist/dynamodb/dynamodb_reserved_words.py
RENAMED
|
File without changes
|
{boto3_assist-0.6.0 → boto3_assist-0.6.1}/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
|
{boto3_assist-0.6.0/tests/dynamodb/models → boto3_assist-0.6.1/tests/dynamodb/dbmodels}/cms/base.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
|