boto3-assist 0.21.0__tar.gz → 0.22.0__tar.gz

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 (144) hide show
  1. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/.vscode/settings.json +2 -1
  2. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/PKG-INFO +1 -1
  3. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/pyproject.toml +1 -1
  4. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb.py +46 -9
  5. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +2 -2
  6. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/utilities/datetime_utility.py +8 -10
  7. boto3_assist-0.22.0/src/boto3_assist/version.py +1 -0
  8. boto3_assist-0.22.0/tests/unit/dynamodb_tests/dynamodb_fail_if_exists_test.py +61 -0
  9. boto3_assist-0.21.0/src/boto3_assist/version.py +0 -1
  10. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/.env.docker +0 -0
  11. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/.env.docker.001 +0 -0
  12. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/.env.docker.nosql.workbench +0 -0
  13. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/.env.unittest +0 -0
  14. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/.gitignore +0 -0
  15. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/.vscode/launch.json +0 -0
  16. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/.vscode/tasks.json +0 -0
  17. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/LICENSE-EXPLAINED.txt +0 -0
  18. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/LICENSE.txt +0 -0
  19. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/README.md +0 -0
  20. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/aws_regions_with_status.csv +0 -0
  21. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/aws_regions_with_status.json +0 -0
  22. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/devops/build.py +0 -0
  23. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/devops/readme.md +0 -0
  24. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/__init__.py +0 -0
  25. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/cloudwatch/log_report.py +0 -0
  26. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/models/order_item_model.py +0 -0
  27. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/models/order_model.py +0 -0
  28. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/models/product_model.py +0 -0
  29. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/models/user_model.py +0 -0
  30. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/models/user_post_model.py +0 -0
  31. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/order_example/main.py +0 -0
  32. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/order_example/products.json +0 -0
  33. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/services/order_item_service.py +0 -0
  34. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/services/order_service.py +0 -0
  35. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/services/product_service.py +0 -0
  36. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/services/table_service.py +0 -0
  37. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/services/user_post_service.py +0 -0
  38. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/services/user_service.py +0 -0
  39. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/services/user_service_client_example.py +0 -0
  40. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/services/user_service_resource_example.py +0 -0
  41. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/dynamodb/user_post_example/main.py +0 -0
  42. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/examples/ec2/regions_report.py +0 -0
  43. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/module-headers.txt +0 -0
  44. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/mypy.ini +0 -0
  45. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/requirements-dev.txt +0 -0
  46. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/requirements.txt +0 -0
  47. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/run-checks.sh +0 -0
  48. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/run_unit_tests.sh +0 -0
  49. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/__init__.py +0 -0
  50. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/aws_config.py +0 -0
  51. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/aws_lambda/event_info.py +0 -0
  52. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/aws_lambda/mock_context.py +0 -0
  53. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/boto3session.py +0 -0
  54. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/cloudwatch/cloudwatch_connection.py +0 -0
  55. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +0 -0
  56. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/cloudwatch/cloudwatch_log_connection.py +0 -0
  57. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/cloudwatch/cloudwatch_logs.py +0 -0
  58. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/cloudwatch/cloudwatch_query.py +0 -0
  59. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/cognito/cognito_authorizer.py +0 -0
  60. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/cognito/cognito_connection.py +0 -0
  61. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/cognito/cognito_utility.py +0 -0
  62. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/cognito/jwks_cache.py +0 -0
  63. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/cognito/user.py +0 -0
  64. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/connection.py +0 -0
  65. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/connection_tracker.py +0 -0
  66. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_connection.py +0 -0
  67. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_helpers.py +0 -0
  68. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_importer.py +0 -0
  69. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_index.py +0 -0
  70. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_iservice.py +0 -0
  71. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_key.py +0 -0
  72. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_model_base.py +0 -0
  73. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_re_indexer.py +0 -0
  74. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_reindexer.py +0 -0
  75. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.py +0 -0
  76. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.txt +0 -0
  77. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/readme.md +0 -0
  78. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/dynamodb/troubleshooting.md +0 -0
  79. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/ec2/ec2_connection.py +0 -0
  80. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/environment_services/__init__.py +0 -0
  81. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/environment_services/environment_loader.py +0 -0
  82. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/environment_services/environment_variables.py +0 -0
  83. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/errors/custom_exceptions.py +0 -0
  84. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/http_status_codes.py +0 -0
  85. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/models/serializable_model.py +0 -0
  86. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/role_assumption_mixin.py +0 -0
  87. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/s3/s3.py +0 -0
  88. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/s3/s3_bucket.py +0 -0
  89. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/s3/s3_connection.py +0 -0
  90. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/s3/s3_event_data.py +0 -0
  91. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/s3/s3_object.py +0 -0
  92. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/securityhub/securityhub.py +0 -0
  93. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/securityhub/securityhub_connection.py +0 -0
  94. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/session_setup_mixin.py +0 -0
  95. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/ssm/connection.py +0 -0
  96. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/ssm/parameter_store/parameter_store.py +0 -0
  97. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/utilities/dictionary_utility.py +0 -0
  98. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/utilities/file_operations.py +0 -0
  99. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/utilities/http_utility.py +0 -0
  100. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/utilities/logging_utility.py +0 -0
  101. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/utilities/numbers_utility.py +0 -0
  102. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/utilities/serialization_utility.py +0 -0
  103. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/src/boto3_assist/utilities/string_utility.py +0 -0
  104. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/__init__.py +0 -0
  105. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/integration/cross_account_connection_test.py +0 -0
  106. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/integration/tenant.py +0 -0
  107. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/integration/tenant_services.py +0 -0
  108. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/aws_config_test.py +0 -0
  109. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/common/db_test_helpers.py +0 -0
  110. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/__init__.py +0 -0
  111. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/db_models/cms/base.py +0 -0
  112. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/db_models/cms/content_block.py +0 -0
  113. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/db_models/cms/page.py +0 -0
  114. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/db_models/cms/template.py +0 -0
  115. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/db_models/simple_model.py +0 -0
  116. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/db_models/user_model.py +0 -0
  117. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/db_models/user_required_fields_model.py +0 -0
  118. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/dynamodb_model_base_test.py +0 -0
  119. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/dynamodb_model_projections_test.py +0 -0
  120. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/dynamodb_model_serializtion_test.py +0 -0
  121. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/dynamodb_moto_sorting_test.py +0 -0
  122. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/dynamodb_query_test.py +0 -0
  123. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/dynamodb_tests/dynamodb_reindex_test.py +0 -0
  124. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/examples_test/__init__.py +0 -0
  125. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/examples_test/user_service_test.py +0 -0
  126. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/lambda_tests/__init__.py +0 -0
  127. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/lambda_tests/event_info_test.py +0 -0
  128. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/models_tests/__init__.py +0 -0
  129. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/models_tests/models/person.py +0 -0
  130. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/models_tests/models/user.py +0 -0
  131. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/models_tests/serializable_model_person_test.py +0 -0
  132. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/models_tests/serializable_model_user_test.py +0 -0
  133. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/models_tests/serializable_model_wide_test.py +0 -0
  134. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/parameter_store/__init__.py +0 -0
  135. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/parameter_store/parameter_store_test.py +0 -0
  136. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/s3/__init__.py +0 -0
  137. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/s3/files/test.txt +0 -0
  138. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/s3/s3_event_data_test.py +0 -0
  139. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/s3/s3_file_delete_test.py +0 -0
  140. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/s3/s3_file_upload_test.py +0 -0
  141. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/session_tests/test_boto3_session_manager.py +0 -0
  142. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/utilities/__init__.py +0 -0
  143. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/utilities/serialization_utility_test.py +0 -0
  144. {boto3_assist-0.21.0 → boto3_assist-0.22.0}/tests/unit/utilities/string_utility_test.py +0 -0
@@ -28,7 +28,8 @@
28
28
  },
29
29
  "cSpell.words": [
30
30
  "addopts",
31
- "geekcafe"
31
+ "geekcafe",
32
+ "relativedelta"
32
33
  ],
33
34
 
34
35
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boto3_assist
3
- Version: 0.21.0
3
+ Version: 0.22.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
@@ -15,7 +15,7 @@ addopts = "-m 'not integration'"
15
15
 
16
16
  [project]
17
17
  name = "boto3_assist"
18
- version = "0.21.0"
18
+ version = "0.22.0"
19
19
 
20
20
  authors = [
21
21
  { name="Eric Wilson", email="boto3-assist@geekcafe.com" }
@@ -6,6 +6,8 @@ MIT License. See Project Root for the license information.
6
6
 
7
7
  import os
8
8
  from typing import List, Optional, overload, Dict, Any
9
+ from botocore.exceptions import ClientError
10
+ from boto3.dynamodb.conditions import Attr
9
11
 
10
12
  from aws_lambda_powertools import Logger
11
13
  from boto3.dynamodb.conditions import (
@@ -65,17 +67,22 @@ class DynamoDB(DynamoDBConnection):
65
67
  item: dict | DynamoDBModelBase,
66
68
  table_name: str,
67
69
  source: Optional[str] = None,
70
+ fail_if_exists: bool = False,
68
71
  ) -> dict:
69
72
  """
70
73
  Save an item to the database
71
74
  Args:
72
- item (dict): DynamoDB Dictionary Object or DynamoDBModelBase. Supports the "client" or
73
- "resource" syntax
75
+ item (dict): DynamoDB Dictionary Object or DynamoDBModelBase.
76
+ Supports the "client" or "resource" syntax
74
77
  table_name (str): The DynamoDb Table Name
75
78
  source (str, optional): The source of the call, used for logging. Defaults to None.
79
+ fail_if_exists (bool, optional): Only allow it to insert once.
80
+ Fail if it already exits. This is useful for loggers, historical records,
81
+ tasks, etc. that should only be created once
76
82
 
77
83
  Raises:
78
- e: Any Error Raised
84
+ ClientError: Client specific errors
85
+ Exception: Any Error Raised
79
86
 
80
87
  Returns:
81
88
  dict: The Response from DynamoDB's put_item actions.
@@ -85,7 +92,7 @@ class DynamoDB(DynamoDBConnection):
85
92
 
86
93
  try:
87
94
  if not isinstance(item, dict):
88
- # attemp to convert it
95
+ # attempt to convert it
89
96
  if not isinstance(item, DynamoDBModelBase):
90
97
  raise RuntimeError(
91
98
  f"Item is not a dictionary or DynamoDBModelBase. Type: {type(item).__name__}. "
@@ -106,19 +113,49 @@ class DynamoDB(DynamoDBConnection):
106
113
 
107
114
  if isinstance(item, dict) and isinstance(next(iter(item.values())), dict):
108
115
  # Use boto3.client syntax
109
- response = dict(
110
- self.dynamodb_client.put_item(TableName=table_name, Item=item)
111
- )
116
+ # client API style
117
+ params = {
118
+ "TableName": table_name,
119
+ "Item": item,
120
+ }
121
+ if fail_if_exists:
122
+ # only insert if the item does *not* already exist
123
+ params["ConditionExpression"] = (
124
+ "attribute_not_exists(#pk) AND attribute_not_exists(#sk)"
125
+ )
126
+ params["ExpressionAttributeNames"] = {"#pk": "pk", "#sk": "sk"}
127
+ response = dict(self.dynamodb_client.put_item(**params))
128
+
112
129
  else:
113
130
  # Use boto3.resource syntax
114
131
  table = self.dynamodb_resource.Table(table_name)
115
- response = dict(table.put_item(Item=item)) # type: ignore[arg-type]
132
+ if fail_if_exists:
133
+ cond = Attr("pk").not_exists() & Attr("sk").not_exists()
134
+ response = dict(table.put_item(Item=item, ConditionExpression=cond))
135
+ else:
136
+ response = dict(table.put_item(Item=item))
137
+ # response = dict(table.put_item(Item=item)) # type: ignore[arg-type]
138
+
139
+ except ClientError as e:
140
+ if (
141
+ fail_if_exists
142
+ and e.response["Error"]["Code"] == "ConditionalCheckFailedException"
143
+ ):
144
+ raise RuntimeError(
145
+ f"Item with pk={item['pk']} already exists in {table_name} "
146
+ f"and fail_if_exists was set to {fail_if_exists}"
147
+ ) from e
148
+
149
+ logger.exception(
150
+ {"source": f"{source}", "metric_filter": "put_item", "error": str(e)}
151
+ )
152
+ raise
116
153
 
117
154
  except Exception as e: # pylint: disable=w0718
118
155
  logger.exception(
119
156
  {"source": f"{source}", "metric_filter": "put_item", "error": str(e)}
120
157
  )
121
- raise e
158
+ raise
122
159
 
123
160
  return response
124
161
 
@@ -25,10 +25,10 @@ class HasKeys(Protocol):
25
25
  """Interface for classes that have primary and sort keys"""
26
26
 
27
27
  def get_pk(self, index_name: str) -> Optional[str]:
28
- """Inteface to get_pk"""
28
+ """Interface to get_pk"""
29
29
 
30
30
  def get_sk(self, index_name: str) -> Optional[str]:
31
- """Inteface to get_sk"""
31
+ """Interface to get_sk"""
32
32
 
33
33
  def get_key(self, index_name: str) -> And | Equals:
34
34
  """Get the index name and key"""
@@ -12,7 +12,6 @@ from aws_lambda_powertools import Logger
12
12
  from dateutil.relativedelta import relativedelta
13
13
 
14
14
 
15
-
16
15
  logger = Logger()
17
16
 
18
17
  _last_timestamp = None
@@ -43,11 +42,10 @@ class DatetimeUtility:
43
42
  @staticmethod
44
43
  def get_utc_now() -> datetime:
45
44
  # datetime.utcnow()
46
- # below is the prefered over datetime.utcnow()
45
+ # below is the preferred over datetime.utcnow()
47
46
  return datetime.now(timezone.utc)
48
47
 
49
48
  @staticmethod
50
-
51
49
  def string_to_date(string_date: str | datetime) -> datetime | None:
52
50
  """
53
51
  Description: takes a string value and returns it as a datetime.
@@ -269,7 +267,7 @@ class DatetimeUtility:
269
267
  months (int): the number of months
270
268
 
271
269
  Returns:
272
- datetime: One Month added to the input dt
270
+ datetime: X Month(s) added to the input dt
273
271
  """
274
272
  new_date = dt + relativedelta(months=+months)
275
273
  new_date = new_date + relativedelta(microseconds=-1)
@@ -278,14 +276,14 @@ class DatetimeUtility:
278
276
 
279
277
  @staticmethod
280
278
  def add_days(dt: datetime, days: int = 1) -> datetime:
281
- """Add a month to the current date
279
+ """Add a day to the current date
282
280
 
283
281
  Args:
284
282
  dt (datetime): datetime
285
- months (int): the number of months
283
+ days (int): the number of days, use a negative number to subtract
286
284
 
287
285
  Returns:
288
- datetime: One Month added to the input dt
286
+ datetime: X days added to the input dt
289
287
  """
290
288
  new_date = dt + relativedelta(days=+days)
291
289
  new_date = new_date + relativedelta(microseconds=-1)
@@ -314,7 +312,7 @@ class DatetimeUtility:
314
312
 
315
313
  Args:
316
314
  utc_datetime (datetime): datetime in utc
317
- timezone (str): 'US/Eastern', 'US/Moutain', etc
315
+ timezone (str): 'US/Eastern', 'US/Mountain', etc
318
316
 
319
317
  Returns:
320
318
  datetime: in the correct timezone
@@ -326,7 +324,7 @@ class DatetimeUtility:
326
324
 
327
325
  @staticmethod
328
326
  def get_timestamp(value: datetime | None | str) -> float:
329
- """Get a timestampe from a date or 0.0"""
327
+ """Get a timestamp from a date or 0.0"""
330
328
  if value is None:
331
329
  return 0.0
332
330
  if not isinstance(value, datetime):
@@ -339,7 +337,7 @@ class DatetimeUtility:
339
337
 
340
338
  @staticmethod
341
339
  def get_timestamp_or_none(value: datetime | None | str) -> float | None:
342
- """Get a timestampe from a date or None"""
340
+ """Get a timestamp from a date or None"""
343
341
  if value is None:
344
342
  return None
345
343
  if not isinstance(value, datetime):
@@ -0,0 +1 @@
1
+ __version__ = '0.22.0'
@@ -0,0 +1,61 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ import unittest
8
+ import moto
9
+
10
+ from tests.unit.dynamodb_tests.db_models.user_model import User
11
+ from boto3_assist.environment_services.environment_loader import EnvironmentLoader
12
+ from boto3_assist.dynamodb.dynamodb import DynamoDB
13
+ from tests.unit.common.db_test_helpers import DbTestHelper
14
+
15
+
16
+ @moto.mock_aws
17
+ class DbQueryTest(unittest.TestCase):
18
+ "Serialization Tests"
19
+
20
+ def __init__(self, methodName="runTest"):
21
+ super().__init__(methodName)
22
+
23
+ ev: EnvironmentLoader = EnvironmentLoader()
24
+ # NOTE: you need to make sure the the env file below exists or you will get an error
25
+ ev.load_environment_file(file_name=".env.unittest")
26
+ self.__table_name = "mock_test_table"
27
+
28
+ self.db: DynamoDB = DynamoDB()
29
+
30
+ def setUp(self):
31
+ # load our test environment file to make sure we override any default AWS Environment Vars setup
32
+ # we don't want to accidentally connect to live environments
33
+ # https://docs.getmoto.org/en/latest/docs/getting_started.html
34
+
35
+ self.db: DynamoDB = self.db or DynamoDB()
36
+ DbTestHelper().helper_create_mock_table(self.__table_name, self.db.client)
37
+ print("Setup Complete")
38
+
39
+ def test_fail_if_exists(self):
40
+
41
+ # create a few users
42
+
43
+ user_id: str = "123456789"
44
+
45
+ user = User(user_id)
46
+ response = self.db.save(table_name=self.__table_name, item=user)
47
+
48
+ self.assertEqual(response["ResponseMetadata"]["HTTPStatusCode"], 200)
49
+
50
+ # this will fail, fail_if_exists is set to true
51
+ self.assertRaises(
52
+ Exception,
53
+ self.db.save,
54
+ table_name=self.__table_name,
55
+ item=user,
56
+ fail_if_exists=True,
57
+ )
58
+
59
+ # this does not
60
+ response = self.db.save(table_name=self.__table_name, item=user)
61
+ self.assertEqual(response["ResponseMetadata"]["HTTPStatusCode"], 200)
@@ -1 +0,0 @@
1
- __version__ = '0.21.0'
File without changes
File without changes
File without changes
File without changes
File without changes