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.
- boto3_assist/__init__.py +0 -0
- boto3_assist/aws_config.py +199 -0
- boto3_assist/aws_lambda/event_info.py +414 -0
- boto3_assist/aws_lambda/mock_context.py +5 -0
- boto3_assist/boto3session.py +87 -0
- boto3_assist/cloudwatch/cloudwatch_connection.py +84 -0
- boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +17 -0
- boto3_assist/cloudwatch/cloudwatch_log_connection.py +62 -0
- boto3_assist/cloudwatch/cloudwatch_logs.py +39 -0
- boto3_assist/cloudwatch/cloudwatch_query.py +191 -0
- boto3_assist/cognito/cognito_authorizer.py +169 -0
- boto3_assist/cognito/cognito_connection.py +59 -0
- boto3_assist/cognito/cognito_utility.py +514 -0
- boto3_assist/cognito/jwks_cache.py +21 -0
- boto3_assist/cognito/user.py +27 -0
- boto3_assist/connection.py +146 -0
- boto3_assist/connection_tracker.py +120 -0
- boto3_assist/dynamodb/dynamodb.py +1206 -0
- boto3_assist/dynamodb/dynamodb_connection.py +113 -0
- boto3_assist/dynamodb/dynamodb_helpers.py +333 -0
- boto3_assist/dynamodb/dynamodb_importer.py +102 -0
- boto3_assist/dynamodb/dynamodb_index.py +507 -0
- boto3_assist/dynamodb/dynamodb_iservice.py +29 -0
- boto3_assist/dynamodb/dynamodb_key.py +130 -0
- boto3_assist/dynamodb/dynamodb_model_base.py +382 -0
- boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +34 -0
- boto3_assist/dynamodb/dynamodb_re_indexer.py +165 -0
- boto3_assist/dynamodb/dynamodb_reindexer.py +165 -0
- boto3_assist/dynamodb/dynamodb_reserved_words.py +52 -0
- boto3_assist/dynamodb/dynamodb_reserved_words.txt +573 -0
- boto3_assist/dynamodb/readme.md +68 -0
- boto3_assist/dynamodb/troubleshooting.md +7 -0
- boto3_assist/ec2/ec2_connection.py +57 -0
- boto3_assist/environment_services/__init__.py +0 -0
- boto3_assist/environment_services/environment_loader.py +128 -0
- boto3_assist/environment_services/environment_variables.py +219 -0
- boto3_assist/erc/__init__.py +64 -0
- boto3_assist/erc/ecr_connection.py +57 -0
- boto3_assist/errors/custom_exceptions.py +46 -0
- boto3_assist/http_status_codes.py +80 -0
- boto3_assist/models/serializable_model.py +9 -0
- boto3_assist/role_assumption_mixin.py +38 -0
- boto3_assist/s3/s3.py +64 -0
- boto3_assist/s3/s3_bucket.py +67 -0
- boto3_assist/s3/s3_connection.py +76 -0
- boto3_assist/s3/s3_event_data.py +168 -0
- boto3_assist/s3/s3_object.py +695 -0
- boto3_assist/securityhub/securityhub.py +150 -0
- boto3_assist/securityhub/securityhub_connection.py +57 -0
- boto3_assist/session_setup_mixin.py +70 -0
- boto3_assist/ssm/connection.py +57 -0
- boto3_assist/ssm/parameter_store/parameter_store.py +116 -0
- boto3_assist/utilities/datetime_utility.py +349 -0
- boto3_assist/utilities/decimal_conversion_utility.py +140 -0
- boto3_assist/utilities/dictionary_utility.py +32 -0
- boto3_assist/utilities/file_operations.py +135 -0
- boto3_assist/utilities/http_utility.py +48 -0
- boto3_assist/utilities/logging_utility.py +0 -0
- boto3_assist/utilities/numbers_utility.py +329 -0
- boto3_assist/utilities/serialization_utility.py +664 -0
- boto3_assist/utilities/string_utility.py +337 -0
- boto3_assist/version.py +1 -0
- boto3_assist-0.32.0.dist-info/METADATA +76 -0
- boto3_assist-0.32.0.dist-info/RECORD +67 -0
- boto3_assist-0.32.0.dist-info/WHEEL +4 -0
- boto3_assist-0.32.0.dist-info/licenses/LICENSE-EXPLAINED.txt +11 -0
- 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:])
|
boto3_assist/version.py
ADDED
|
@@ -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
|
+
[](https://pypi.org/project/boto3-assist/)
|
|
30
|
+
[](https://opensource.org/licenses/MIT)
|
|
31
|
+
[](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,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.
|