From 3d59cc65466565e3c08ece492fa82fb0cd108e8f Mon Sep 17 00:00:00 2001 From: karezche <64801825+karenc-bq@users.noreply.github.com> Date: Thu, 20 Aug 2026 17:04:12 -0700 Subject: [PATCH 1/2] chore: bump version to 3.1.0 and update changelog --- CHANGELOG.md | 17 ++++++++++++++++- Maintenance.md | 1 + aws_advanced_python_wrapper/driver_info.py | 2 +- tests/__init__.py | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eecf8e701..d4f211a76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,27 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/#semantic-versioning-200). -## [Unreleased] +## [3.1.0] - 2026-08-20 ### :magic_wand: Added * Python 3.14 support. ([PR #1252](https://github.com/aws/aws-advanced-python-wrapper/pull/1252)) +* Aurora Global Database support. Adds the `gdb_failover` plugin, which is aware of a home region and selects a failover target using the `failover_home_region`, `active_home_failover_mode` and `inactive_home_failover_mode` parameters, and the `gdb_rw` plugin, which restricts read/write splitting to the home region and can defer writes to Global Write Forwarding. Global writer endpoints are recognized, and cross-region topology is discovered through the `global-aurora-pg` / `global-aurora-mysql` dialects using `global_cluster_instance_host_patterns`. See [Aurora Global Databases](./docs/using-the-python-wrapper/GlobalDatabases.md). ([PR #1243](https://github.com/aws/aws-advanced-python-wrapper/pull/1243), [PR #1246](https://github.com/aws/aws-advanced-python-wrapper/pull/1246)) +* `gdb_accessible_regions`, restricting host selection to the AWS regions an application can reach, and `monitoring_connection_priority` / `gdb_monitoring_connection_priority`, controlling which host role or region the topology monitor uses for its background connection. Both are currently supported in the synchronous driver only. ([PR #1266](https://github.com/aws/aws-advanced-python-wrapper/pull/1266)) * Async (asyncio) counterpart of the wrapper (`aws_advanced_python_wrapper.aio`), targeting sync parity for the shipped plugins: failover v2, read/write splitting, EFM v2, IAM auth, AWS Secrets Manager, federated + Okta auth, Aurora connection tracker, cluster topology monitor, custom endpoint, stale DNS, Aurora initial connection strategy, simple read/write splitting, developer plugin, blue/green deployment, limitless, fastest-response strategy. Backed by psycopg async and aiomysql, with async SQLAlchemy support via `create_async_engine` (`postgresql+aws_wrapper_psycopg://` serves both sync and async; MySQL async uses `mysql+aws_wrapper_aiomysql://`). Includes `AsyncConnectionProvider`/`AsyncPooledConnectionProvider`, `AsyncSessionStateService`, an async IdP factory registry, and `release_resources_async()` for background-task teardown. ([PR #1257](https://github.com/aws/aws-advanced-python-wrapper/pull/1257)) ### :bug: Fixed * Cross-thread use-after-free (SIGSEGV) when an offloaded query times out (e.g. during failover) and the connection is later closed or reused while the query is still running: on timeout the driver dialects now shut down the connection socket and wait for the worker to unwind before propagating, and leak rather than close a connection whose worker cannot be drained. ([PR #1252](https://github.com/aws/aws-advanced-python-wrapper/pull/1252)) +* Schema-qualified every function, operator, cast and catalog reference in the PostgreSQL queries the driver issues internally, so a session `search_path` cannot redirect them. This covers the queries issued by the asynchronous Aurora host list provider as well. ([PR #1262](https://github.com/aws/aws-advanced-python-wrapper/pull/1262), [PR #1270](https://github.com/aws/aws-advanced-python-wrapper/pull/1270)) +* Connection properties whose name indicates a credential are now masked when connection properties are logged. Previously only `password` was masked, so properties such as `idp_password` and the `monitoring-` and `blue-green-monitoring-` prefixed passwords were logged in clear text. The Secrets Manager properties remain readable, since they identify a secret rather than hold one. ([PR #1270](https://github.com/aws/aws-advanced-python-wrapper/pull/1270)) +* `opentelemetry-api` is now declared as a runtime dependency rather than a development one. ([PR #1261](https://github.com/aws/aws-advanced-python-wrapper/pull/1261)) +* Query timeouts are now threaded through the failover paths, and pooled connections are invalidated in the Aurora connection tracker. ([PR #1255](https://github.com/aws/aws-advanced-python-wrapper/pull/1255)) +* `pool_pre_ping` is now supported in the SQLAlchemy ORM MySQL dialect. ([PR #1245](https://github.com/aws/aws-advanced-python-wrapper/pull/1245)) +* Six issues found during a synchronous/asynchronous parity review. ([PR #1256](https://github.com/aws/aws-advanced-python-wrapper/pull/1256)) +* Documentation corrections. ([PR #1244](https://github.com/aws/aws-advanced-python-wrapper/pull/1244)) +* Corrected documented examples that could not run as written: the plugin codes `failover2` and `efm2` (the registered codes are `failover_v2` and `host_monitoring_v2`), `dialect` in place of the `wrapper_dialect` parameter, and a MySQL Global Database chain containing `host_monitoring_v2`, which cannot be loaded on `mysql-connector-python`. Also documents the event loop requirement for asyncio on Windows, and notes that `gdb_accessible_regions` is currently supported in the synchronous driver only. ([PR #1270](https://github.com/aws/aws-advanced-python-wrapper/pull/1270)) + +### :cloud: Changed +* Reworked the Aurora initial connection strategy plugin. ([PR #1253](https://github.com/aws/aws-advanced-python-wrapper/pull/1253), [PR #1264](https://github.com/aws/aws-advanced-python-wrapper/pull/1264)) +* Updated the Community and Aurora database versions the test suite runs against. ([PR #1248](https://github.com/aws/aws-advanced-python-wrapper/pull/1248)) ## [3.0.0] - 2026-06-02 @@ -135,6 +149,7 @@ The Amazon Web Services (AWS) Advanced Python Wrapper allows an application to t * Support for PostgreSQL * Support for MySQL +[3.1.0]: https://github.com/aws/aws-advanced-python-wrapper/compare/3.0.0...3.1.0 [3.0.0]: https://github.com/aws/aws-advanced-python-wrapper/compare/2.1.0...3.0.0 [2.1.0]: https://github.com/aws/aws-advanced-python-wrapper/compare/2.0.0...2.1.0 [2.0.0]: https://github.com/aws/aws-advanced-python-wrapper/compare/1.4.0...2.0.0 diff --git a/Maintenance.md b/Maintenance.md index 9d60d748e..951f69095 100644 --- a/Maintenance.md +++ b/Maintenance.md @@ -11,6 +11,7 @@ | January 14, 2026 | [Release 2.0.0](https://github.com/aws/aws-advanced-python-wrapper/releases/tag/2.0.0) | | February 11, 2026 | [Release 2.1.0](https://github.com/aws/aws-advanced-python-wrapper/releases/tag/2.1.0) | | June 2, 2026 | [Release 3.0.0](https://github.com/aws/aws-advanced-python-wrapper/releases/tag/3.0.0) | +| August 20, 2026 | [Release 3.1.0](https://github.com/aws/aws-advanced-python-wrapper/releases/tag/3.1.0) | `aws-advanced-python-wrapper` [follows semver](https://semver.org/#semantic-versioning-200) which means we will only release breaking changes in major versions. Generally speaking patches will be released to fix existing problems without diff --git a/aws_advanced_python_wrapper/driver_info.py b/aws_advanced_python_wrapper/driver_info.py index b75c85abe..5f1d6d795 100644 --- a/aws_advanced_python_wrapper/driver_info.py +++ b/aws_advanced_python_wrapper/driver_info.py @@ -15,4 +15,4 @@ class DriverInfo: DRIVER_NAME = "aws_advanced_python_wrapper" - DRIVER_VERSION = "3.0.0" + DRIVER_VERSION = "3.1.0" diff --git a/tests/__init__.py b/tests/__init__.py index eb0620715..723749b4f 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "2.1.0" +__version__ = "3.1.0" From d23b2ebcee6847326d1718e150ff309b0d388bf3 Mon Sep 17 00:00:00 2001 From: karezche <64801825+karenc-bq@users.noreply.github.com> Date: Thu, 20 Aug 2026 17:32:12 -0700 Subject: [PATCH 2/2] chore: update release draft process to append rc to the release candidates, and update changelog --- .github/scripts/next_rc_number.py | 65 +++++++++++++++++++++++++++++ .github/workflows/draft_release.yml | 26 ++++++++++++ CHANGELOG.md | 13 +++++- Maintenance.md | 4 +- 4 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 .github/scripts/next_rc_number.py diff --git a/.github/scripts/next_rc_number.py b/.github/scripts/next_rc_number.py new file mode 100644 index 000000000..24d82f9cb --- /dev/null +++ b/.github/scripts/next_rc_number.py @@ -0,0 +1,65 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Print the next release-candidate number for a release version. + +Usage: python next_rc_number.py 3.1.0 + +The counter is read back from TestPyPI rather than kept as CI-side state, so it +starts at 1 for a release version that has no candidates yet and increments on +every re-cut. This uses the standard simple-index JSON API. + +Caveat: the index lists only the versions currently published, while the upload +API keeps every filename ever used permanently reserved. Deleting a candidate +release therefore frees its number here but not on the index, and the next +upload would be rejected. Leave published candidates in place. +""" + +import json +import re +import sys +import urllib.error +import urllib.request + +INDEX_URL = "https://test.pypi.org/simple/aws-advanced-python-wrapper/" +ACCEPT_HEADER = "application/vnd.pypi.simple.v1+json" +REQUEST_TIMEOUT_SEC = 30 + + +def next_rc_number(release_version: str, uploaded_versions: list[str]) -> int: + candidate_pattern = re.compile(re.escape(release_version) + r"rc(\d+)$") + matches = [candidate_pattern.match(version) for version in uploaded_versions] + used_numbers = [int(match.group(1)) for match in matches if match is not None] + return max(used_numbers) + 1 if used_numbers else 1 + + +def fetch_uploaded_versions() -> list[str]: + request = urllib.request.Request(INDEX_URL, headers={"Accept": ACCEPT_HEADER}) + try: + with urllib.request.urlopen(request, timeout=REQUEST_TIMEOUT_SEC) as response: + return json.load(response).get("versions", []) + except urllib.error.HTTPError as error: + if error.code != 404: + raise + return [] # The project has never been uploaded to TestPyPI. + + +def main() -> None: + if len(sys.argv) != 2: + raise SystemExit(f"usage: {sys.argv[0]} ") + print(next_rc_number(sys.argv[1], fetch_uploaded_versions())) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml index 703565928..e00f2a7d3 100644 --- a/.github/workflows/draft_release.yml +++ b/.github/workflows/draft_release.yml @@ -55,15 +55,41 @@ jobs: echo "$RELEASE_DETAILS" > RELEASE_DETAILS.md - name: 'Create a Package' run: poetry build + # The tag, the GitHub draft release, and the eventual PyPI release all keep + # the plain version. Only the TestPyPI upload carries an rc suffix, so a tag + # can be re-cut without colliding with an immutable TestPyPI filename. + # release.yml builds from the tag independently, so PyPI is unaffected. + - name: 'Build A Release Candidate For TestPyPI' + run: | + set -euo pipefail + # rc1 for the first candidate of a release version, then rc2, rc3, ... + # The counter is read back from TestPyPI so no state is carried between + # runs and a re-cut can never collide with an immutable filename. + RC_VERSION="${RELEASE_VERSION}rc$(python .github/scripts/next_rc_number.py "$RELEASE_VERSION")" + mv dist dist-release + poetry version "$RC_VERSION" + poetry build + mv dist dist-rc + mv dist-release dist + poetry version "$RELEASE_VERSION" + echo "Release candidate: pin testers to \`aws_advanced_python_wrapper==$RC_VERSION\`" >> $GITHUB_STEP_SUMMARY - name: 'Upload to TestPyPI' uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 with: repository-url: https://test.pypi.org/legacy/ + packages-dir: dist-rc - name: 'Create a Draft Release' if: always() uses: ncipollo/release-action@339a81892b84b4eeb0f6e744e4574d79d0d9b8dd # v1.21.0 with: draft: true + # Allow a tag to be re-cut: update the existing draft and replace its + # artifacts instead of failing because the release already exists. + allowUpdates: true + replacesArtifacts: true + # Never overwrite an already-published release: only a draft or + # prerelease may be updated in place. + updateOnlyUnreleased: true name: "AWS Advanced Python Wrapper - v${{ env.RELEASE_VERSION }}" bodyFile: RELEASE_DETAILS.md artifacts: ./dist/* diff --git a/CHANGELOG.md b/CHANGELOG.md index d4f211a76..233f27eb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/#semantic-versioning-200). -## [3.1.0] - 2026-08-20 +## [3.1.0] - 2026-08-24 ### :magic_wand: Added * Python 3.14 support. ([PR #1252](https://github.com/aws/aws-advanced-python-wrapper/pull/1252)) * Aurora Global Database support. Adds the `gdb_failover` plugin, which is aware of a home region and selects a failover target using the `failover_home_region`, `active_home_failover_mode` and `inactive_home_failover_mode` parameters, and the `gdb_rw` plugin, which restricts read/write splitting to the home region and can defer writes to Global Write Forwarding. Global writer endpoints are recognized, and cross-region topology is discovered through the `global-aurora-pg` / `global-aurora-mysql` dialects using `global_cluster_instance_host_patterns`. See [Aurora Global Databases](./docs/using-the-python-wrapper/GlobalDatabases.md). ([PR #1243](https://github.com/aws/aws-advanced-python-wrapper/pull/1243), [PR #1246](https://github.com/aws/aws-advanced-python-wrapper/pull/1246)) @@ -15,13 +15,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), * Schema-qualified every function, operator, cast and catalog reference in the PostgreSQL queries the driver issues internally, so a session `search_path` cannot redirect them. This covers the queries issued by the asynchronous Aurora host list provider as well. ([PR #1262](https://github.com/aws/aws-advanced-python-wrapper/pull/1262), [PR #1270](https://github.com/aws/aws-advanced-python-wrapper/pull/1270)) * Connection properties whose name indicates a credential are now masked when connection properties are logged. Previously only `password` was masked, so properties such as `idp_password` and the `monitoring-` and `blue-green-monitoring-` prefixed passwords were logged in clear text. The Secrets Manager properties remain readable, since they identify a secret rather than hold one. ([PR #1270](https://github.com/aws/aws-advanced-python-wrapper/pull/1270)) * `opentelemetry-api` is now declared as a runtime dependency rather than a development one. ([PR #1261](https://github.com/aws/aws-advanced-python-wrapper/pull/1261)) +* `boto3-stubs` and `types_aws_xray_sdk` are no longer declared as runtime dependencies. Both are type-stub distributions with no runtime effect, and declaring them meant their version ranges constrained applications that pin those packages themselves. ([PR #1274](https://github.com/aws/aws-advanced-python-wrapper/pull/1274)) +* `create_engine("postgresql+aws_wrapper_psycopg://")` now resolves. The PostgreSQL SQLAlchemy dialect entry point registered by 3.0.0 pointed at a module that was not present in the distribution, so constructing the engine raised `ModuleNotFoundError` before any connection was attempted. ([Issue #1260](https://github.com/aws/aws-advanced-python-wrapper/issues/1260), [Issue #1273](https://github.com/aws/aws-advanced-python-wrapper/issues/1273), [PR #1252](https://github.com/aws/aws-advanced-python-wrapper/pull/1252)) * Query timeouts are now threaded through the failover paths, and pooled connections are invalidated in the Aurora connection tracker. ([PR #1255](https://github.com/aws/aws-advanced-python-wrapper/pull/1255)) * `pool_pre_ping` is now supported in the SQLAlchemy ORM MySQL dialect. ([PR #1245](https://github.com/aws/aws-advanced-python-wrapper/pull/1245)) -* Six issues found during a synchronous/asynchronous parity review. ([PR #1256](https://github.com/aws/aws-advanced-python-wrapper/pull/1256)) +* Issues found while aligning the synchronous and asynchronous implementations ([PR #1256](https://github.com/aws/aws-advanced-python-wrapper/pull/1256)): + * The Aurora Initial Connection Strategy Plugin computed its retry deadline from `open_connection_retry_interval_ms` rather than `open_connection_retry_timeout_ms`, so it gave up retrying much earlier than configured. + * The Limitless Plugin discarded the result of its login-exception check, so an authentication failure while fetching transaction routers was never recognized as one. + * The Limitless Plugin did not read the connection from its routing context before using it. + * Resetting the session state transfer handler assigned to a name that did not exist, leaving a previously registered handler installed. + * A message key was raised in place of its resolved text when the current host could not be determined. + * Added two missing Blue/Green deployment log messages. * Documentation corrections. ([PR #1244](https://github.com/aws/aws-advanced-python-wrapper/pull/1244)) * Corrected documented examples that could not run as written: the plugin codes `failover2` and `efm2` (the registered codes are `failover_v2` and `host_monitoring_v2`), `dialect` in place of the `wrapper_dialect` parameter, and a MySQL Global Database chain containing `host_monitoring_v2`, which cannot be loaded on `mysql-connector-python`. Also documents the event loop requirement for asyncio on Windows, and notes that `gdb_accessible_regions` is currently supported in the synchronous driver only. ([PR #1270](https://github.com/aws/aws-advanced-python-wrapper/pull/1270)) ### :cloud: Changed +* The SQLAlchemy dialects moved to `aws_advanced_python_wrapper.sqlalchemy_dialects` and register as drivers under SQLAlchemy's existing dialects: `postgresql+aws_wrapper_psycopg://`, `mysql+aws_wrapper_mysqlconnector://` and `mysql+aws_wrapper_aiomysql://`. The URL driver names are unchanged, so URL-based and `creator=` configurations continue to work without modification. `aws_advanced_python_wrapper.sqlalchemy.mysql_orm_dialect.SqlAlchemyOrmMysqlDialect` remains importable as a deprecated alias for `sqlalchemy_dialects.mysql.AwsWrapperMySQLConnectorDialect` and will be removed in the next major version. Note that the replacement class does not inject a default `aurora_connection_tracker,failover_v2` plugin chain when `wrapper_plugins` is absent; the wrapper's own default chain applies instead, which for `mysql-connector-python` is `initial_connection,aurora_connection_tracker,failover_v2`. See [SQLAlchemy Support](./docs/using-the-python-wrapper/SqlAlchemySupport.md). ([PR #1274](https://github.com/aws/aws-advanced-python-wrapper/pull/1274)) * Reworked the Aurora initial connection strategy plugin. ([PR #1253](https://github.com/aws/aws-advanced-python-wrapper/pull/1253), [PR #1264](https://github.com/aws/aws-advanced-python-wrapper/pull/1264)) * Updated the Community and Aurora database versions the test suite runs against. ([PR #1248](https://github.com/aws/aws-advanced-python-wrapper/pull/1248)) diff --git a/Maintenance.md b/Maintenance.md index 951f69095..737d1653f 100644 --- a/Maintenance.md +++ b/Maintenance.md @@ -11,7 +11,7 @@ | January 14, 2026 | [Release 2.0.0](https://github.com/aws/aws-advanced-python-wrapper/releases/tag/2.0.0) | | February 11, 2026 | [Release 2.1.0](https://github.com/aws/aws-advanced-python-wrapper/releases/tag/2.1.0) | | June 2, 2026 | [Release 3.0.0](https://github.com/aws/aws-advanced-python-wrapper/releases/tag/3.0.0) | -| August 20, 2026 | [Release 3.1.0](https://github.com/aws/aws-advanced-python-wrapper/releases/tag/3.1.0) | +| August 24, 2026 | [Release 3.1.0](https://github.com/aws/aws-advanced-python-wrapper/releases/tag/3.1.0) | `aws-advanced-python-wrapper` [follows semver](https://semver.org/#semantic-versioning-200) which means we will only release breaking changes in major versions. Generally speaking patches will be released to fix existing problems without @@ -66,4 +66,4 @@ from the updated source after the PRs are merged. |---------------|----------------------|-------------|------------------|--------------------------|------------------------| | 1 | 1.4.0 | Maintenance | May 16, 2024 | January 14, 2026 | January 14, 2027 | | 2 | 2.1.0 | Maintenance | January 14, 2026 | June 2, 2026 | June 2, 2027 | -| 3 | 3.0.0 | Current | June 2, 2026 | N/A | N/A | +| 3 | 3.1.0 | Current | June 2, 2026 | N/A | N/A |