aws-advanced-python-wrapper 1.2.0__tar.gz → 1.4.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 (81) hide show
  1. aws_advanced_python_wrapper-1.4.0/NOTICE +2 -0
  2. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/PKG-INFO +18 -17
  3. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/README.md +15 -11
  4. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/aurora_connection_tracker_plugin.py +0 -13
  5. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/aurora_initial_connection_strategy_plugin.py +13 -16
  6. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/aws_secrets_manager_plugin.py +24 -10
  7. aws_advanced_python_wrapper-1.4.0/aws_advanced_python_wrapper/blue_green_plugin.py +1926 -0
  8. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/connection_provider.py +7 -5
  9. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/database_dialect.py +162 -48
  10. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/default_plugin.py +6 -3
  11. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/driver_info.py +1 -1
  12. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/failover_plugin.py +2 -23
  13. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/fastest_response_strategy_plugin.py +3 -22
  14. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/federated_plugin.py +5 -2
  15. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/host_list_provider.py +10 -0
  16. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/host_monitoring_plugin.py +7 -24
  17. aws_advanced_python_wrapper-1.4.0/aws_advanced_python_wrapper/host_monitoring_v2_plugin.py +518 -0
  18. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/host_selector.py +88 -4
  19. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/hostinfo.py +23 -9
  20. aws_advanced_python_wrapper-1.4.0/aws_advanced_python_wrapper/limitless_plugin.py +532 -0
  21. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/okta_plugin.py +5 -2
  22. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/plugin.py +3 -2
  23. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/plugin_service.py +175 -33
  24. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/read_write_splitting_plugin.py +2 -15
  25. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/reader_failover_handler.py +9 -3
  26. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/resources/aws_advanced_python_wrapper_messages.properties +118 -1
  27. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/sql_alchemy_connection_provider.py +7 -4
  28. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/stale_dns_plugin.py +0 -12
  29. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/atomic.py +41 -0
  30. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/cache_map.py +4 -4
  31. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/concurrent.py +72 -3
  32. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/properties.py +115 -10
  33. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/rds_url_type.py +1 -0
  34. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/rdsutils.py +66 -8
  35. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/utils.py +8 -0
  36. aws_advanced_python_wrapper-1.4.0/aws_advanced_python_wrapper/utils/value_container.py +71 -0
  37. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/wrapper.py +7 -1
  38. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/writer_failover_handler.py +7 -7
  39. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/pyproject.toml +5 -3
  40. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/CONTRIBUTING.md +0 -0
  41. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/LICENSE +0 -0
  42. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/__init__.py +0 -0
  43. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/allowed_and_blocked_hosts.py +0 -0
  44. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/connect_time_plugin.py +0 -0
  45. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/credentials_provider_factory.py +0 -0
  46. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/custom_endpoint_plugin.py +0 -0
  47. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/developer_plugin.py +0 -0
  48. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/driver_configuration_profiles.py +0 -0
  49. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/driver_dialect.py +0 -0
  50. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/driver_dialect_codes.py +0 -0
  51. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/driver_dialect_manager.py +0 -0
  52. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/errors.py +0 -0
  53. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/exception_handling.py +0 -0
  54. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/execute_time_plugin.py +0 -0
  55. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/failover_result.py +0 -0
  56. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/host_availability.py +0 -0
  57. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/iam_plugin.py +0 -0
  58. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/mysql_driver_dialect.py +0 -0
  59. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/pep249.py +0 -0
  60. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/pg_driver_dialect.py +0 -0
  61. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/sqlalchemy_driver_dialect.py +0 -0
  62. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/states/__init__.py +0 -0
  63. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/states/session_state.py +0 -0
  64. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/states/session_state_service.py +0 -0
  65. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/__init__.py +0 -0
  66. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/decorators.py +0 -0
  67. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/failover_mode.py +0 -0
  68. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/iam_utils.py +0 -0
  69. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/log.py +0 -0
  70. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/messages.py +0 -0
  71. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/mysql_exception_handler.py +0 -0
  72. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/notifications.py +0 -0
  73. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/pg_exception_handler.py +0 -0
  74. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/region_utils.py +0 -0
  75. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/saml_utils.py +0 -0
  76. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/sliding_expiration_cache.py +0 -0
  77. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/telemetry/default_telemetry_factory.py +0 -0
  78. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/telemetry/null_telemetry.py +0 -0
  79. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/telemetry/open_telemetry.py +0 -0
  80. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/telemetry/telemetry.py +0 -0
  81. {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/telemetry/xray_telemetry.py +0 -0
@@ -0,0 +1,2 @@
1
+ AWS Advanced Python Wrapper
2
+ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
- Name: aws-advanced-python-wrapper
3
- Version: 1.2.0
2
+ Name: aws_advanced_python_wrapper
3
+ Version: 1.4.0
4
4
  Summary: Amazon Web Services (AWS) Advanced Python Wrapper
5
5
  Home-page: https://github.com/awslabs/aws-advanced-python-wrapper
6
6
  License: Apache-2.0
@@ -15,12 +15,9 @@ Classifier: Programming Language :: Python :: 3
15
15
  Classifier: Programming Language :: Python :: 3.9
16
16
  Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
- Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Programming Language :: Python :: 3 :: Only
20
- Classifier: Programming Language :: Python :: 3.10
21
- Classifier: Programming Language :: Python :: 3.11
22
20
  Classifier: Programming Language :: Python :: 3.8
23
- Classifier: Programming Language :: Python :: 3.9
24
21
  Requires-Dist: aws-xray-sdk (>=2.13.1,<3.0.0)
25
22
  Requires-Dist: boto3 (>=1.34.111,<2.0.0)
26
23
  Requires-Dist: opentelemetry-api (>=1.22.0,<2.0.0)
@@ -83,10 +80,9 @@ with AwsWrapperConnection.connect(
83
80
  autocommit=True
84
81
  ) as awsconn:
85
82
  awscursor = awsconn.cursor()
86
- awscursor.execute("SELECT aurora_db_instance_identifier()")
87
- awscursor.fetchone()
88
- for record in awscursor:
89
- print(record)
83
+ awscursor.execute("SELECT pg_catalog.aurora_db_instance_identifier()")
84
+ row = awscursor.fetchone()
85
+ print(row)
90
86
  ```
91
87
  The `AwsWrapperConnection#connect` method accepts the connection configuration through both the connection string and the keyword arguments.
92
88
 
@@ -107,9 +103,8 @@ with AwsWrapperConnection.connect(
107
103
  ) as awsconn:
108
104
  awscursor = awsconn.cursor()
109
105
  awscursor.execute("SELECT @@aurora_server_id")
110
- awscursor.fetchone()
111
- for record in awscursor:
112
- print(record)
106
+ row = awscursor.fetchone()
107
+ print(row)
113
108
  ```
114
109
 
115
110
  For more details on how to download the AWS Advanced Python Driver, minimum requirements to use it,
@@ -155,6 +150,8 @@ The following table lists the connection properties used with the AWS Advanced P
155
150
  | `secrets_manager_secret_id` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
156
151
  | `secrets_manager_region` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
157
152
  | `secrets_manager_endpoint` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
153
+ | `secrets_manager_secret_username` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
154
+ | `secrets_manager_secret_password` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
158
155
  | `reader_host_selector_strategy` | [Connection Strategy](./docs/using-the-python-driver/using-plugins/UsingTheReadWriteSplittingPlugin.md#connection-strategies) |
159
156
  | `db_user` | [Federated Authentication Plugin](./docs/using-the-python-driver/using-plugins/UsingTheFederatedAuthenticationPlugin.md) |
160
157
  | `idp_username` | [Federated Authentication Plugin](./docs/using-the-python-driver/using-plugins/UsingTheFederatedAuthenticationPlugin.md) |
@@ -181,9 +178,13 @@ To find all the documentation and concrete examples on how to use the AWS Advanc
181
178
 
182
179
  #### Amazon RDS Blue/Green Deployments
183
180
 
184
- This driver currently does not support switchover in Amazon RDS Blue/Green Deployments. In order to execute a Blue/Green deployment with the driver,
185
- please ensure your application is coded to retry the database connection. Retry will allow the driver to re-establish a connection to an available
186
- database instance. Without a retry, the driver will not be able to identify an available database instance after blue/green switchover has occurred.
181
+ Support for Blue/Green deployments using the AWS Advanced Python Driver requires specific metadata tables. The following service versions provide support for Blue/Green Deployments:
182
+
183
+ - Supported RDS PostgreSQL Versions: `rds_tools v1.7 (17.1, 16.5, 15.9, 14.14, 13.17, 12.21)` and above.
184
+ - Supported Aurora PostgreSQL Versions: Engine Release `17.5, 16.9, 15.13, 14.18, 13.21` and above.
185
+ - Supported Aurora MySQL Versions: Engine Release `3.07` and above.
186
+
187
+ Please note that Aurora Global Database and RDS Multi-AZ clusters with Blue/Green deployments is currently not supported. For detailed information on supported database versions, refer to the [Blue/Green Deployment Plugin Documentation](./docs/using-the-python-driver/using-plugins/UsingTheBlueGreenPlugin.md).
187
188
 
188
189
  #### MySQL Connector/Python C Extension
189
190
 
@@ -236,7 +237,7 @@ For all other questions, please use [GitHub discussions](https://github.com/awsl
236
237
 
237
238
  1. Set up your environment by following the directions in the [Development Guide](./docs/development-guide/DevelopmentGuide.md).
238
239
  2. To contribute, first make a fork of this project.
239
- 3. Make any changes on your fork. Make sure you are aware of the requirements for the project (e.g. do not require Python 3.7 if we are supporting Python 3.8 and higher).
240
+ 3. Make any changes on your fork. Make sure you are aware of the requirements for the project (e.g. do not require Python 3.7 if we are supporting Python 3.8 - 3.11 (inclusive)).
240
241
  4. Create a pull request from your fork.
241
242
  5. Pull requests need to be approved and merged by maintainers into the main branch. <br />
242
243
 
@@ -48,10 +48,9 @@ with AwsWrapperConnection.connect(
48
48
  autocommit=True
49
49
  ) as awsconn:
50
50
  awscursor = awsconn.cursor()
51
- awscursor.execute("SELECT aurora_db_instance_identifier()")
52
- awscursor.fetchone()
53
- for record in awscursor:
54
- print(record)
51
+ awscursor.execute("SELECT pg_catalog.aurora_db_instance_identifier()")
52
+ row = awscursor.fetchone()
53
+ print(row)
55
54
  ```
56
55
  The `AwsWrapperConnection#connect` method accepts the connection configuration through both the connection string and the keyword arguments.
57
56
 
@@ -72,9 +71,8 @@ with AwsWrapperConnection.connect(
72
71
  ) as awsconn:
73
72
  awscursor = awsconn.cursor()
74
73
  awscursor.execute("SELECT @@aurora_server_id")
75
- awscursor.fetchone()
76
- for record in awscursor:
77
- print(record)
74
+ row = awscursor.fetchone()
75
+ print(row)
78
76
  ```
79
77
 
80
78
  For more details on how to download the AWS Advanced Python Driver, minimum requirements to use it,
@@ -120,6 +118,8 @@ The following table lists the connection properties used with the AWS Advanced P
120
118
  | `secrets_manager_secret_id` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
121
119
  | `secrets_manager_region` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
122
120
  | `secrets_manager_endpoint` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
121
+ | `secrets_manager_secret_username` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
122
+ | `secrets_manager_secret_password` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
123
123
  | `reader_host_selector_strategy` | [Connection Strategy](./docs/using-the-python-driver/using-plugins/UsingTheReadWriteSplittingPlugin.md#connection-strategies) |
124
124
  | `db_user` | [Federated Authentication Plugin](./docs/using-the-python-driver/using-plugins/UsingTheFederatedAuthenticationPlugin.md) |
125
125
  | `idp_username` | [Federated Authentication Plugin](./docs/using-the-python-driver/using-plugins/UsingTheFederatedAuthenticationPlugin.md) |
@@ -146,9 +146,13 @@ To find all the documentation and concrete examples on how to use the AWS Advanc
146
146
 
147
147
  #### Amazon RDS Blue/Green Deployments
148
148
 
149
- This driver currently does not support switchover in Amazon RDS Blue/Green Deployments. In order to execute a Blue/Green deployment with the driver,
150
- please ensure your application is coded to retry the database connection. Retry will allow the driver to re-establish a connection to an available
151
- database instance. Without a retry, the driver will not be able to identify an available database instance after blue/green switchover has occurred.
149
+ Support for Blue/Green deployments using the AWS Advanced Python Driver requires specific metadata tables. The following service versions provide support for Blue/Green Deployments:
150
+
151
+ - Supported RDS PostgreSQL Versions: `rds_tools v1.7 (17.1, 16.5, 15.9, 14.14, 13.17, 12.21)` and above.
152
+ - Supported Aurora PostgreSQL Versions: Engine Release `17.5, 16.9, 15.13, 14.18, 13.21` and above.
153
+ - Supported Aurora MySQL Versions: Engine Release `3.07` and above.
154
+
155
+ Please note that Aurora Global Database and RDS Multi-AZ clusters with Blue/Green deployments is currently not supported. For detailed information on supported database versions, refer to the [Blue/Green Deployment Plugin Documentation](./docs/using-the-python-driver/using-plugins/UsingTheBlueGreenPlugin.md).
152
156
 
153
157
  #### MySQL Connector/Python C Extension
154
158
 
@@ -201,7 +205,7 @@ For all other questions, please use [GitHub discussions](https://github.com/awsl
201
205
 
202
206
  1. Set up your environment by following the directions in the [Development Guide](./docs/development-guide/DevelopmentGuide.md).
203
207
  2. To contribute, first make a fork of this project.
204
- 3. Make any changes on your fork. Make sure you are aware of the requirements for the project (e.g. do not require Python 3.7 if we are supporting Python 3.8 and higher).
208
+ 3. Make any changes on your fork. Make sure you are aware of the requirements for the project (e.g. do not require Python 3.7 if we are supporting Python 3.8 - 3.11 (inclusive)).
205
209
  4. Create a pull request from your fork.
206
210
  5. Pull requests need to be approved and merged by maintainers into the main branch. <br />
207
211
 
@@ -173,19 +173,6 @@ class AuroraConnectionTrackerPlugin(Plugin):
173
173
  props: Properties,
174
174
  is_initial_connection: bool,
175
175
  connect_func: Callable) -> Connection:
176
- return self._connect(host_info, connect_func)
177
-
178
- def force_connect(
179
- self,
180
- target_driver_func: Callable,
181
- driver_dialect: DriverDialect,
182
- host_info: HostInfo,
183
- props: Properties,
184
- is_initial_connection: bool,
185
- force_connect_func: Callable) -> Connection:
186
- return self._connect(host_info, force_connect_func)
187
-
188
- def _connect(self, host_info: HostInfo, connect_func: Callable):
189
176
  conn = connect_func()
190
177
 
191
178
  if conn:
@@ -35,9 +35,7 @@ from aws_advanced_python_wrapper.utils.rdsutils import RdsUtils
35
35
 
36
36
 
37
37
  class AuroraInitialConnectionStrategyPlugin(Plugin):
38
- _SUBSCRIBED_METHODS: Set[str] = {"init_host_provider",
39
- "connect",
40
- "force_connect"}
38
+ _SUBSCRIBED_METHODS: Set[str] = {"init_host_provider", "connect"}
41
39
 
42
40
  _host_list_provider_service: Optional[HostListProviderService] = None
43
41
 
@@ -52,29 +50,24 @@ class AuroraInitialConnectionStrategyPlugin(Plugin):
52
50
 
53
51
  def connect(self, target_driver_func: Callable, driver_dialect: DriverDialect, host_info: HostInfo, props: Properties,
54
52
  is_initial_connection: bool, connect_func: Callable) -> Connection:
55
- return self._connect(host_info, props, is_initial_connection, connect_func)
56
-
57
- def force_connect(self, target_driver_func: Callable, driver_dialect: DriverDialect, host_info: HostInfo, props: Properties,
58
- is_initial_connection: bool, force_connect_func: Callable) -> Connection:
59
- return self._connect(host_info, props, is_initial_connection, force_connect_func)
60
-
61
- def _connect(self, host_info: HostInfo, props: Properties, is_initial_connection: bool, connect_func: Callable):
62
- type: RdsUrlType = self._rds_utils.identify_rds_type(host_info.host)
63
- if not type.is_rds_cluster:
53
+ url_type: RdsUrlType = self._rds_utils.identify_rds_type(host_info.host)
54
+ if not url_type.is_rds_cluster:
64
55
  return connect_func()
65
56
 
66
- if type == RdsUrlType.RDS_WRITER_CLUSTER:
57
+ if url_type == RdsUrlType.RDS_WRITER_CLUSTER:
67
58
  writer_candidate_conn: Optional[Connection] = self._get_verified_writer_connection(props, is_initial_connection, connect_func)
68
59
  if writer_candidate_conn is None:
69
60
  return connect_func()
70
61
  return writer_candidate_conn
71
62
 
72
- if type == RdsUrlType.RDS_READER_CLUSTER:
63
+ if url_type == RdsUrlType.RDS_READER_CLUSTER:
73
64
  reader_candidate_conn: Optional[Connection] = self._get_verified_reader_connection(props, is_initial_connection, connect_func)
74
65
  if reader_candidate_conn is None:
75
66
  return connect_func()
76
67
  return reader_candidate_conn
77
68
 
69
+ return connect_func()
70
+
78
71
  def _get_verified_writer_connection(self, props: Properties, is_initial_connection: bool, connect_func: Callable) -> Connection | None:
79
72
  retry_delay_ms: int = WrapperProperties.OPEN_CONNECTION_RETRY_INTERVAL_MS.get_int(props)
80
73
  end_time_nano = perf_counter_ns() + (WrapperProperties.OPEN_CONNECTION_RETRY_INTERVAL_MS.get_int(props) * 1000000)
@@ -84,7 +77,6 @@ class AuroraInitialConnectionStrategyPlugin(Plugin):
84
77
 
85
78
  while perf_counter_ns() < end_time_nano:
86
79
  writer_candidate_conn = None
87
- writer_candidate = None
88
80
 
89
81
  try:
90
82
  writer_candidate = self._get_writer()
@@ -94,7 +86,7 @@ class AuroraInitialConnectionStrategyPlugin(Plugin):
94
86
  self._plugin_service.force_refresh_host_list(writer_candidate_conn)
95
87
  writer_candidate = self._plugin_service.identify_connection(writer_candidate_conn)
96
88
 
97
- if writer_candidate is not None and writer_candidate.role != HostRole.WRITER:
89
+ if writer_candidate is None or writer_candidate.role != HostRole.WRITER:
98
90
  self._close_connection(writer_candidate_conn)
99
91
  self._delay(retry_delay_ms)
100
92
  continue
@@ -141,6 +133,11 @@ class AuroraInitialConnectionStrategyPlugin(Plugin):
141
133
  self._plugin_service.force_refresh_host_list(reader_candidate_conn)
142
134
  reader_candidate = self._plugin_service.identify_connection(reader_candidate_conn)
143
135
 
136
+ if reader_candidate is None:
137
+ self._close_connection(reader_candidate_conn)
138
+ self._delay(retry_delay_ms)
139
+ continue
140
+
144
141
  if reader_candidate is not None and reader_candidate.role != HostRole.READER:
145
142
  if self._has_no_readers():
146
143
  # Cluster has no readers. Simulate Aurora reader cluster endpoint logic and return the current writer connection.
@@ -17,11 +17,13 @@ from __future__ import annotations
17
17
  from json import JSONDecodeError, loads
18
18
  from re import search
19
19
  from types import SimpleNamespace
20
- from typing import TYPE_CHECKING, Callable, Dict, Optional, Set, Tuple
20
+ from typing import TYPE_CHECKING, Callable, Optional, Set, Tuple
21
21
 
22
22
  import boto3
23
23
  from botocore.exceptions import ClientError, EndpointConnectionError
24
24
 
25
+ from aws_advanced_python_wrapper.utils.cache_map import CacheMap
26
+
25
27
  if TYPE_CHECKING:
26
28
  from boto3 import Session
27
29
  from aws_advanced_python_wrapper.driver_dialect import DriverDialect
@@ -46,8 +48,10 @@ class AwsSecretsManagerPlugin(Plugin):
46
48
  _SUBSCRIBED_METHODS: Set[str] = {"connect", "force_connect"}
47
49
 
48
50
  _SECRETS_ARN_PATTERN = r"^arn:aws:secretsmanager:(?P<region>[^:\n]*):[^:\n]*:([^:/\n]*[:/])?(.*)$"
51
+ _ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365
49
52
 
50
- _secrets_cache: Dict[Tuple, SimpleNamespace] = {}
53
+ _secret: Optional[SimpleNamespace] = None
54
+ _secrets_cache: CacheMap[Tuple, SimpleNamespace] = CacheMap()
51
55
  _secret_key: Tuple = ()
52
56
 
53
57
  @property
@@ -94,7 +98,13 @@ class AwsSecretsManagerPlugin(Plugin):
94
98
  return self._connect(props, force_connect_func)
95
99
 
96
100
  def _connect(self, props: Properties, connect_func: Callable) -> Connection:
97
- secret_fetched: bool = self._update_secret()
101
+ token_expiration_sec: int = WrapperProperties.SECRETS_MANAGER_EXPIRATION.get_int(props)
102
+ # if value is less than 0, default to one year
103
+ if token_expiration_sec < 0:
104
+ token_expiration_sec = AwsSecretsManagerPlugin._ONE_YEAR_IN_SECONDS
105
+ token_expiration_ns = token_expiration_sec * 1_000_000_000
106
+
107
+ secret_fetched: bool = self._update_secret(token_expiration_ns=token_expiration_ns)
98
108
 
99
109
  try:
100
110
  self._apply_secret_to_properties(props)
@@ -105,7 +115,7 @@ class AwsSecretsManagerPlugin(Plugin):
105
115
  raise AwsWrapperError(
106
116
  Messages.get_formatted("AwsSecretsManagerPlugin.ConnectException", e)) from e
107
117
 
108
- secret_fetched = self._update_secret(True)
118
+ secret_fetched = self._update_secret(token_expiration_ns=token_expiration_ns, force_refetch=True)
109
119
 
110
120
  if secret_fetched:
111
121
  try:
@@ -117,9 +127,10 @@ class AwsSecretsManagerPlugin(Plugin):
117
127
  unhandled_error)) from unhandled_error
118
128
  raise AwsWrapperError(Messages.get_formatted("AwsSecretsManagerPlugin.FailedLogin", e)) from e
119
129
 
120
- def _update_secret(self, force_refetch: bool = False) -> bool:
130
+ def _update_secret(self, token_expiration_ns: int, force_refetch: bool = False) -> bool:
121
131
  """
122
132
  Called to update credentials from the cache, or from the AWS Secrets Manager service.
133
+ :param token_expiration_ns: Expiration time in nanoseconds for secret stored in cache.
123
134
  :param force_refetch: Allows ignoring cached credentials and force fetches the latest credentials from the service.
124
135
  :return: `True`, if credentials were fetched from the service.
125
136
  """
@@ -135,7 +146,7 @@ class AwsSecretsManagerPlugin(Plugin):
135
146
  try:
136
147
  self._secret = self._fetch_latest_credentials()
137
148
  if self._secret:
138
- AwsSecretsManagerPlugin._secrets_cache[self._secret_key] = self._secret
149
+ AwsSecretsManagerPlugin._secrets_cache.put(self._secret_key, self._secret, token_expiration_ns)
139
150
  fetched = True
140
151
  except (ClientError, AttributeError) as e:
141
152
  logger.debug("AwsSecretsManagerPlugin.FailedToFetchDbCredentials", e)
@@ -188,12 +199,15 @@ class AwsSecretsManagerPlugin(Plugin):
188
199
  """
189
200
  Updates credentials in provided properties. Other plugins in the plugin chain may change them if needed.
190
201
  Eventually, credentials will be used to open a new connection in :py:class:`DefaultConnectionPlugin`.
191
-
192
- :param properties: Properties to store credentials.
193
202
  """
194
203
  if self._secret:
195
- WrapperProperties.USER.set(properties, self._secret.username)
196
- WrapperProperties.PASSWORD.set(properties, self._secret.password)
204
+ username_key = WrapperProperties.SECRETS_MANAGER_SECRET_USERNAME_KEY.get(properties)
205
+ username_value = getattr(self._secret, str(username_key))
206
+ WrapperProperties.USER.set(properties, username_value)
207
+
208
+ password_key = WrapperProperties.SECRETS_MANAGER_SECRET_PASSWORD_KEY.get(properties)
209
+ password_value = getattr(self._secret, str(password_key))
210
+ WrapperProperties.PASSWORD.set(properties, password_value)
197
211
 
198
212
  def _get_rds_region(self, secret_id: str, props: Properties) -> str:
199
213
  session = self._session if self._session else boto3.Session()