boto3-assist 0.22.0__tar.gz → 0.24.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 (147) hide show
  1. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/.vscode/settings.json +1 -0
  2. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/PKG-INFO +5 -5
  3. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/README.md +4 -4
  4. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/devops/build.py +1 -1
  5. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/pyproject.toml +1 -1
  6. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/requirements-dev.txt +2 -1
  7. boto3_assist-0.24.0/setup.sh +55 -0
  8. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb.py +3 -1
  9. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_index.py +30 -13
  10. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_model_base.py +9 -1
  11. boto3_assist-0.24.0/src/boto3_assist/version.py +1 -0
  12. boto3_assist-0.24.0/tests/unit/dynamodb_tests/db_models/task.py +76 -0
  13. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/dynamodb_fail_if_exists_test.py +7 -9
  14. boto3_assist-0.24.0/tests/unit/dynamodb_tests/dynamodb_primary_key_sort_test.py +82 -0
  15. boto3_assist-0.22.0/src/boto3_assist/version.py +0 -1
  16. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/.env.docker +0 -0
  17. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/.env.docker.001 +0 -0
  18. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/.env.docker.nosql.workbench +0 -0
  19. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/.env.unittest +0 -0
  20. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/.gitignore +0 -0
  21. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/.vscode/launch.json +0 -0
  22. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/.vscode/tasks.json +0 -0
  23. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/LICENSE-EXPLAINED.txt +0 -0
  24. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/LICENSE.txt +0 -0
  25. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/aws_regions_with_status.csv +0 -0
  26. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/aws_regions_with_status.json +0 -0
  27. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/devops/readme.md +0 -0
  28. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/__init__.py +0 -0
  29. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/cloudwatch/log_report.py +0 -0
  30. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/models/order_item_model.py +0 -0
  31. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/models/order_model.py +0 -0
  32. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/models/product_model.py +0 -0
  33. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/models/user_model.py +0 -0
  34. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/models/user_post_model.py +0 -0
  35. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/order_example/main.py +0 -0
  36. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/order_example/products.json +0 -0
  37. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/services/order_item_service.py +0 -0
  38. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/services/order_service.py +0 -0
  39. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/services/product_service.py +0 -0
  40. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/services/table_service.py +0 -0
  41. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/services/user_post_service.py +0 -0
  42. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/services/user_service.py +0 -0
  43. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/services/user_service_client_example.py +0 -0
  44. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/services/user_service_resource_example.py +0 -0
  45. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/dynamodb/user_post_example/main.py +0 -0
  46. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/examples/ec2/regions_report.py +0 -0
  47. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/module-headers.txt +0 -0
  48. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/mypy.ini +0 -0
  49. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/requirements.txt +0 -0
  50. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/run-checks.sh +0 -0
  51. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/run_unit_tests.sh +0 -0
  52. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/__init__.py +0 -0
  53. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/aws_config.py +0 -0
  54. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/aws_lambda/event_info.py +0 -0
  55. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/aws_lambda/mock_context.py +0 -0
  56. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/boto3session.py +0 -0
  57. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/cloudwatch/cloudwatch_connection.py +0 -0
  58. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +0 -0
  59. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/cloudwatch/cloudwatch_log_connection.py +0 -0
  60. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/cloudwatch/cloudwatch_logs.py +0 -0
  61. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/cloudwatch/cloudwatch_query.py +0 -0
  62. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/cognito/cognito_authorizer.py +0 -0
  63. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/cognito/cognito_connection.py +0 -0
  64. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/cognito/cognito_utility.py +0 -0
  65. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/cognito/jwks_cache.py +0 -0
  66. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/cognito/user.py +0 -0
  67. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/connection.py +0 -0
  68. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/connection_tracker.py +0 -0
  69. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_connection.py +0 -0
  70. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_helpers.py +0 -0
  71. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_importer.py +0 -0
  72. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_iservice.py +0 -0
  73. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_key.py +0 -0
  74. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +0 -0
  75. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_re_indexer.py +0 -0
  76. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_reindexer.py +0 -0
  77. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.py +0 -0
  78. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.txt +0 -0
  79. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/readme.md +0 -0
  80. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/dynamodb/troubleshooting.md +0 -0
  81. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/ec2/ec2_connection.py +0 -0
  82. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/environment_services/__init__.py +0 -0
  83. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/environment_services/environment_loader.py +0 -0
  84. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/environment_services/environment_variables.py +0 -0
  85. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/errors/custom_exceptions.py +0 -0
  86. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/http_status_codes.py +0 -0
  87. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/models/serializable_model.py +0 -0
  88. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/role_assumption_mixin.py +0 -0
  89. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/s3/s3.py +0 -0
  90. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/s3/s3_bucket.py +0 -0
  91. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/s3/s3_connection.py +0 -0
  92. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/s3/s3_event_data.py +0 -0
  93. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/s3/s3_object.py +0 -0
  94. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/securityhub/securityhub.py +0 -0
  95. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/securityhub/securityhub_connection.py +0 -0
  96. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/session_setup_mixin.py +0 -0
  97. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/ssm/connection.py +0 -0
  98. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/ssm/parameter_store/parameter_store.py +0 -0
  99. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/utilities/datetime_utility.py +0 -0
  100. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/utilities/dictionary_utility.py +0 -0
  101. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/utilities/file_operations.py +0 -0
  102. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/utilities/http_utility.py +0 -0
  103. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/utilities/logging_utility.py +0 -0
  104. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/utilities/numbers_utility.py +0 -0
  105. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/utilities/serialization_utility.py +0 -0
  106. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/src/boto3_assist/utilities/string_utility.py +0 -0
  107. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/__init__.py +0 -0
  108. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/integration/cross_account_connection_test.py +0 -0
  109. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/integration/tenant.py +0 -0
  110. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/integration/tenant_services.py +0 -0
  111. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/aws_config_test.py +0 -0
  112. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/common/db_test_helpers.py +0 -0
  113. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/__init__.py +0 -0
  114. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/db_models/cms/base.py +0 -0
  115. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/db_models/cms/content_block.py +0 -0
  116. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/db_models/cms/page.py +0 -0
  117. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/db_models/cms/template.py +0 -0
  118. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/db_models/simple_model.py +0 -0
  119. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/db_models/user_model.py +0 -0
  120. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/db_models/user_required_fields_model.py +0 -0
  121. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/dynamodb_model_base_test.py +0 -0
  122. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/dynamodb_model_projections_test.py +0 -0
  123. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/dynamodb_model_serializtion_test.py +0 -0
  124. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/dynamodb_moto_sorting_test.py +0 -0
  125. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/dynamodb_query_test.py +0 -0
  126. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/dynamodb_tests/dynamodb_reindex_test.py +0 -0
  127. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/examples_test/__init__.py +0 -0
  128. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/examples_test/user_service_test.py +0 -0
  129. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/lambda_tests/__init__.py +0 -0
  130. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/lambda_tests/event_info_test.py +0 -0
  131. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/models_tests/__init__.py +0 -0
  132. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/models_tests/models/person.py +0 -0
  133. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/models_tests/models/user.py +0 -0
  134. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/models_tests/serializable_model_person_test.py +0 -0
  135. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/models_tests/serializable_model_user_test.py +0 -0
  136. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/models_tests/serializable_model_wide_test.py +0 -0
  137. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/parameter_store/__init__.py +0 -0
  138. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/parameter_store/parameter_store_test.py +0 -0
  139. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/s3/__init__.py +0 -0
  140. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/s3/files/test.txt +0 -0
  141. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/s3/s3_event_data_test.py +0 -0
  142. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/s3/s3_file_delete_test.py +0 -0
  143. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/s3/s3_file_upload_test.py +0 -0
  144. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/session_tests/test_boto3_session_manager.py +0 -0
  145. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/utilities/__init__.py +0 -0
  146. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/utilities/serialization_utility_test.py +0 -0
  147. {boto3_assist-0.22.0 → boto3_assist-0.24.0}/tests/unit/utilities/string_utility_test.py +0 -0
@@ -28,6 +28,7 @@
28
28
  },
29
29
  "cSpell.words": [
30
30
  "addopts",
31
+ "dateutil",
31
32
  "geekcafe",
32
33
  "relativedelta"
33
34
  ],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boto3_assist
3
- Version: 0.22.0
3
+ Version: 0.24.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
@@ -32,7 +32,7 @@ Description-Content-Type: text/markdown
32
32
 
33
33
  This is in beta and subject to changes before it's initial 1.0.0 release
34
34
 
35
- This libary was created to make life a little easier when using boto3.
35
+ This library was created to make life a little easier when using boto3.
36
36
 
37
37
  Currently it supports:
38
38
  - User Authentication / Session Mapping
@@ -40,11 +40,11 @@ Currently it supports:
40
40
 
41
41
 
42
42
  ## User Authentication / Session Mapping
43
- Have you ever needed an easy way to load your sessions for a local, dev or production enviroment? Well this library
43
+ Have you ever needed an easy way to load your sessions for a local, dev or production environment? Well this library
44
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
45
  environment vars first and then load your session.
46
46
 
47
- ## DyamoDB model mapping and Key Generation
47
+ ## DynamoDB model mapping and Key Generation
48
48
  It's a light weight mapping tool to turn your python classes / object models to DynamoDB items that are ready
49
49
  for saving. See the [examples](https://github.com/geekcafe/boto3-assist/tree/main/examples) directory in the repo for more information.
50
50
 
@@ -61,7 +61,7 @@ pip install boto3-assist
61
61
  ## Running Unit Tests
62
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
63
 
64
- For your convenince 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.
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
65
 
66
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
67
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  This is in beta and subject to changes before it's initial 1.0.0 release
8
8
 
9
- This libary was created to make life a little easier when using boto3.
9
+ This library was created to make life a little easier when using boto3.
10
10
 
11
11
  Currently it supports:
12
12
  - User Authentication / Session Mapping
@@ -14,11 +14,11 @@ Currently it supports:
14
14
 
15
15
 
16
16
  ## User Authentication / Session Mapping
17
- Have you ever needed an easy way to load your sessions for a local, dev or production enviroment? Well this library
17
+ Have you ever needed an easy way to load your sessions for a local, dev or production environment? Well this library
18
18
  makes it a little easier by lazy loading your boto3 session so that tools like `python-dotenv` can be used to load your
19
19
  environment vars first and then load your session.
20
20
 
21
- ## DyamoDB model mapping and Key Generation
21
+ ## DynamoDB model mapping and Key Generation
22
22
  It's a light weight mapping tool to turn your python classes / object models to DynamoDB items that are ready
23
23
  for saving. See the [examples](https://github.com/geekcafe/boto3-assist/tree/main/examples) directory in the repo for more information.
24
24
 
@@ -35,7 +35,7 @@ pip install boto3-assist
35
35
  ## Running Unit Tests
36
36
  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).
37
37
 
38
- For your convenince 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.
38
+ 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.
39
39
 
40
40
  Since we also point to a profile, you should create the profile in the `~/.aws/config` file. The entry should look like the following:
41
41
 
@@ -62,7 +62,7 @@ def extract_version_and_write_to_file(pyproject_toml: str, version_file: str):
62
62
 
63
63
  def run_build():
64
64
  """Run python build commands"""
65
- run_commands(["python", "-m", "build"])
65
+ run_commands(["python", "-m", "build", "--no-isolation"])
66
66
 
67
67
 
68
68
  def run_publish():
@@ -15,7 +15,7 @@ addopts = "-m 'not integration'"
15
15
 
16
16
  [project]
17
17
  name = "boto3_assist"
18
- version = "0.22.0"
18
+ version = "0.24.0"
19
19
 
20
20
  authors = [
21
21
  { name="Eric Wilson", email="boto3-assist@geekcafe.com" }
@@ -20,4 +20,5 @@ pkginfo # occasionally we need to upgrade this or we can get upload errors when
20
20
  # ERROR InvalidDistribution: Metadata is missing required fields: Name, Version.
21
21
  # Make sure the distribution includes the files where those fields are specified, and is using a supported
22
22
  # Metadata-Version: 1.0, 1.1, 1.2, 2.0, 2.1, 2.2, 2.3.
23
- pytest
23
+ pytest
24
+ hatchling
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # setup.sh - Cross-platform setup for python projects
5
+
6
+ # Default mode: ask the user
7
+ FETCH_LATEST="interactive"
8
+
9
+ usage() {
10
+ cat <<EOF
11
+ Usage: $0 [options]
12
+
13
+ Options:
14
+ -u, --update Automatically pull the latest setup.py (no prompt)
15
+ -n, --no-update Skip pulling the latest setup.py
16
+ --ci CI/CD mode (same as --update)
17
+ -h, --help Show this help message and exit
18
+ EOF
19
+ exit 0
20
+ }
21
+
22
+ # --- parse command-line flags ---
23
+ while [[ $# -gt 0 ]]; do
24
+ case "$1" in
25
+ -u|--update) FETCH_LATEST="yes" ;;
26
+ -n|--no-update) FETCH_LATEST="no" ;;
27
+ --ci) FETCH_LATEST="yes" ;;
28
+ -h|--help) usage ;;
29
+ *) echo "Unknown option: $1" >&2
30
+ usage
31
+ ;;
32
+ esac
33
+ shift
34
+ done
35
+
36
+ # --- interactive prompt if needed ---
37
+ if [[ "$FETCH_LATEST" == "interactive" ]]; then
38
+ read -r -p "Pull latest setup.py from repository? [y/N] " answer
39
+ if [[ "$answer" =~ ^[Yy] ]]; then
40
+ FETCH_LATEST="yes"
41
+ else
42
+ FETCH_LATEST="no"
43
+ fi
44
+ fi
45
+
46
+ # --- fetch if requested ---
47
+ if [[ "$FETCH_LATEST" == "yes" ]]; then
48
+ echo "🔄 Fetching latest setup.py..."
49
+ curl -sSL \
50
+ https://raw.githubusercontent.com/geekcafe/py-setup-tool/main/setup.py \
51
+ -o setup.py
52
+ fi
53
+
54
+ # --- run the Python installer ---
55
+ python3 setup.py
@@ -355,7 +355,9 @@ class DynamoDB(DynamoDBConnection):
355
355
  key = key.key()
356
356
 
357
357
  kwargs: dict = {}
358
- if index_name:
358
+
359
+ if index_name and index_name != "primary":
360
+ # only include the index_name if we are not using our "primary" pk/sk
359
361
  kwargs["IndexName"] = f"{index_name}"
360
362
  kwargs["TableName"] = f"{table_name}"
361
363
  kwargs["KeyConditionExpression"] = key
@@ -37,7 +37,7 @@ class DynamoDBIndexes:
37
37
  if index.name in self.__indexes:
38
38
  raise ValueError(
39
39
  f"The index {index.name} is already defined in your model somewhere. "
40
- "This error is generated to protect you from unforseen issues. "
40
+ "This error is generated to protect you from unforeseen issues. "
41
41
  "If you models are inheriting from other models, you may have the primary defined twice."
42
42
  )
43
43
 
@@ -64,7 +64,7 @@ class DynamoDBIndexes:
64
64
  for _, v in self.__indexes.items():
65
65
  if v.partition_key.attribute_name == index.partition_key.attribute_name:
66
66
  raise ValueError(
67
- f"The attrubute {index.partition_key.attribute_name} is already being used by index "
67
+ f"The attribute {index.partition_key.attribute_name} is already being used by index "
68
68
  f"{v.name}. "
69
69
  f"Reusing this attribute would over write the value on index {v.name}"
70
70
  )
@@ -73,7 +73,7 @@ class DynamoDBIndexes:
73
73
  for _, v in self.__indexes.items():
74
74
  if v.sort_key.attribute_name == index.sort_key.attribute_name:
75
75
  raise ValueError(
76
- f"The attrubute {index.sort_key.attribute_name} is already being used by index "
76
+ f"The attribute {index.sort_key.attribute_name} is already being used by index "
77
77
  f"{v.name}. "
78
78
  f"Reusing this attribute would over write the value on index {v.name}"
79
79
  )
@@ -156,21 +156,13 @@ class DynamoDBIndex:
156
156
  condition: str = "begins_with",
157
157
  low_value: Any = None,
158
158
  high_value: Any = None,
159
+ query_key: bool = False,
159
160
  # sk_value_2: Optional[str | int | float] = None,
160
161
  ) -> dict | Key | ConditionBase | ComparisonCondition | Equals:
161
162
  """Get the key for a given index"""
162
163
  key: dict | Key | ConditionBase | ComparisonCondition | Equals
163
- if self.name == DynamoDBIndexes.PRIMARY_INDEX and include_sort_key:
164
- # this is a direct primary key which is used in a get call
165
- # this is differenet than query keys
166
- key = {}
167
- key[self.partition_key.attribute_name] = self.partition_key.value
168
164
 
169
- if self.sort_key and self.sort_key.attribute_name:
170
- key[self.sort_key.attribute_name] = self.sort_key.value
171
-
172
- return key
173
- else:
165
+ if query_key:
174
166
  key = self._build_query_key(
175
167
  include_sort_key=include_sort_key,
176
168
  condition=condition,
@@ -179,6 +171,31 @@ class DynamoDBIndex:
179
171
  )
180
172
  return key
181
173
 
174
+ elif (
175
+ self.name == DynamoDBIndexes.PRIMARY_INDEX
176
+ and include_sort_key
177
+ # if it ends with a # we are assuming that we are doing a wild card mapping
178
+ and not str(self.sort_key.value).endswith("#")
179
+ ):
180
+ # this is a direct primary key which is used in a get call
181
+ # this is different than query keys
182
+ key = {}
183
+ key[self.partition_key.attribute_name] = self.partition_key.value
184
+
185
+ if self.sort_key and self.sort_key.attribute_name:
186
+ key[self.sort_key.attribute_name] = self.sort_key.value
187
+
188
+ return key
189
+
190
+ # catch all (TODO: decide if this is the best pattern or should we raise an error)
191
+ key = self._build_query_key(
192
+ include_sort_key=include_sort_key,
193
+ condition=condition,
194
+ low_value=low_value,
195
+ high_value=high_value,
196
+ )
197
+ return key
198
+
182
199
  def _build_query_key(
183
200
  self,
184
201
  *,
@@ -21,6 +21,7 @@ from boto3_assist.dynamodb.dynamodb_index import (
21
21
  from boto3_assist.dynamodb.dynamodb_reserved_words import DynamoDBReservedWords
22
22
  from boto3_assist.utilities.datetime_utility import DatetimeUtility
23
23
  from boto3_assist.models.serializable_model import SerializableModel
24
+ from boto3_assist.utilities.string_utility import StringUtility
24
25
 
25
26
 
26
27
  def exclude_from_serialization(method):
@@ -190,7 +191,7 @@ class DynamoDBModelBase(SerializableModel):
190
191
  def to_dictionary(self, include_none: bool = True):
191
192
  """
192
193
  Convert the instance to a dictionary without an indexes/keys.
193
- Usefull for turning an object into a dictionary for serialization.
194
+ Useful for turning an object into a dictionary for serialization.
194
195
  This is the same as to_resource_dictionary(include_indexes=False)
195
196
  """
196
197
  return DynamoDBSerializer.to_resource_dictionary(
@@ -205,6 +206,13 @@ class DynamoDBModelBase(SerializableModel):
205
206
 
206
207
  return self.indexes.get(index_name)
207
208
 
209
+ @staticmethod
210
+ def generate_uuid(sortable: bool = True) -> str:
211
+ if sortable:
212
+ return StringUtility.generate_sortable_uuid()
213
+
214
+ return StringUtility.generate_uuid()
215
+
208
216
  @property
209
217
  @exclude_from_serialization
210
218
  def helpers(self) -> DynamoDBHelpers:
@@ -0,0 +1 @@
1
+ __version__ = '0.24.0'
@@ -0,0 +1,76 @@
1
+ from typing import Optional
2
+ from boto3_assist.dynamodb.dynamodb_model_base import DynamoDBModelBase
3
+ from boto3_assist.dynamodb.dynamodb_index import DynamoDBIndex
4
+ from boto3_assist.dynamodb.dynamodb_key import DynamoDBKey
5
+ from boto3_assist.utilities.string_utility import StringUtility
6
+
7
+
8
+ class Task(DynamoDBModelBase):
9
+ """
10
+ A Generic Task Model
11
+
12
+ Using the same task.id, you can chain child elements via task.step_id
13
+
14
+ """
15
+
16
+ def __init__(self, id: Optional[str] = None):
17
+ super().__init__()
18
+ self.id: str = id or StringUtility.generate_uuid()
19
+ self._name: Optional[str] = None
20
+ self._step: Optional[str] = None
21
+ self._step_id: Optional[str] = None
22
+ self.metadata: dict = {}
23
+ self._setup_pk()
24
+
25
+ @property
26
+ def name(self) -> Optional[str]:
27
+ """
28
+ Returns the name for this task
29
+ """
30
+ return self._name
31
+
32
+ @name.setter
33
+ def name(self, value: str):
34
+ """
35
+ Sets the name for this task
36
+ """
37
+ self._name = value
38
+
39
+ @property
40
+ def step(self) -> Optional[str]:
41
+ """
42
+ Returns the step for this task
43
+ """
44
+ return self._step
45
+
46
+ @step.setter
47
+ def step(self, value: str):
48
+ """
49
+ Sets the step for this task
50
+ """
51
+ self._step = value
52
+
53
+ @property
54
+ def step_id(self) -> str | None:
55
+
56
+ return self._step_id
57
+
58
+ @step_id.setter
59
+ def step_id(self, value: str):
60
+ """
61
+ Sets the step_id for this task
62
+ """
63
+
64
+ self._step_id = value
65
+
66
+ def _setup_pk(self):
67
+ primary: DynamoDBIndex = DynamoDBIndex()
68
+ primary.name = "primary"
69
+ primary.partition_key.attribute_name = "pk"
70
+ primary.partition_key.value = lambda: DynamoDBKey.build_key(
71
+ (self.__class__.__name__, self.id)
72
+ )
73
+
74
+ primary.sort_key.attribute_name = "sk"
75
+ primary.sort_key.value = lambda: DynamoDBKey.build_key(("step", self.step_id))
76
+ self.indexes.add_primary(primary)
@@ -6,8 +6,8 @@ MIT License. See Project Root for the license information.
6
6
 
7
7
  import unittest
8
8
  import moto
9
-
10
- from tests.unit.dynamodb_tests.db_models.user_model import User
9
+ from typing import Optional
10
+ from tests.unit.dynamodb_tests.db_models.task import Task
11
11
  from boto3_assist.environment_services.environment_loader import EnvironmentLoader
12
12
  from boto3_assist.dynamodb.dynamodb import DynamoDB
13
13
  from tests.unit.common.db_test_helpers import DbTestHelper
@@ -38,12 +38,10 @@ class DbQueryTest(unittest.TestCase):
38
38
 
39
39
  def test_fail_if_exists(self):
40
40
 
41
- # create a few users
42
-
43
- user_id: str = "123456789"
41
+ task_id: str = "123456789"
44
42
 
45
- user = User(user_id)
46
- response = self.db.save(table_name=self.__table_name, item=user)
43
+ task = Task(task_id)
44
+ response = self.db.save(table_name=self.__table_name, item=task)
47
45
 
48
46
  self.assertEqual(response["ResponseMetadata"]["HTTPStatusCode"], 200)
49
47
 
@@ -52,10 +50,10 @@ class DbQueryTest(unittest.TestCase):
52
50
  Exception,
53
51
  self.db.save,
54
52
  table_name=self.__table_name,
55
- item=user,
53
+ item=task,
56
54
  fail_if_exists=True,
57
55
  )
58
56
 
59
57
  # this does not
60
- response = self.db.save(table_name=self.__table_name, item=user)
58
+ response = self.db.save(table_name=self.__table_name, item=task)
61
59
  self.assertEqual(response["ResponseMetadata"]["HTTPStatusCode"], 200)
@@ -0,0 +1,82 @@
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
+ from typing import Optional
10
+ from tests.unit.dynamodb_tests.db_models.task import Task
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 create_data_process_task(
40
+ self,
41
+ name: str,
42
+ step: str,
43
+ task_id: Optional[str] = None,
44
+ metadata: Optional[dict] = None,
45
+ ) -> Task:
46
+ task = Task()
47
+ if task_id:
48
+ task.id = task_id
49
+ task.step_id = Task.generate_uuid()
50
+ else:
51
+ task.step_id = task.id
52
+ task.name = name
53
+ task.step = step
54
+
55
+ task.metadata = metadata
56
+ response = self.db.save(
57
+ table_name=self.__table_name, item=task, fail_if_exists=True
58
+ )
59
+ assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
60
+ return task
61
+
62
+ def test_primary_key_query_sort(self):
63
+ task: Task = self.create_data_process_task(
64
+ name="test", step="test", task_id=None
65
+ )
66
+
67
+ # no create a bunch of children
68
+ for i in range(0, 10):
69
+ self.create_data_process_task(
70
+ name="test",
71
+ step=f"child-{i}",
72
+ task_id=task.id,
73
+ metadata={"child": f"i"},
74
+ )
75
+
76
+ query_model: Task = Task()
77
+ query_model.id = task.id
78
+ key = query_model.get_key("primary")
79
+ query_response = self.db.query(table_name=self.__table_name, key=key)
80
+
81
+ # primary task and 10 children == 11
82
+ assert len(query_response["Items"]) == 11
@@ -1 +0,0 @@
1
- __version__ = '0.22.0'
File without changes
File without changes
File without changes
File without changes