boto3-assist 0.40.0__py3-none-any.whl → 0.41.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/dynamodb/dynamodb_index.py +106 -86
- boto3_assist/version.py +1 -1
- {boto3_assist-0.40.0.dist-info → boto3_assist-0.41.0.dist-info}/METADATA +1 -1
- {boto3_assist-0.40.0.dist-info → boto3_assist-0.41.0.dist-info}/RECORD +7 -7
- {boto3_assist-0.40.0.dist-info → boto3_assist-0.41.0.dist-info}/WHEEL +0 -0
- {boto3_assist-0.40.0.dist-info → boto3_assist-0.41.0.dist-info}/licenses/LICENSE-EXPLAINED.txt +0 -0
- {boto3_assist-0.40.0.dist-info → boto3_assist-0.41.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -38,7 +38,7 @@ class DynamoDBIndexes:
|
|
|
38
38
|
raise ValueError(
|
|
39
39
|
f"The index {index.name} is already defined in your model somewhere. "
|
|
40
40
|
"This error is generated to protect you from unforeseen issues. "
|
|
41
|
-
"If
|
|
41
|
+
"If your models are inheriting from other models, you may have the primary defined twice."
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
self.__indexes[DynamoDBIndexes.PRIMARY_INDEX] = index
|
|
@@ -152,19 +152,19 @@ class DynamoDBIndex:
|
|
|
152
152
|
def to_dict(self, include_sort_key: bool = True) -> dict[str, str]:
|
|
153
153
|
"""
|
|
154
154
|
Return a dictionary representation of this index's keys for debugging.
|
|
155
|
-
|
|
155
|
+
|
|
156
156
|
This is particularly useful for:
|
|
157
157
|
- Debugging key generation logic
|
|
158
158
|
- Logging DynamoDB operations
|
|
159
159
|
- Verifying composite key structure
|
|
160
160
|
- Testing key values
|
|
161
|
-
|
|
161
|
+
|
|
162
162
|
Args:
|
|
163
163
|
include_sort_key: Whether to include the sort key (default: True)
|
|
164
|
-
|
|
164
|
+
|
|
165
165
|
Returns:
|
|
166
166
|
Dictionary with partition key and optionally sort key.
|
|
167
|
-
|
|
167
|
+
|
|
168
168
|
Example:
|
|
169
169
|
>>> index = DynamoDBIndex()
|
|
170
170
|
>>> index.partition_key.attribute_name = "pk"
|
|
@@ -173,21 +173,21 @@ class DynamoDBIndex:
|
|
|
173
173
|
>>> index.sort_key.value = lambda: "user#123"
|
|
174
174
|
>>> index.to_dict()
|
|
175
175
|
{'pk': 'user#123', 'sk': 'user#123'}
|
|
176
|
-
|
|
176
|
+
|
|
177
177
|
>>> # Partition key only
|
|
178
178
|
>>> index.to_dict(include_sort_key=False)
|
|
179
179
|
{'pk': 'user#123'}
|
|
180
|
-
|
|
180
|
+
|
|
181
181
|
>>> # Useful for debugging
|
|
182
182
|
>>> print(f"Querying with key: {index.to_dict()}")
|
|
183
183
|
Querying with key: {'pk': 'user#123', 'sk': 'user#123'}
|
|
184
184
|
"""
|
|
185
185
|
result = {}
|
|
186
|
-
|
|
186
|
+
|
|
187
187
|
# Always include partition key
|
|
188
188
|
if self.__pk:
|
|
189
189
|
result[self.partition_key.attribute_name] = self.partition_key.value
|
|
190
|
-
|
|
190
|
+
|
|
191
191
|
# Optionally include sort key
|
|
192
192
|
if include_sort_key and self.__sk and self.sort_key.attribute_name:
|
|
193
193
|
try:
|
|
@@ -195,7 +195,7 @@ class DynamoDBIndex:
|
|
|
195
195
|
except ValueError:
|
|
196
196
|
# Sort key value not set, skip it
|
|
197
197
|
pass
|
|
198
|
-
|
|
198
|
+
|
|
199
199
|
return result
|
|
200
200
|
|
|
201
201
|
def debug_info(
|
|
@@ -208,22 +208,22 @@ class DynamoDBIndex:
|
|
|
208
208
|
) -> dict[str, Any]:
|
|
209
209
|
"""
|
|
210
210
|
Return detailed debugging information about this index and how it would be queried.
|
|
211
|
-
|
|
211
|
+
|
|
212
212
|
This is useful for understanding:
|
|
213
213
|
- What keys are defined
|
|
214
214
|
- What condition would be used in a query
|
|
215
215
|
- What the actual key values are
|
|
216
216
|
- What index name would be used
|
|
217
|
-
|
|
217
|
+
|
|
218
218
|
Args:
|
|
219
219
|
include_sort_key: Whether to include the sort key (default: True)
|
|
220
220
|
condition: The condition type being used (default: "begins_with")
|
|
221
221
|
low_value: Low value for "between" condition
|
|
222
222
|
high_value: High value for "between" condition
|
|
223
|
-
|
|
223
|
+
|
|
224
224
|
Returns:
|
|
225
225
|
Dictionary with debugging information including keys, condition, and index details.
|
|
226
|
-
|
|
226
|
+
|
|
227
227
|
Example:
|
|
228
228
|
>>> index = product.indexes.get("gsi1")
|
|
229
229
|
>>> debug = index.debug_info(condition="begins_with")
|
|
@@ -242,54 +242,60 @@ class DynamoDBIndex:
|
|
|
242
242
|
'keys_dict': {'gsi1_pk': 'category#electronics', 'gsi1_sk': 'product#prod_123'},
|
|
243
243
|
'query_type': 'GSI' or 'Primary'
|
|
244
244
|
}
|
|
245
|
-
|
|
245
|
+
|
|
246
246
|
>>> # Check condition type
|
|
247
247
|
>>> if debug['sort_key']['condition'] == 'begins_with':
|
|
248
248
|
... print("This query uses begins_with")
|
|
249
249
|
"""
|
|
250
250
|
result = {
|
|
251
|
-
|
|
252
|
-
|
|
251
|
+
"index_name": self.name,
|
|
252
|
+
"query_type": (
|
|
253
|
+
"Primary" if self.name == DynamoDBIndexes.PRIMARY_INDEX else "GSI/LSI"
|
|
254
|
+
),
|
|
253
255
|
}
|
|
254
|
-
|
|
256
|
+
|
|
255
257
|
# Partition key info
|
|
256
258
|
if self.__pk:
|
|
257
|
-
result[
|
|
258
|
-
|
|
259
|
-
|
|
259
|
+
result["partition_key"] = {
|
|
260
|
+
"attribute": self.partition_key.attribute_name,
|
|
261
|
+
"value": self.partition_key.value,
|
|
260
262
|
}
|
|
261
|
-
|
|
263
|
+
|
|
262
264
|
# Sort key info with condition
|
|
263
265
|
if include_sort_key and self.__sk and self.sort_key.attribute_name:
|
|
264
266
|
try:
|
|
265
267
|
sk_info = {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
268
|
+
"attribute": self.sort_key.attribute_name,
|
|
269
|
+
"value": self.sort_key.value,
|
|
270
|
+
"condition": condition,
|
|
269
271
|
}
|
|
270
|
-
|
|
272
|
+
|
|
271
273
|
# Add range info for between condition
|
|
272
|
-
if
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
274
|
+
if (
|
|
275
|
+
condition == "between"
|
|
276
|
+
and low_value is not None
|
|
277
|
+
and high_value is not None
|
|
278
|
+
):
|
|
279
|
+
sk_info["low_value"] = low_value
|
|
280
|
+
sk_info["high_value"] = high_value
|
|
281
|
+
sk_info["full_range"] = {
|
|
282
|
+
"low": f"{self.sort_key.value}{low_value}",
|
|
283
|
+
"high": f"{self.sort_key.value}{high_value}",
|
|
278
284
|
}
|
|
279
|
-
|
|
280
|
-
result[
|
|
285
|
+
|
|
286
|
+
result["sort_key"] = sk_info
|
|
281
287
|
except ValueError:
|
|
282
288
|
# Sort key value not set
|
|
283
|
-
result[
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
289
|
+
result["sort_key"] = {
|
|
290
|
+
"attribute": self.sort_key.attribute_name,
|
|
291
|
+
"value": None,
|
|
292
|
+
"condition": condition,
|
|
293
|
+
"note": "Sort key value not set",
|
|
288
294
|
}
|
|
289
|
-
|
|
295
|
+
|
|
290
296
|
# Include the keys dictionary for convenience
|
|
291
|
-
result[
|
|
292
|
-
|
|
297
|
+
result["keys_dict"] = self.to_dict(include_sort_key=include_sort_key)
|
|
298
|
+
|
|
293
299
|
return result
|
|
294
300
|
|
|
295
301
|
def key(
|
|
@@ -393,25 +399,24 @@ class DynamoDBIndex:
|
|
|
393
399
|
|
|
394
400
|
@staticmethod
|
|
395
401
|
def extract_key_values(
|
|
396
|
-
key_expression: And | Equals,
|
|
397
|
-
index: Optional[str | DynamoDBIndex] = None
|
|
402
|
+
key_expression: And | Equals, index: Optional[str | DynamoDBIndex] = None
|
|
398
403
|
) -> dict[str, Any]:
|
|
399
404
|
"""
|
|
400
405
|
Extract key values and condition information from a boto3 Key condition expression.
|
|
401
|
-
|
|
406
|
+
|
|
402
407
|
This is useful for debugging queries at runtime to see exactly what values
|
|
403
408
|
are being used in the KeyConditionExpression.
|
|
404
|
-
|
|
409
|
+
|
|
405
410
|
Args:
|
|
406
411
|
key_expression: The Key condition expression (from key() or _build_query_key())
|
|
407
412
|
index: Optional index name (str) or DynamoDBIndex object to include in results
|
|
408
|
-
|
|
413
|
+
|
|
409
414
|
Returns:
|
|
410
415
|
Dictionary containing:
|
|
411
416
|
- index_name: str (if index parameter provided)
|
|
412
417
|
- partition_key: {'attribute': str, 'value': str}
|
|
413
418
|
- sort_key: {'attribute': str, 'value': str, 'operator': str, 'format': str} (if present)
|
|
414
|
-
|
|
419
|
+
|
|
415
420
|
Example:
|
|
416
421
|
>>> index = model.indexes.get("gsi1")
|
|
417
422
|
>>> key_expr = index.key(query_key=True, condition="begins_with")
|
|
@@ -430,10 +435,10 @@ class DynamoDBIndex:
|
|
|
430
435
|
'format': '{operator}({0}, {1})'
|
|
431
436
|
}
|
|
432
437
|
}
|
|
433
|
-
|
|
438
|
+
|
|
434
439
|
>>> # Or pass just the index name
|
|
435
440
|
>>> debug = DynamoDBIndex.extract_key_values(key_expr, "gsi1")
|
|
436
|
-
|
|
441
|
+
|
|
437
442
|
>>> # Quick access to values
|
|
438
443
|
>>> pk_value = debug['partition_key']['value']
|
|
439
444
|
>>> sk_value = debug['sort_key']['value']
|
|
@@ -441,67 +446,82 @@ class DynamoDBIndex:
|
|
|
441
446
|
>>> index_name = debug.get('index_name')
|
|
442
447
|
"""
|
|
443
448
|
result = {}
|
|
444
|
-
|
|
449
|
+
|
|
445
450
|
# Include index name if provided
|
|
446
451
|
if index is not None:
|
|
447
452
|
if isinstance(index, str):
|
|
448
|
-
result[
|
|
453
|
+
result["index_name"] = index
|
|
449
454
|
elif isinstance(index, DynamoDBIndex):
|
|
450
|
-
result[
|
|
451
|
-
|
|
455
|
+
result["index_name"] = index.name
|
|
456
|
+
|
|
452
457
|
try:
|
|
453
458
|
# The key_expression._values is a list of conditions
|
|
454
459
|
# [0] is the partition key (Equals condition)
|
|
455
460
|
# [1] is the sort key (ComparisonCondition) if present
|
|
456
|
-
|
|
457
|
-
if hasattr(key_expression,
|
|
461
|
+
|
|
462
|
+
if hasattr(key_expression, "_values") and len(key_expression._values) > 0:
|
|
458
463
|
# Extract partition key
|
|
459
464
|
pk_condition = key_expression._values[0]
|
|
460
|
-
if hasattr(pk_condition,
|
|
465
|
+
if hasattr(pk_condition, "_values") and len(pk_condition._values) >= 2:
|
|
461
466
|
pk_attr = pk_condition._values[0]
|
|
462
|
-
result[
|
|
463
|
-
|
|
464
|
-
|
|
467
|
+
result["partition_key"] = {
|
|
468
|
+
"attribute": (
|
|
469
|
+
pk_attr.name if hasattr(pk_attr, "name") else str(pk_attr)
|
|
470
|
+
),
|
|
471
|
+
"value": pk_condition._values[1],
|
|
465
472
|
}
|
|
466
|
-
|
|
473
|
+
|
|
467
474
|
# Extract sort key if present
|
|
468
475
|
if len(key_expression._values) > 1:
|
|
469
476
|
sk_condition = key_expression._values[1]
|
|
470
|
-
if hasattr(sk_condition,
|
|
471
|
-
sk_attr =
|
|
477
|
+
if hasattr(sk_condition, "_values"):
|
|
478
|
+
sk_attr = (
|
|
479
|
+
sk_condition._values[0]
|
|
480
|
+
if len(sk_condition._values) > 0
|
|
481
|
+
else None
|
|
482
|
+
)
|
|
472
483
|
sk_info = {
|
|
473
|
-
|
|
484
|
+
"attribute": (
|
|
485
|
+
sk_attr.name
|
|
486
|
+
if (sk_attr and hasattr(sk_attr, "name"))
|
|
487
|
+
else str(sk_attr)
|
|
488
|
+
),
|
|
474
489
|
}
|
|
475
|
-
|
|
490
|
+
|
|
476
491
|
# Get value(s)
|
|
477
492
|
if len(sk_condition._values) > 1:
|
|
478
|
-
sk_info[
|
|
479
|
-
|
|
493
|
+
sk_info["value"] = sk_condition._values[1]
|
|
494
|
+
|
|
480
495
|
# For 'between' condition, there are two values
|
|
481
496
|
if len(sk_condition._values) > 2:
|
|
482
|
-
sk_info[
|
|
483
|
-
sk_info[
|
|
484
|
-
del sk_info[
|
|
485
|
-
|
|
497
|
+
sk_info["value_low"] = sk_condition._values[1]
|
|
498
|
+
sk_info["value_high"] = sk_condition._values[2]
|
|
499
|
+
del sk_info["value"] # Remove single value key
|
|
500
|
+
|
|
486
501
|
# Get operator and format
|
|
487
|
-
if hasattr(sk_condition,
|
|
488
|
-
sk_info[
|
|
489
|
-
if hasattr(sk_condition,
|
|
490
|
-
sk_info[
|
|
491
|
-
|
|
492
|
-
result[
|
|
493
|
-
|
|
502
|
+
if hasattr(sk_condition, "expression_operator"):
|
|
503
|
+
sk_info["operator"] = sk_condition.expression_operator
|
|
504
|
+
if hasattr(sk_condition, "expression_format"):
|
|
505
|
+
sk_info["format"] = sk_condition.expression_format
|
|
506
|
+
|
|
507
|
+
result["sort_key"] = sk_info
|
|
508
|
+
|
|
494
509
|
# If no _values found, handle single Equals condition (no sort key)
|
|
495
510
|
elif isinstance(key_expression, Equals):
|
|
496
|
-
if
|
|
511
|
+
if (
|
|
512
|
+
hasattr(key_expression, "_values")
|
|
513
|
+
and len(key_expression._values) >= 2
|
|
514
|
+
):
|
|
497
515
|
pk_attr = key_expression._values[0]
|
|
498
|
-
result[
|
|
499
|
-
|
|
500
|
-
|
|
516
|
+
result["partition_key"] = {
|
|
517
|
+
"attribute": (
|
|
518
|
+
pk_attr.name if hasattr(pk_attr, "name") else str(pk_attr)
|
|
519
|
+
),
|
|
520
|
+
"value": key_expression._values[1],
|
|
501
521
|
}
|
|
502
|
-
|
|
522
|
+
|
|
503
523
|
except (AttributeError, IndexError) as e:
|
|
504
|
-
result[
|
|
505
|
-
result[
|
|
506
|
-
|
|
524
|
+
result["error"] = f"Unable to extract key values: {str(e)}"
|
|
525
|
+
result["note"] = "The Key expression structure may have changed"
|
|
526
|
+
|
|
507
527
|
return result
|
boto3_assist/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.41.0"
|
|
@@ -7,7 +7,7 @@ boto3_assist/connection_tracker.py,sha256=UgfR9RlvXf3A4ssMr3gDMpw89ka8mSRvJn4M34
|
|
|
7
7
|
boto3_assist/http_status_codes.py,sha256=G0zRSWenwavYKETvDF9tNVUXQz3Ae2gXdBETYbjvJe8,3284
|
|
8
8
|
boto3_assist/role_assumption_mixin.py,sha256=PMUU5yC2FUBjFD1UokVkRY3CPB5zTw85AhIB5BMtbc8,1031
|
|
9
9
|
boto3_assist/session_setup_mixin.py,sha256=X-JQKyyaWNA8Z8kKgf2V2I5vsiLAH8udLTX_xepnsdQ,3140
|
|
10
|
-
boto3_assist/version.py,sha256=
|
|
10
|
+
boto3_assist/version.py,sha256=WqzeTKVe9Q7QeiOa2KhoieBiGxzHK-Gb2TvnyeIJEKk,23
|
|
11
11
|
boto3_assist/aws_lambda/event_info.py,sha256=OkZ4WzuGaHEu_T8sB188KBgShAJhZpWASALKRGBOhMg,14648
|
|
12
12
|
boto3_assist/aws_lambda/mock_context.py,sha256=LPjHP-3YSoY6iPl1kPqJDwSVf1zLNTcukUunDtYcbK0,116
|
|
13
13
|
boto3_assist/cloudwatch/cloudwatch_connection.py,sha256=mnGWaLSQpHh5EeY7Ek_2o9JKHJxOELIYtQVMX1IaHn4,2480
|
|
@@ -25,7 +25,7 @@ boto3_assist/dynamodb/dynamodb.py,sha256=HY9i_PIxUW5-Mz6rQrmKfyd1Mwl-VwogH3w-Ckt
|
|
|
25
25
|
boto3_assist/dynamodb/dynamodb_connection.py,sha256=1fA8iC6lq5F4bItJZZwL22fNgVBl7Sw6rV01PXVQ8Cc,3703
|
|
26
26
|
boto3_assist/dynamodb/dynamodb_helpers.py,sha256=BYJEuXaQVCPbDfbtPswWA_OvV_yC3fVoTtKvIoZeIBc,12092
|
|
27
27
|
boto3_assist/dynamodb/dynamodb_importer.py,sha256=nCKsyRQeMqDSf0Q5mQ_X_oVIg4PRnu0hcUzZnBli610,3471
|
|
28
|
-
boto3_assist/dynamodb/dynamodb_index.py,sha256=
|
|
28
|
+
boto3_assist/dynamodb/dynamodb_index.py,sha256=EySBmzNIGqUjPZFUWFswXamPNPkfGisy-7ynu0Y8aJk,19861
|
|
29
29
|
boto3_assist/dynamodb/dynamodb_iservice.py,sha256=O9Aj0PFEvcuk2vhARifWTFnUwcQW5EXzwZS478Hm-N0,796
|
|
30
30
|
boto3_assist/dynamodb/dynamodb_key.py,sha256=adUnMN6HARTY3Co3hPiodXaW82Q_CCqvT-LjZ8-rP14,4130
|
|
31
31
|
boto3_assist/dynamodb/dynamodb_model_base.py,sha256=gCUG0UKXV9AUcPBlbxJ3Xb8wOS8awrGG7DZpZjgIS58,21291
|
|
@@ -66,8 +66,8 @@ boto3_assist/utilities/logging_utility.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
|
66
66
|
boto3_assist/utilities/numbers_utility.py,sha256=wzv9d0uXT_2_ZHHio7LBzibwxPqhGpvbq9HinrVn_4A,10160
|
|
67
67
|
boto3_assist/utilities/serialization_utility.py,sha256=m5wRZNeWW9VltQPVNziR27OGKO3MDJm6mFmcDHwN-n4,24479
|
|
68
68
|
boto3_assist/utilities/string_utility.py,sha256=XxUIz19L2LFFTRDAAmdPa8Qhn40u9yO7g4nULFuvg0M,11033
|
|
69
|
-
boto3_assist-0.
|
|
70
|
-
boto3_assist-0.
|
|
71
|
-
boto3_assist-0.
|
|
72
|
-
boto3_assist-0.
|
|
73
|
-
boto3_assist-0.
|
|
69
|
+
boto3_assist-0.41.0.dist-info/METADATA,sha256=Hk7GCF0InL5y1uV5Lf9lzxPScwtEDMurJxE3ACrqmXY,2879
|
|
70
|
+
boto3_assist-0.41.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
71
|
+
boto3_assist-0.41.0.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
|
|
72
|
+
boto3_assist-0.41.0.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
|
|
73
|
+
boto3_assist-0.41.0.dist-info/RECORD,,
|
|
File without changes
|
{boto3_assist-0.40.0.dist-info → boto3_assist-0.41.0.dist-info}/licenses/LICENSE-EXPLAINED.txt
RENAMED
|
File without changes
|
|
File without changes
|