Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 4 additions & 15 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,14 @@ jobs:
with:
python-version: "3.14"

- run: pip install nox coverage
- name: Install uv
uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1

- name: Checkout PR branch
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}

- name: Calculate PR code coverage
run: |
nox --sessions unit-3.14
coverage report --show-missing
export PR_COVER=$(coverage report | awk '$1 == "TOTAL" {print $NF+0}')
echo "PR_COVER=$PR_COVER" >> $GITHUB_ENV
coverage erase

- name: Verify code coverage. If your reading this and the step has failed, please add tests to cover your changes.
run: |
echo "PULL REQUEST CODE COVERAGE is ${{ env.PR_COVER }}%"
if [ "${{ env.PR_COVER }}" -lt "90" ]; then
exit 1;
fi
- name: Verify code coverage
run: ./scripts/coverage.sh
8 changes: 4 additions & 4 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ jobs:
with:
python-version: "3.14"

- name: Install nox
run: pip install nox
- name: Install uv
uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1

- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}

- name: Run nox lint session
run: nox -s lint
- name: Run lint
run: ./scripts/lint.sh
13 changes: 7 additions & 6 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install nox
run: pip install nox
- name: Install uv
uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1

- id: 'auth'
name: Authenticate to Google Cloud
Expand All @@ -66,7 +66,8 @@ jobs:
access_token_lifetime: 600s

- name: Run tests
run: nox -s unit-${{ matrix.python-version }}
shell: bash
run: ./scripts/test_unit.sh

- name: FlakyBot (Linux)
# only run flakybot on periodic (schedule) and continuous (push) events
Expand Down Expand Up @@ -118,8 +119,8 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install nox
run: pip install nox
- name: Install uv
uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1

- id: 'auth'
name: 'Authenticate to Google Cloud'
Expand Down Expand Up @@ -149,7 +150,7 @@ jobs:
ALLOYDB_INSTANCE_IP: '${{ steps.secrets.outputs.ALLOYDB_INSTANCE_IP }}'
ALLOYDB_INSTANCE_URI: '${{ steps.secrets.outputs.ALLOYDB_INSTANCE_URI }}'
ALLOYDB_PSC_INSTANCE_URI: '${{ steps.secrets.outputs.ALLOYDB_PSC_INSTANCE_URI }}'
run: nox -s system-${{ matrix.python-version }}
run: ./scripts/test_system.sh

- name: FlakyBot (Linux)
# only run flakybot on periodic (schedule) and continuous (push) events
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ docs.metadata

# Virtual environment
env/
.venv

# uv lock file (library — consumers resolve their own deps)
uv.lock

# Test logs
coverage.xml
Expand Down
11 changes: 9 additions & 2 deletions google/cloud/alloydbconnector/async_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,17 @@ def __init__(

# check if AsyncConnector is being initialized with event loop running
# Otherwise we will lazy init keys
self._keys: Optional[asyncio.Task] = None
try:
self._keys: Optional[asyncio.Task] = asyncio.create_task(generate_keys())
# Try to get the running loop before creating a task. The call here
# will raise a RuntimeError if no loop is running. Without calling
# get_running_loop, a direct call to create_task would also raise
# an exception but it would leak the generate_keys coroutine. To
# avoid leaking the coroutine, we call get_running_loop first.
asyncio.get_running_loop()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to call asyncio.get_running_loop() here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment just above to explain why. Short answer: prior to this change when an event loop was not running, we would be starting the generate_keys coroutine, but never await it and therefore leak it. The addition of get_running_loop ensures we never leak a coroutine.

self._keys = asyncio.create_task(generate_keys())
except RuntimeError:
self._keys = None
pass
self._client: Optional[AlloyDBClient] = None
self._closed = False

Expand Down
10 changes: 5 additions & 5 deletions google/cloud/alloydbconnector/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import logging
from typing import TYPE_CHECKING
from typing import Optional
from typing import Union

from cryptography import x509

Expand Down Expand Up @@ -95,7 +96,7 @@ def __init__(
# API, even from multiple threads, need to be made to a single-event
# loop. See https://github.com/GoogleCloudPlatform/alloydb-python-connector/issues/435
# for more details.
self._is_sync = False
self._client: Union[v1beta.AlloyDBAdminClient, v1beta.AlloyDBAdminAsyncClient]
if client:
self._client = client
elif driver == "pg8000" or driver == "psycopg":
Expand All @@ -110,7 +111,6 @@ def __init__(
user_agent=user_agent,
),
)
self._is_sync = True
else:
self._client = v1beta.AlloyDBAdminAsyncClient(
credentials=credentials,
Expand Down Expand Up @@ -163,7 +163,7 @@ async def _get_metadata(
)

req = v1beta.GetConnectionInfoRequest(parent=parent)
if self._is_sync:
if isinstance(self._client, v1beta.AlloyDBAdminClient):
resp = self._client.get_connection_info(request=req)
else:
resp = await self._client.get_connection_info(request=req)
Expand Down Expand Up @@ -213,11 +213,11 @@ async def _get_client_certificate(
public_key=pub_key,
use_metadata_exchange=self._use_metadata,
)
if self._is_sync:
if isinstance(self._client, v1beta.AlloyDBAdminClient):
resp = self._client.generate_client_certificate(request=req)
else:
resp = await self._client.generate_client_certificate(request=req)
return (resp.ca_cert, resp.pem_certificate_chain)
return (resp.ca_cert, list(resp.pem_certificate_chain))

async def get_connection_info(
self,
Expand Down
135 changes: 0 additions & 135 deletions noxfile.py

This file was deleted.

26 changes: 25 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,31 @@ pg8000 = ["pg8000>=1.31.1"]
asyncpg = ["asyncpg>=0.31.0"]
psycopg = ["psycopg>=3.1.0"]

[dependency-groups]
test = [
"asyncpg>=0.31.0",
"mock>=5.2.0",
"pg8000>=1.31.5",
"psycopg2-binary>=2.9.11",
"psycopg>=3.3.3",
"psycopg-binary>=3.3.3",
"pytest>=9.0.2",
"pytest-asyncio>=1.3.0",
"pytest-cov>=7.0.0",
"SQLAlchemy[asyncio]>=2.0.48",
"aioresponses>=0.7.8",
"coverage",
]
lint = [
"ruff==0.11.2",
"mypy",
"types-aiofiles",
"types-requests",
"build",
"twine",
{include-group = "test"},
]

[tool.setuptools.dynamic]
version = { attr = "google.cloud.alloydbconnector.version.__version__" }

Expand Down Expand Up @@ -98,7 +123,6 @@ ignore = [
]

[tool.ruff.lint.per-file-ignores]
"noxfile.py" = ["ANN"]
"tests/*" = ["ANN"]

[tool.ruff.lint.isort]
Expand Down
11 changes: 0 additions & 11 deletions requirements-test.txt

This file was deleted.

5 changes: 0 additions & 5 deletions requirements.txt

This file was deleted.

30 changes: 30 additions & 0 deletions scripts/coverage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Copyright 2026 Google LLC
#
# 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.

set -euo pipefail

uv run --group test \
coverage run \
--include="*/google/cloud/alloydbconnector/*.py" \
-m pytest -v tests/unit "$@"
uv run --group test coverage report --show-missing
PR_COVER=$(uv run --group test coverage report | awk '$1 == "TOTAL" {print $NF+0}')
uv run --group test coverage erase

echo "CODE COVERAGE is ${PR_COVER}%"
if [ "${PR_COVER}" -lt "90" ]; then
echo "Coverage below 90% threshold"
exit 1
fi
Loading
Loading