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.
@@ -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 you models are inheriting from other models, you may have the primary defined twice."
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
- 'index_name': self.name,
252
- 'query_type': 'Primary' if self.name == DynamoDBIndexes.PRIMARY_INDEX else 'GSI/LSI'
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['partition_key'] = {
258
- 'attribute': self.partition_key.attribute_name,
259
- 'value': self.partition_key.value
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
- 'attribute': self.sort_key.attribute_name,
267
- 'value': self.sort_key.value,
268
- 'condition': condition
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 condition == "between" and low_value is not None and high_value is not None:
273
- sk_info['low_value'] = low_value
274
- sk_info['high_value'] = high_value
275
- sk_info['full_range'] = {
276
- 'low': f"{self.sort_key.value}{low_value}",
277
- 'high': f"{self.sort_key.value}{high_value}"
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['sort_key'] = sk_info
285
+
286
+ result["sort_key"] = sk_info
281
287
  except ValueError:
282
288
  # Sort key value not set
283
- result['sort_key'] = {
284
- 'attribute': self.sort_key.attribute_name,
285
- 'value': None,
286
- 'condition': condition,
287
- 'note': 'Sort key value not set'
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['keys_dict'] = self.to_dict(include_sort_key=include_sort_key)
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['index_name'] = index
453
+ result["index_name"] = index
449
454
  elif isinstance(index, DynamoDBIndex):
450
- result['index_name'] = index.name
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, '_values') and len(key_expression._values) > 0:
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, '_values') and len(pk_condition._values) >= 2:
465
+ if hasattr(pk_condition, "_values") and len(pk_condition._values) >= 2:
461
466
  pk_attr = pk_condition._values[0]
462
- result['partition_key'] = {
463
- 'attribute': pk_attr.name if hasattr(pk_attr, 'name') else str(pk_attr),
464
- 'value': pk_condition._values[1]
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, '_values'):
471
- sk_attr = sk_condition._values[0] if len(sk_condition._values) > 0 else None
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
- 'attribute': sk_attr.name if (sk_attr and hasattr(sk_attr, 'name')) else str(sk_attr),
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['value'] = sk_condition._values[1]
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['value_low'] = sk_condition._values[1]
483
- sk_info['value_high'] = sk_condition._values[2]
484
- del sk_info['value'] # Remove single value key
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, 'expression_operator'):
488
- sk_info['operator'] = sk_condition.expression_operator
489
- if hasattr(sk_condition, 'expression_format'):
490
- sk_info['format'] = sk_condition.expression_format
491
-
492
- result['sort_key'] = sk_info
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 hasattr(key_expression, '_values') and len(key_expression._values) >= 2:
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['partition_key'] = {
499
- 'attribute': pk_attr.name if hasattr(pk_attr, 'name') else str(pk_attr),
500
- 'value': key_expression._values[1]
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['error'] = f"Unable to extract key values: {str(e)}"
505
- result['note'] = "The Key expression structure may have changed"
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.40.0"
1
+ __version__ = "0.41.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boto3_assist
3
- Version: 0.40.0
3
+ Version: 0.41.0
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
@@ -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=_ExaG55L38qKQZWAUr2OC6wbl37pJ9GTCjtqQbCdwB0,23
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=2AKxHo8HrRbaxL0ePj7S6ek36_sy5cHkDp5I9wIp8Kw,19797
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.40.0.dist-info/METADATA,sha256=5_jINdvUKPSIhxoDPYm0mCPGVigMUc5ecFbS1iICqWc,2879
70
- boto3_assist-0.40.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
71
- boto3_assist-0.40.0.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
72
- boto3_assist-0.40.0.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
73
- boto3_assist-0.40.0.dist-info/RECORD,,
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,,