boto3-assist 0.32.0__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.
Files changed (67) hide show
  1. boto3_assist/__init__.py +0 -0
  2. boto3_assist/aws_config.py +199 -0
  3. boto3_assist/aws_lambda/event_info.py +414 -0
  4. boto3_assist/aws_lambda/mock_context.py +5 -0
  5. boto3_assist/boto3session.py +87 -0
  6. boto3_assist/cloudwatch/cloudwatch_connection.py +84 -0
  7. boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +17 -0
  8. boto3_assist/cloudwatch/cloudwatch_log_connection.py +62 -0
  9. boto3_assist/cloudwatch/cloudwatch_logs.py +39 -0
  10. boto3_assist/cloudwatch/cloudwatch_query.py +191 -0
  11. boto3_assist/cognito/cognito_authorizer.py +169 -0
  12. boto3_assist/cognito/cognito_connection.py +59 -0
  13. boto3_assist/cognito/cognito_utility.py +514 -0
  14. boto3_assist/cognito/jwks_cache.py +21 -0
  15. boto3_assist/cognito/user.py +27 -0
  16. boto3_assist/connection.py +146 -0
  17. boto3_assist/connection_tracker.py +120 -0
  18. boto3_assist/dynamodb/dynamodb.py +1206 -0
  19. boto3_assist/dynamodb/dynamodb_connection.py +113 -0
  20. boto3_assist/dynamodb/dynamodb_helpers.py +333 -0
  21. boto3_assist/dynamodb/dynamodb_importer.py +102 -0
  22. boto3_assist/dynamodb/dynamodb_index.py +507 -0
  23. boto3_assist/dynamodb/dynamodb_iservice.py +29 -0
  24. boto3_assist/dynamodb/dynamodb_key.py +130 -0
  25. boto3_assist/dynamodb/dynamodb_model_base.py +382 -0
  26. boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +34 -0
  27. boto3_assist/dynamodb/dynamodb_re_indexer.py +165 -0
  28. boto3_assist/dynamodb/dynamodb_reindexer.py +165 -0
  29. boto3_assist/dynamodb/dynamodb_reserved_words.py +52 -0
  30. boto3_assist/dynamodb/dynamodb_reserved_words.txt +573 -0
  31. boto3_assist/dynamodb/readme.md +68 -0
  32. boto3_assist/dynamodb/troubleshooting.md +7 -0
  33. boto3_assist/ec2/ec2_connection.py +57 -0
  34. boto3_assist/environment_services/__init__.py +0 -0
  35. boto3_assist/environment_services/environment_loader.py +128 -0
  36. boto3_assist/environment_services/environment_variables.py +219 -0
  37. boto3_assist/erc/__init__.py +64 -0
  38. boto3_assist/erc/ecr_connection.py +57 -0
  39. boto3_assist/errors/custom_exceptions.py +46 -0
  40. boto3_assist/http_status_codes.py +80 -0
  41. boto3_assist/models/serializable_model.py +9 -0
  42. boto3_assist/role_assumption_mixin.py +38 -0
  43. boto3_assist/s3/s3.py +64 -0
  44. boto3_assist/s3/s3_bucket.py +67 -0
  45. boto3_assist/s3/s3_connection.py +76 -0
  46. boto3_assist/s3/s3_event_data.py +168 -0
  47. boto3_assist/s3/s3_object.py +695 -0
  48. boto3_assist/securityhub/securityhub.py +150 -0
  49. boto3_assist/securityhub/securityhub_connection.py +57 -0
  50. boto3_assist/session_setup_mixin.py +70 -0
  51. boto3_assist/ssm/connection.py +57 -0
  52. boto3_assist/ssm/parameter_store/parameter_store.py +116 -0
  53. boto3_assist/utilities/datetime_utility.py +349 -0
  54. boto3_assist/utilities/decimal_conversion_utility.py +140 -0
  55. boto3_assist/utilities/dictionary_utility.py +32 -0
  56. boto3_assist/utilities/file_operations.py +135 -0
  57. boto3_assist/utilities/http_utility.py +48 -0
  58. boto3_assist/utilities/logging_utility.py +0 -0
  59. boto3_assist/utilities/numbers_utility.py +329 -0
  60. boto3_assist/utilities/serialization_utility.py +664 -0
  61. boto3_assist/utilities/string_utility.py +337 -0
  62. boto3_assist/version.py +1 -0
  63. boto3_assist-0.32.0.dist-info/METADATA +76 -0
  64. boto3_assist-0.32.0.dist-info/RECORD +67 -0
  65. boto3_assist-0.32.0.dist-info/WHEEL +4 -0
  66. boto3_assist-0.32.0.dist-info/licenses/LICENSE-EXPLAINED.txt +11 -0
  67. boto3_assist-0.32.0.dist-info/licenses/LICENSE.txt +21 -0
@@ -0,0 +1,337 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ import hashlib
8
+ import secrets
9
+ import string
10
+ import time
11
+ from datetime import datetime
12
+ from decimal import Decimal
13
+ import uuid
14
+ import json
15
+ import re
16
+ from aws_lambda_powertools import Logger
17
+ from boto3_assist.utilities.datetime_utility import DatetimeUtility
18
+
19
+ logger = Logger()
20
+
21
+
22
+ class JsonEncoder(json.JSONEncoder):
23
+ """
24
+ This class is used to serialize python generics which implement a __json_encode__ method
25
+ and where the recipient does not require type hinting for deserialization.
26
+ If type hinting is required, use GenericJsonEncoder
27
+ """
28
+
29
+ def default(self, o):
30
+ # First, check if the object has a custom encoding method
31
+ if hasattr(o, "__json_encode__"):
32
+ return o.__json_encode__()
33
+
34
+ # check for dictionary
35
+ if hasattr(o, "__dict__"):
36
+ return {k: v for k, v in o.__dict__.items() if not k.startswith("_")}
37
+
38
+ # Handling datetime.datetime objects specifically
39
+ elif isinstance(o, datetime):
40
+ return o.isoformat()
41
+ # handle decimal wrappers
42
+ elif isinstance(o, Decimal):
43
+ return float(o)
44
+
45
+ logger.info(f"JsonEncoder failing back: ${type(o)}")
46
+
47
+ # Fallback to the base class implementation for other types
48
+
49
+ try:
50
+ return super().default(o)
51
+ except TypeError:
52
+ # If an object does not have a __dict__ attribute, you might want to handle it differently.
53
+ # For example, you could choose to return str(o) or implement other specific cases.
54
+ return str(
55
+ o
56
+ ) # Or any other way you wish to serialize objects without __dict__
57
+
58
+
59
+ class StringUtility:
60
+ """String Utilities"""
61
+
62
+ SPECIAL_CHARACTERS = "!\\#$%&()*+,-.:;<=>?@[]^_{|}~"
63
+
64
+ @staticmethod
65
+ def generate_random_string(
66
+ length=12, digits=True, letters=True, special=False
67
+ ) -> str:
68
+ """
69
+ Generate a random string with specified options.
70
+
71
+ Args:
72
+ length (int, optional): The length of the generated string. Defaults to 12.
73
+ digits (bool, optional): Include digits in the string. Defaults to True.
74
+ letters (bool, optional): Include letters in the string. Defaults to True.
75
+ special (bool, optional): Include special characters in the string. Defaults to False.
76
+
77
+ Returns:
78
+ str: The generated random string.
79
+ """
80
+ characters = ""
81
+ if letters:
82
+ characters += string.ascii_letters
83
+ if digits:
84
+ characters += string.digits
85
+ if special:
86
+ characters += StringUtility.SPECIAL_CHARACTERS
87
+
88
+ random_string = "".join(secrets.choice(characters) for _ in range(length))
89
+ return random_string
90
+
91
+ @staticmethod
92
+ def generate_random_password(
93
+ length=15, digits=True, letters=True, special=True
94
+ ) -> str:
95
+ """
96
+ Generate a random password with specified options ensuring a minimum length of 8.
97
+
98
+ Args:
99
+ length (int, optional): The length of the generated password. Defaults to 15.
100
+ digits (bool, optional): Include digits in the password. Defaults to True.
101
+ letters (bool, optional): Include letters in the password. Defaults to True.
102
+ special (bool, optional): Include special characters in the password. Defaults to True.
103
+
104
+ Raises:
105
+ RuntimeError: If no character sets are selected.
106
+
107
+ Returns:
108
+ str: The generated random password.
109
+ """
110
+ characters = ""
111
+ if length < 8:
112
+ length = 8
113
+
114
+ if letters:
115
+ characters += string.ascii_letters
116
+ if digits:
117
+ characters += string.digits
118
+ if special:
119
+ characters += StringUtility.SPECIAL_CHARACTERS
120
+
121
+ if len(characters) == 0:
122
+ raise RuntimeError(
123
+ "You must choose at least one of the options: digits, letters, special"
124
+ )
125
+
126
+ password = []
127
+ if letters:
128
+ password.append(secrets.choice(string.ascii_lowercase))
129
+ password.append(secrets.choice(string.ascii_lowercase))
130
+ password.append(secrets.choice(string.ascii_uppercase))
131
+ password.append(secrets.choice(string.ascii_uppercase))
132
+ if digits:
133
+ password.append(secrets.choice(string.digits))
134
+ password.append(secrets.choice(string.digits))
135
+ if special:
136
+ password.append(secrets.choice(StringUtility.SPECIAL_CHARACTERS))
137
+ password.append(secrets.choice(StringUtility.SPECIAL_CHARACTERS))
138
+
139
+ remaining_length = length - len(password)
140
+ password.extend(secrets.choice(characters) for _ in range(remaining_length))
141
+
142
+ secrets.SystemRandom().shuffle(password)
143
+
144
+ return "".join(password)
145
+
146
+ @staticmethod
147
+ def wrap_text(text: str, max_width: int) -> str:
148
+ """
149
+ Wrap text to a specified maximum width.
150
+
151
+ Args:
152
+ text (str): The text to wrap.
153
+ max_width (int): The maximum width of each line.
154
+
155
+ Returns:
156
+ str: The wrapped text.
157
+ """
158
+ wrapped_text = ""
159
+ if not text:
160
+ return text
161
+
162
+ while len(text) > max_width:
163
+ break_point = (
164
+ text.rfind(" ", 0, max_width) if " " in text[0:max_width] else max_width
165
+ )
166
+ if break_point == -1:
167
+ break_point = max_width
168
+ wrapped_text += text[:break_point] + "\n"
169
+ text = text[break_point:].lstrip()
170
+ wrapped_text += text
171
+ return wrapped_text
172
+
173
+ @staticmethod
174
+ def generate_uuid() -> str:
175
+ """
176
+ Generate a random UUID.
177
+
178
+ Returns:
179
+ str: The generated UUID as a string.
180
+ """
181
+ return str(uuid.uuid4())
182
+
183
+ @staticmethod
184
+ def generate_hash(input_string: str) -> str:
185
+ """
186
+ Generate a SHA-256 hash for the given input string.
187
+
188
+ Args:
189
+ input_string (str): The string to hash.
190
+
191
+ Returns:
192
+ str: The resulting hash value as a hexadecimal string.
193
+ """
194
+ encoded_string = input_string.encode()
195
+ hash_object = hashlib.sha256()
196
+ hash_object.update(encoded_string)
197
+ return hash_object.hexdigest()
198
+
199
+ @staticmethod
200
+ def generate_idempotent_uuid(
201
+ namespace: uuid.UUID | str, unique_string: str, case_sensitive: bool = False
202
+ ) -> str:
203
+ """
204
+ Generates an idempotent UUID, which is useful for creates
205
+
206
+ Args:
207
+ namespace (GUID | str): A namespace for your id, it must be a UUID or a string in a UUID format
208
+ unique_string (str): A unique string like an email address, a tenant name.
209
+ Use a combination for more granularity:
210
+ tenant-name:email
211
+ vendor:product-name
212
+ vendor:product-id
213
+ etc
214
+
215
+ Returns:
216
+ str: a string representation of a UUID
217
+ """
218
+ if isinstance(namespace, str):
219
+ namespace = uuid.UUID(namespace)
220
+
221
+ if not unique_string:
222
+ raise ValueError("unique_string cannot be empty")
223
+
224
+ if not case_sensitive:
225
+ unique_string = unique_string.lower()
226
+
227
+ return str(uuid.uuid5(namespace, unique_string))
228
+
229
+ @staticmethod
230
+ def get_size_in_kb(input_string: str | dict) -> float:
231
+ """
232
+ Get the size of the input string in kilobytes.
233
+
234
+ Args:
235
+ input_string (str): The input string.
236
+
237
+ Returns:
238
+ int: The size of the input string in kilobytes.
239
+ """
240
+ size_in_bytes = StringUtility.get_size_in_bytes(input_string)
241
+
242
+ size = size_in_bytes / 1024
243
+
244
+ return size
245
+
246
+ @staticmethod
247
+ def get_size_in_bytes(input_string: str | dict) -> int:
248
+ """
249
+ Get the size of the input string in kilobytes.
250
+
251
+ Args:
252
+ input_string (str): The input string.
253
+
254
+ Returns:
255
+ int: The size of the input string in kilobytes.
256
+ """
257
+ if isinstance(input_string, dict):
258
+ input_string = json.dumps(input_string, cls=JsonEncoder)
259
+ # encodes the string to bytes, which is necessary because the length of a string
260
+ # can differ from the length of its byte representation,
261
+ # especially for non-ASCII characters.
262
+ _bytes: bytes = input_string.encode("utf-8")
263
+ size = int(len(_bytes))
264
+
265
+ return size
266
+
267
+ @staticmethod
268
+ def generate_sortable_uuid():
269
+ """
270
+ Generates a unique id for the execution event
271
+ """
272
+ epoch_time = time.time()
273
+ sortable_uuid: uuid.UUID = DatetimeUtility.uuid1_utc(timestamp=epoch_time)
274
+
275
+ time_stamp = str(epoch_time).replace(".", "-")
276
+ sortable_id = f"{time_stamp}:{str(sortable_uuid)}"
277
+ return sortable_id
278
+
279
+ @staticmethod
280
+ def to_bool(value: str | bool | int | None) -> bool:
281
+ """
282
+ Converts a string or boolean value to a boolean.
283
+
284
+ Args:
285
+ value (str | bool | int | None): The value to convert.
286
+
287
+ Returns:
288
+ bool: The converted boolean value.
289
+
290
+ Raises:
291
+ ValueError: If the input value is not a valid boolean or string representation.
292
+ """
293
+ return StringUtility.to_boolean(value)
294
+
295
+ @staticmethod
296
+ def to_boolean(value: str | bool | int | None) -> bool:
297
+ """
298
+ Converts a string or boolean value to a boolean.
299
+
300
+ Args:
301
+ value (str | bool | int | None): The value to convert.
302
+
303
+ Returns:
304
+ bool: The converted boolean value.
305
+
306
+ Raises:
307
+ ValueError: If the input value is not a valid boolean or string representation.
308
+ """
309
+ if isinstance(value, bool):
310
+ return value
311
+ if isinstance(value, str):
312
+ value = str(value).lower().strip()
313
+ if value in ("true", "1", "t", "y", "yes"):
314
+ return True
315
+ if value in ("false", "0", "f", "n", "no"):
316
+ return False
317
+ raise ValueError(f"Invalid boolean value: {value}")
318
+ elif isinstance(value, int):
319
+ return bool(value)
320
+ elif value is None:
321
+ return False
322
+ else:
323
+ raise ValueError(f"Invalid boolean value: {value}")
324
+
325
+ @staticmethod
326
+ def camel_to_snake(value: str) -> str:
327
+ """Converts a camelCase to a snake_case"""
328
+ # Insert underscores before uppercase letters, then convert to lowercase.
329
+ s1 = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", value)
330
+ return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s1).lower()
331
+
332
+ @staticmethod
333
+ def snake_to_camel(value: str) -> str:
334
+ """Converts a value from snake_case to camelCase"""
335
+ # Split the value by underscores and capitalize each component except the first.
336
+ components = value.split("_")
337
+ return components[0] + "".join(x.title() for x in components[1:])
@@ -0,0 +1 @@
1
+ __version__ = "0.32.0"
@@ -0,0 +1,76 @@
1
+ Metadata-Version: 2.4
2
+ Name: boto3_assist
3
+ Version: 0.32.0
4
+ Summary: Additional boto3 wrappers to make your life a little easier
5
+ Author-email: Eric Wilson <boto3-assist@geekcafe.com>
6
+ License-File: LICENSE-EXPLAINED.txt
7
+ License-File: LICENSE.txt
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Software Development
14
+ Requires-Python: >=3.10
15
+ Requires-Dist: aws-lambda-powertools
16
+ Requires-Dist: aws-xray-sdk
17
+ Requires-Dist: boto3
18
+ Requires-Dist: jsons
19
+ Requires-Dist: pyjwt
20
+ Requires-Dist: python-dateutil
21
+ Requires-Dist: python-dotenv
22
+ Requires-Dist: pytz
23
+ Requires-Dist: requests
24
+ Requires-Dist: types-python-dateutil
25
+ Description-Content-Type: text/markdown
26
+
27
+ # boto3 assist
28
+
29
+ [![PyPI version](https://img.shields.io/pypi/v/boto3-assist.svg)](https://pypi.org/project/boto3-assist/)
30
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
31
+ [![Downloads](https://static.pepy.tech/badge/boto3-assist)](https://pepy.tech/project/boto3-assist)
32
+
33
+ This is in beta and subject to changes before it's initial 1.0.0 release
34
+
35
+ This library was created to make life a little easier when using boto3.
36
+
37
+ Currently it supports:
38
+ - User Authentication / Session Mapping
39
+ - DynamoDB model mapping and key generation.
40
+
41
+
42
+ ## User Authentication / Session Mapping
43
+ Have you ever needed an easy way to load your sessions for a local, dev or production environment? Well this library
44
+ makes it a little easier by lazy loading your boto3 session so that tools like `python-dotenv` can be used to load your
45
+ environment vars first and then load your session.
46
+
47
+ ## DynamoDB model mapping and Key Generation
48
+ It's a light weight mapping tool to turn your python classes / object models to DynamoDB items that are ready
49
+ for saving. See the [examples](https://github.com/geekcafe/boto3-assist/tree/main/examples) directory in the repo for more information.
50
+
51
+
52
+ ```sh
53
+ python -m vevn .venv
54
+ source ./.venv/bin/activate
55
+
56
+ pip install --upgrade pip
57
+ pip install boto3-assist
58
+
59
+ ```
60
+
61
+ ## Running Unit Tests
62
+ Several of our tests use a mocking library to simulate connections to S3, DynamoDB, etc. In order to use those tests, you will need to have a `.env.unittest` file at the root of this project (which our tests will attempt to locate and load).
63
+
64
+ For your convenience the `.evn.unittest` file has been added to this project. The values should not point to live AWS profiles, instead it should use the values added.
65
+
66
+ Since we also point to a profile, you should create the profile in the `~/.aws/config` file. The entry should look like the following:
67
+
68
+ ```toml
69
+ [profile moto-mock-tests]
70
+ region = us-east-1
71
+ output = json
72
+ aws_access_key_id = test
73
+ aws_secret_access_key = test
74
+
75
+ ```
76
+
@@ -0,0 +1,67 @@
1
+ boto3_assist/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ boto3_assist/aws_config.py,sha256=evmk_blj498ugptJa8lxIDJOIursxY6mT4joLfEbrl0,6558
3
+ boto3_assist/boto3session.py,sha256=p4FKVSX5A-xNHdpRan8pgMoY4iIywNfwriyTfjQ-zTQ,2967
4
+ boto3_assist/connection.py,sha256=tqsNGLouAzCiTdtm9JylDTA6IiYqaQQiHmY-kH2bksU,4905
5
+ boto3_assist/connection_tracker.py,sha256=UgfR9RlvXf3A4ssMr3gDMpw89ka8mSRvJn4M34SzhbU,4378
6
+ boto3_assist/http_status_codes.py,sha256=G0zRSWenwavYKETvDF9tNVUXQz3Ae2gXdBETYbjvJe8,3284
7
+ boto3_assist/role_assumption_mixin.py,sha256=PMUU5yC2FUBjFD1UokVkRY3CPB5zTw85AhIB5BMtbc8,1031
8
+ boto3_assist/session_setup_mixin.py,sha256=X-JQKyyaWNA8Z8kKgf2V2I5vsiLAH8udLTX_xepnsdQ,3140
9
+ boto3_assist/version.py,sha256=s1FApnNsg-mmWP3shY6ep6EAjZrNFXHlyBXWcP2KV6Q,23
10
+ boto3_assist/aws_lambda/event_info.py,sha256=OkZ4WzuGaHEu_T8sB188KBgShAJhZpWASALKRGBOhMg,14648
11
+ boto3_assist/aws_lambda/mock_context.py,sha256=LPjHP-3YSoY6iPl1kPqJDwSVf1zLNTcukUunDtYcbK0,116
12
+ boto3_assist/cloudwatch/cloudwatch_connection.py,sha256=mnGWaLSQpHh5EeY7Ek_2o9JKHJxOELIYtQVMX1IaHn4,2480
13
+ boto3_assist/cloudwatch/cloudwatch_connection_tracker.py,sha256=Y59WfjrB71qYlgmRngenElFEYHA35zK6DQkXY2anD5w,398
14
+ boto3_assist/cloudwatch/cloudwatch_log_connection.py,sha256=qQMZHjUJ6gA8wU9utjQhOURXNSPH2RjxSoAy83bvoCs,1737
15
+ boto3_assist/cloudwatch/cloudwatch_logs.py,sha256=VtI0OnFjX1l4RYVvA8tvveGkPwAogtrplnflZ4dQSNM,1204
16
+ boto3_assist/cloudwatch/cloudwatch_query.py,sha256=uNhSb1Gfp99v8BaHmCnCKs63j4MMU4WveqBavCJyhGY,6409
17
+ boto3_assist/cognito/cognito_authorizer.py,sha256=ONcxzjTACgVYl6qI9kJAQ5SoRMtVHYGDeuKi5QqJvOY,5837
18
+ boto3_assist/cognito/cognito_connection.py,sha256=deuXR3cNHz0mCYff2k0LfAvK--9OkqehWp0Bl--lDuw,1607
19
+ boto3_assist/cognito/cognito_utility.py,sha256=IVZAg58nHG1U7uxe7FsTYpqwwZiwwdIBGiVTZuLCFqg,18417
20
+ boto3_assist/cognito/jwks_cache.py,sha256=1Y9r-YfQ8qrgZN5xYPvjUEEV0vthbdcPdAIaPbZP7kU,373
21
+ boto3_assist/cognito/user.py,sha256=qc44qLx3gwq6q2zMxcPQze1EjeZwy5Kuav93vbe-4WU,820
22
+ boto3_assist/dynamodb/dynamodb.py,sha256=MElfzO0kDKHdMye5vtIOC4sGH32P2xxvPlxj76NEDe4,48632
23
+ boto3_assist/dynamodb/dynamodb_connection.py,sha256=D4KmVpMpE0OuVOwW5g4JBWllUNkwy0hMXEGUiToAMBc,3608
24
+ boto3_assist/dynamodb/dynamodb_helpers.py,sha256=BYJEuXaQVCPbDfbtPswWA_OvV_yC3fVoTtKvIoZeIBc,12092
25
+ boto3_assist/dynamodb/dynamodb_importer.py,sha256=nCKsyRQeMqDSf0Q5mQ_X_oVIg4PRnu0hcUzZnBli610,3471
26
+ boto3_assist/dynamodb/dynamodb_index.py,sha256=2AKxHo8HrRbaxL0ePj7S6ek36_sy5cHkDp5I9wIp8Kw,19797
27
+ boto3_assist/dynamodb/dynamodb_iservice.py,sha256=O9Aj0PFEvcuk2vhARifWTFnUwcQW5EXzwZS478Hm-N0,796
28
+ boto3_assist/dynamodb/dynamodb_key.py,sha256=3VPFBGLXSLNGol5WodLiOFGU60VU9ZAdLjd2oqZ1YH4,3928
29
+ boto3_assist/dynamodb/dynamodb_model_base.py,sha256=5hfnfQPWDS8q7wJS9pFyrcRFLrSlEabs7t2KIRiqT6o,13180
30
+ boto3_assist/dynamodb/dynamodb_model_base_interfaces.py,sha256=SFw-yK7TDPL4cK52bpn2zMm5G4mX7eYNU7eFytEw0-A,749
31
+ boto3_assist/dynamodb/dynamodb_re_indexer.py,sha256=D9gCGTJMS1R-ovAbqXK9gMbkl7a9zkBwA8_pxOAkHSY,6164
32
+ boto3_assist/dynamodb/dynamodb_reindexer.py,sha256=bCj6KIU0fQOgjkkiq9yF51PFZZr4Y9Lu3-hPlmsPG0Y,6164
33
+ boto3_assist/dynamodb/dynamodb_reserved_words.py,sha256=p0irNBSqGe4rd2FwWQqbRJWrNr4svdbWiyIXmz9lj4c,1937
34
+ boto3_assist/dynamodb/dynamodb_reserved_words.txt,sha256=rvctS63Cv3i9SHmPq2Unmj6RZyQ-OMqxUXsNhtbg1is,4136
35
+ boto3_assist/dynamodb/readme.md,sha256=wNMzdRwk0qRV0kE88UUYnJos3pEK0HNjEIVkq2PATf8,1490
36
+ boto3_assist/dynamodb/troubleshooting.md,sha256=Wa2SlH7_5UDz_fffg1h8b9ua9YG7l65bZU22UltPFio,292
37
+ boto3_assist/ec2/ec2_connection.py,sha256=IrtaidH6_SF5l3OeNehRsTlC-sX7EURVqcO-U6P6ff8,1318
38
+ boto3_assist/environment_services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ boto3_assist/environment_services/environment_loader.py,sha256=1uVLqSPQriUWazGXpxPJBLveGL8rLZaT5ZsciqqjVek,3979
40
+ boto3_assist/environment_services/environment_variables.py,sha256=4ccBKdPt6O7hcRT3zBHd8vqu8yQU8udmoD5RLAT3iMs,6801
41
+ boto3_assist/erc/__init__.py,sha256=ZVpE1TayNer4ZFb3t3wlo5LkWD9G-HbYE2DkoQoMI9w,2175
42
+ boto3_assist/erc/ecr_connection.py,sha256=5fbJiouHe2uta4OiN-NKOo3fS2608Zcc01fWBOyPbI4,1370
43
+ boto3_assist/errors/custom_exceptions.py,sha256=QAMW49NbClELVnRd00u4NHfzVtRS3Tc1TrsIMUP9wLw,1041
44
+ boto3_assist/models/serializable_model.py,sha256=ZMrRJRvJWLY8PBSKK_nPCgYKv1qUxDPEVdcADKbIHsI,266
45
+ boto3_assist/s3/s3.py,sha256=ESTPXtyDi8mrwHaYNWjQLNGTuTUV4CxKDqw-O_KGzKs,2052
46
+ boto3_assist/s3/s3_bucket.py,sha256=GfyBbuI5BWz_ybwU_nDqUZiC0wt24PNt49GKZmb05OY,2018
47
+ boto3_assist/s3/s3_connection.py,sha256=0JgEDNoDFPQTo5hQe-lS8mWnFBJ2S8MDSl0LPG__lZo,2008
48
+ boto3_assist/s3/s3_event_data.py,sha256=Q7QUI1pwkc7g6yZ3IZWMXBIAfsMlPRC7wac2RvrQoA4,4112
49
+ boto3_assist/s3/s3_object.py,sha256=77jZeIUFpQX3cFYGGwRFBvL-peCe54iILnthm-GFjMc,22518
50
+ boto3_assist/securityhub/securityhub.py,sha256=ne-J_v4DaCVZm5YgJa_-LKVomLJQo5Gpw6wleAKSsws,5467
51
+ boto3_assist/securityhub/securityhub_connection.py,sha256=hWfcj9gjS2lNXUObyw4cShtveoqJPIp8kKFuz-fz1J4,1449
52
+ boto3_assist/ssm/connection.py,sha256=gYpKn5HsUR3hcRUqJzF5QcTITCk0DReq9KhoE_8-Htg,1370
53
+ boto3_assist/ssm/parameter_store/parameter_store.py,sha256=2ISi-SmR29mESHFH-onJkxPX1aThIgBRojA3ZoNcP9s,3949
54
+ boto3_assist/utilities/datetime_utility.py,sha256=yQa9winN661Gt837zeQQWl4ARMYtZcU4pQEYMnTESC0,11171
55
+ boto3_assist/utilities/decimal_conversion_utility.py,sha256=E87lXpgOTDQpHU2wCE916YzNQeIFSc_nl02le0o9v4E,5037
56
+ boto3_assist/utilities/dictionary_utility.py,sha256=IrN5Q3gJ_KWQ_3KCjyXEJyV8oLk2n3tQOO52dVbY6sk,1002
57
+ boto3_assist/utilities/file_operations.py,sha256=IYhJkh8wUPMvGnyDRRa9yOCDdHN9wR3N6m_xpJS51TM,3949
58
+ boto3_assist/utilities/http_utility.py,sha256=_K39Fq0V4QcgklAWctUktuMjqXDTwgMld77IOUfR2zc,1282
59
+ boto3_assist/utilities/logging_utility.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
+ boto3_assist/utilities/numbers_utility.py,sha256=wzv9d0uXT_2_ZHHio7LBzibwxPqhGpvbq9HinrVn_4A,10160
61
+ boto3_assist/utilities/serialization_utility.py,sha256=m5wRZNeWW9VltQPVNziR27OGKO3MDJm6mFmcDHwN-n4,24479
62
+ boto3_assist/utilities/string_utility.py,sha256=XxUIz19L2LFFTRDAAmdPa8Qhn40u9yO7g4nULFuvg0M,11033
63
+ boto3_assist-0.32.0.dist-info/METADATA,sha256=4vPZ1SreO2iScZ8gO32Otg6TGZsHHin0ZW32UTaLfZM,2879
64
+ boto3_assist-0.32.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
65
+ boto3_assist-0.32.0.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
66
+ boto3_assist-0.32.0.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
67
+ boto3_assist-0.32.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,11 @@
1
+ This license is permissive, meaning it allows almost unrestricted use of the code,
2
+ including the right to use, copy, modify, merge, publish, distribute, sublicense,
3
+ and/or sell copies of the software.
4
+
5
+ However, it requires that the original copyright notice and permission notice be included
6
+ in all copies or substantial portions of the software, ensuring I or anyone else who works on this
7
+ gets credit for the work.
8
+
9
+ Hey, this took a lot of love, so I'd / we'd like to get some recognition for it - if you use it. 😉
10
+
11
+ Thanks for your understanding and support. I hope this library is of use to you!
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Eric Wilson, Geek Cafe LLC & Tech Talk with Eric
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.