boto3-assist 0.6.0__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.
@@ -5,5 +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 SerializableModel
8
+
9
+ from boto3_assist.utilities.serialization_utility import SerializableModel # noqa: F401 # pylint: disable=unused-import
@@ -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 aws_lambda_powertools import Logger
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.load_properties(
155
+ return Serialization._load_properties(
122
156
  source=source_dict, target=target, coerce=coerce
123
157
  )
124
158
 
125
159
  @staticmethod
126
- def load_properties(
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.load_properties(value, attr, coerce=coerce)
300
+ Serialization._load_properties(value, attr, coerce=coerce)
187
301
  elif hasattr(attr, "__dict__") and isinstance(value, dict):
188
- Serialization.load_properties(value, attr, coerce=coerce)
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)))
boto3_assist/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.6.0'
1
+ __version__ = '0.6.1'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boto3_assist
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: Additional boto3 wrappers to make your life a little easier
5
5
  Author-email: Eric Wilson <boto3-assist@geekcafe.com>
6
6
  License-File: LICENSE-EXPLAINED.txt
@@ -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=CBY3jsC-9HCm7eZ6CKD-sYLCejqOJ1pYWPQM4LGIXcI,22
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
@@ -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=nzGdkggAzmrIukPPyumB9EPUNrPfvQrCqbTSndnwT1c,257
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=fj5FDQjA7pC_mhX22n0N1UwRXl7S__q0VrisQTc0GHg,12415
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.6.0.dist-info/METADATA,sha256=DFeAHlHVbA3lVP2ZKQPfSc9y8pvUWleUq8G649h8iy4,1728
49
- boto3_assist-0.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
50
- boto3_assist-0.6.0.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
51
- boto3_assist-0.6.0.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
52
- boto3_assist-0.6.0.dist-info/RECORD,,
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,,