Compare commits

...
19 Commits
Author SHA1 Message Date
CI Bot 703bb9521f chore: release v0.5.1 [skip ci] 2026-07-07 19:37:22 +00:00
brian 8e47ebf4c6 Merge pull request '[patch] Fix MinIO get_object response leak in MinioAdapter.get()' (#32) from fix/minio-get-object-response-cleanup into main
Release on merge to main / release (push) Successful in 14s
Test Python Package / unit-tests (push) Successful in 15s
Code Quality Pipeline / code-quality (push) Successful in 47s
Test Python Package / integration-tests (push) Successful in 54s
Test Python Package / coverage-report (push) Successful in 15s
Reviewed-on: https://gitea.lille-vemmelund.dk/brian/python-repositories/pulls/32
2026-07-07 21:37:04 +02:00
Brian Bjarke JensenandCursor 9a800bf553 Fetch live PR title in pr-title-check CI workflow.
Code Quality Pipeline / code-quality (pull_request) Successful in 24s
Test Python Package / integration-tests (pull_request) Successful in 1m18s
Test Python Package / unit-tests (pull_request) Successful in 1m24s
Test Python Package / coverage-report (pull_request) Successful in 12s
PR Title Check / check-title (pull_request) Successful in 6s
Rerunning the job now reads the current title from the Gitea API instead of the stale pull_request event payload.

Co-authored-by: Cursor <[email protected]>
2026-07-07 21:34:18 +02:00
Brian Bjarke JensenandCursor 8c34534187 Fix MinIO get_object response leak in MinioAdapter.get().
Test Python Package / integration-tests (pull_request) Successful in 27s
Code Quality Pipeline / code-quality (pull_request) Successful in 31s
Test Python Package / unit-tests (pull_request) Successful in 36s
Test Python Package / coverage-report (pull_request) Successful in 53s
PR Title Check / check-title (pull_request) Failing after 5s
Close and release the HTTP response in a finally block per SDK guidance, and add unit tests for success and read-failure cleanup.

Co-authored-by: Cursor <[email protected]>
2026-07-07 21:21:42 +02:00
brian b1210bddf2 Merge pull request 'Reach 100% combined coverage with targeted unit tests' (#31) from cursor/balanced-100-coverage into main
Test Python Package / coverage-report (push) Successful in 45s
Test Python Package / unit-tests (push) Successful in 14s
Code Quality Pipeline / code-quality (push) Successful in 33s
Release on merge to main / release (push) Successful in 36s
Test Python Package / integration-tests (push) Successful in 23s
Reviewed-on: https://gitea.lille-vemmelund.dk/brian/python-repositories/pulls/31
2026-07-07 21:05:51 +02:00
Brian Bjarke JensenandCursor 39b104383c Fix mypy unreachable-code warning in minio reconnect test.
PR Title Check / check-title (pull_request) Successful in 7s
Test Python Package / coverage-report (pull_request) Successful in 12s
Code Quality Pipeline / code-quality (pull_request) Successful in 48s
Test Python Package / unit-tests (pull_request) Successful in 19s
Test Python Package / integration-tests (pull_request) Successful in 28s
Drop bucket_name assertions that mypy treated as always false after manually clearing _bucket_name.

Co-authored-by: Cursor <[email protected]>
2026-07-07 21:04:39 +02:00
Brian Bjarke JensenandCursor beb2b5128e Reach 100% combined coverage with targeted unit tests.
Code Quality Pipeline / code-quality (pull_request) Failing after 29s
Test Python Package / integration-tests (pull_request) Successful in 35s
Test Python Package / unit-tests (pull_request) Successful in 42s
PR Title Check / check-title (pull_request) Successful in 52s
Test Python Package / coverage-report (pull_request) Successful in 12s
Add fast unit tests for lazy-import helpers and injected-client connect paths that integration tests miss, and raise the coverage floor to 100%.

Co-authored-by: Cursor <[email protected]>
2026-07-07 21:01:03 +02:00
brian ce062be411 Merge pull request 'Enforce 90% combined coverage floor in CI' (#29) from cursor/enforce-coverage-floor into main
Release on merge to main / release (push) Successful in 5s
Test Python Package / unit-tests (push) Successful in 19s
Test Python Package / integration-tests (push) Successful in 25s
Code Quality Pipeline / code-quality (push) Successful in 48s
Test Python Package / coverage-report (push) Successful in 12s
Reviewed-on: https://gitea.lille-vemmelund.dk/brian/python-repositories/pulls/29
2026-07-07 20:41:44 +02:00
Brian Bjarke JensenandCursor a381d45650 Lower combined coverage floor from 95% to 90%.
PR Title Check / check-title (pull_request) Successful in 4s
Code Quality Pipeline / code-quality (pull_request) Successful in 24s
Test Python Package / unit-tests (pull_request) Successful in 36s
Test Python Package / integration-tests (pull_request) Successful in 48s
Test Python Package / coverage-report (pull_request) Successful in 12s
Update fail_under in pyproject.toml and the README to match.

Co-authored-by: Cursor <[email protected]>
2026-07-07 20:39:08 +02:00
Brian Bjarke JensenandCursor 5c8cd841b6 Document where combined coverage floor is enforced in CI.
Test Python Package / unit-tests (pull_request) Successful in 13s
Code Quality Pipeline / code-quality (pull_request) Successful in 26s
PR Title Check / check-title (pull_request) Successful in 6s
Test Python Package / integration-tests (pull_request) Successful in 1m7s
Test Python Package / coverage-report (pull_request) Failing after 15s
Clarify that unit and integration jobs skip the floor check because they only produce partial coverage.

Co-authored-by: Cursor <[email protected]>
2026-07-07 20:34:54 +02:00
Brian Bjarke JensenandCursor 34632980ba Skip coverage floor check in partial CI test jobs.
Code Quality Pipeline / code-quality (pull_request) Successful in 48s
Test Python Package / integration-tests (pull_request) Successful in 47s
Test Python Package / coverage-report (pull_request) Failing after 15s
PR Title Check / check-title (pull_request) Successful in 5s
Test Python Package / unit-tests (pull_request) Successful in 21s
Unit and integration jobs each produce partial coverage; pytest-cov reads fail_under from pyproject.toml unless overridden with --cov-fail-under=0.

Co-authored-by: Cursor <[email protected]>
2026-07-07 20:33:21 +02:00
Brian Bjarke JensenandCursor 5393efc6cd Enforce a 95% combined coverage floor in CI and local runs.
Test Python Package / unit-tests (pull_request) Failing after 56s
Code Quality Pipeline / code-quality (pull_request) Successful in 1m36s
Test Python Package / integration-tests (pull_request) Failing after 1m14s
Test Python Package / coverage-report (pull_request) Has been skipped
PR Title Check / check-title (pull_request) Successful in 35s
Configure fail_under in pyproject.toml and read it in the coverage-report workflow so the threshold stays in one place.

Co-authored-by: Cursor <[email protected]>
2026-07-07 20:27:39 +02:00
brian e39fc96ac1 Merge pull request 'Split CI into parallel unit, integration, and coverage report jobs' (#28) from cursor/split-ci-test-jobs into main
Code Quality Pipeline / code-quality (push) Successful in 23s
Test Python Package / coverage-report (push) Successful in 10s
Release on merge to main / release (push) Successful in 6s
Test Python Package / unit-tests (push) Successful in 13s
Test Python Package / integration-tests (push) Successful in 22s
Reviewed-on: https://gitea.lille-vemmelund.dk/brian/python-repositories/pulls/28
2026-07-07 19:37:27 +02:00
Brian Bjarke JensenandCursor c1f4826d78 Use christopherhx v4 artifact actions for parallel coverage merge.
PR Title Check / check-title (pull_request) Successful in 6s
Test Python Package / unit-tests (pull_request) Successful in 18s
Code Quality Pipeline / code-quality (pull_request) Successful in 24s
Test Python Package / integration-tests (pull_request) Successful in 46s
Test Python Package / coverage-report (pull_request) Successful in 16s
Restore per-job coverage uploads while keeping unit and integration jobs parallel on Gitea 1.26.

Co-authored-by: Cursor <[email protected]>
2026-07-07 19:35:19 +02:00
Brian Bjarke JensenandCursor 0315a33a3b Avoid cross-job artifacts; combine coverage with --cov-append.
PR Title Check / check-title (pull_request) Successful in 4s
Test Python Package / unit-tests (pull_request) Successful in 10s
Code Quality Pipeline / code-quality (pull_request) Successful in 24s
Test Python Package / integration-tests (pull_request) Successful in 20s
Test Python Package / coverage-report (pull_request) Successful in 24s
Gitea artifact download is unreliable with v3 actions, so the report job re-runs both suites on one runner after parallel test gates pass.

Co-authored-by: Cursor <[email protected]>
2026-07-07 19:27:26 +02:00
Brian Bjarke JensenandCursor 5d33ec6091 Use artifact action v3 for Gitea Actions compatibility.
PR Title Check / check-title (pull_request) Successful in 5s
Code Quality Pipeline / code-quality (pull_request) Successful in 24s
Test Python Package / unit-tests (pull_request) Successful in 22s
Test Python Package / integration-tests (pull_request) Successful in 32s
Test Python Package / coverage-report (pull_request) Failing after 3m18s
Gitea does not support upload-artifact/download-artifact v4 yet.

Co-authored-by: Cursor <[email protected]>
2026-07-07 19:17:57 +02:00
Brian Bjarke JensenandCursor 9538e4d26d Split CI into parallel unit, integration, and coverage report jobs.
Code Quality Pipeline / code-quality (pull_request) Successful in 32s
PR Title Check / check-title (pull_request) Successful in 6s
Test Python Package / unit-tests (pull_request) Successful in 1m28s
Test Python Package / integration-tests (pull_request) Successful in 56s
Test Python Package / coverage-report (pull_request) Failing after 11s
Run test jobs in parallel and merge coverage artifacts for an accurate full-suite PR report.

Co-authored-by: Cursor <[email protected]>
2026-07-06 22:02:35 +02:00
brian 14b8d2798c Merge pull request 'Replace hardcoded version examples in release docs' (#27) from cursor/fix-version-doc-drift into main
Test Python Package / test (push) Successful in 52s
Code Quality Pipeline / code-quality (push) Successful in 46s
Release on merge to main / release (push) Successful in 7s
Reviewed-on: https://gitea.lille-vemmelund.dk/brian/python-repositories/pulls/27
2026-07-06 21:37:34 +02:00
Brian Bjarke JensenandCursor d3cbb65bbc Use version-agnostic examples in release docs.
Code Quality Pipeline / code-quality (pull_request) Successful in 46s
PR Title Check / check-title (pull_request) Successful in 6s
Test Python Package / test (pull_request) Successful in 1m21s
Replace hardcoded semver examples with stable placeholders and point readers to pyproject.toml for the current version.

Co-authored-by: Cursor <[email protected]>
2026-07-06 21:25:50 +02:00
11 changed files with 301 additions and 14 deletions
+5 -3
View File
@@ -2,9 +2,11 @@
If this PR changes files under `python_repositories/`, the **title must** start with one of:
- `[patch]` or `[fix]` — bug fix (0.3.1 → 0.3.2)
- `[minor]` or `[feat]` — new feature (0.3.1 → 0.4.0)
- `[major]` or `[breaking]` — breaking change (0.3.1 → 1.0.0)
- `[patch]` or `[fix]` — bug fix (`1.2.3``1.2.4`)
- `[minor]` or `[feat]` — new feature (`1.2.3``1.3.0`)
- `[major]` or `[breaking]` — breaking change (`1.2.3``2.0.0`)
Current version: see [`pyproject.toml`](pyproject.toml) on `main`.
Docs-, CI-, or test-only PRs do not need a prefix.
+7 -1
View File
@@ -16,8 +16,14 @@ jobs:
- name: Check PR title when source files change
env:
PR_TITLE: ${{ github.event.pull_request.title }}
API_URL: ${{ vars.API_URL }}
REPO_OWNER: ${{ github.repository_owner }}
REPO_NAME: ${{ github.event.repository.name }}
PR_NUMBER: ${{ github.event.pull_request.number }}
CI_RUNNER_TOKEN: ${{ secrets.CI_RUNNER_TOKEN }}
run: |
git fetch origin "${{ github.base_ref }}"
PR_TITLE=$(scripts/ci/fetch-pr-title.sh)
echo "Live PR title: ${PR_TITLE}"
git diff --name-only "origin/${{ github.base_ref }}...HEAD" \
| scripts/ci/check-pr-title.sh "$PR_TITLE"
+108 -4
View File
@@ -7,7 +7,7 @@ on:
pull_request:
jobs:
test:
unit-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout code
@@ -26,10 +26,114 @@ jobs:
UV_LINK_MODE: copy
run: uv sync --all-extras
- name: Run pytest
- name: Run unit tests
run: |
# --cov-fail-under=0: partial coverage only; floor is checked in coverage-report.
uv run pytest tests/unit/ -m "not integration" \
--cov=python_repositories \
--cov-report= \
--cov-fail-under=0
- name: Upload unit coverage
uses: https://github.com/christopherHX/gitea-upload-artifact@v4
with:
name: coverage-unit
path: .coverage
retention-days: 1
compression-level: 0
integration-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version-file: .python-version
- name: Install uv
run: pip install uv
- name: Install dependencies
env:
PYTHONPATH: .
run: uv run pytest --cov=python_repositories --cov-report=term-missing > coverage.txt
UV_LINK_MODE: copy
run: uv sync --all-extras
- name: Verify Docker
run: docker info
- name: Run integration tests
run: |
# --cov-fail-under=0: partial coverage only; floor is checked in coverage-report.
uv run pytest -m integration \
--cov=python_repositories \
--cov-report= \
--cov-fail-under=0
- name: Upload integration coverage
uses: https://github.com/christopherHX/gitea-upload-artifact@v4
with:
name: coverage-integration
path: .coverage
retention-days: 1
compression-level: 0
coverage-report:
# Merges unit + integration coverage and enforces fail_under from pyproject.toml.
needs: [unit-tests, integration-tests]
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version-file: .python-version
- name: Install uv
run: pip install uv
- name: Install dependencies
env:
UV_LINK_MODE: copy
run: uv sync --all-extras
- name: Download unit coverage
uses: https://github.com/christopherHX/gitea-download-artifact@v4
with:
name: coverage-unit
path: coverage-unit
- name: Download integration coverage
uses: https://github.com/christopherHX/gitea-download-artifact@v4
with:
name: coverage-integration
path: coverage-integration
- name: Combine coverage report
run: |
# --fail-under=0 so the full report is always written before the floor check.
uv run coverage combine coverage-unit/.coverage coverage-integration/.coverage
uv run coverage report -m --include='python_repositories/*' --fail-under=0 > coverage.txt
- name: Show coverage report
run: cat coverage.txt
- name: Enforce coverage floor
run: |
# Reads fail_under from pyproject.toml; only combined coverage is evaluated here.
FAIL_UNDER=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['tool']['coverage']['report']['fail_under'])")
echo "Checking combined coverage against ${FAIL_UNDER}% floor..."
if uv run coverage report --fail-under="$FAIL_UNDER" --include='python_repositories/*'; then
echo "Coverage floor met."
else
echo "::error::Combined coverage is below the ${FAIL_UNDER}% floor"
exit 1
fi
- name: Post coverage summary to PR
if: github.event_name == 'pull_request'
+13 -4
View File
@@ -148,6 +148,15 @@ uv run pytest -v # full suite (requires Doc
Integration tests are marked with `@pytest.mark.integration` and require Docker (testcontainers). Run unit tests alone for quick local feedback.
CI runs unit and integration tests in parallel with coverage, then merges `.coverage` artifacts in a follow-up job (via [christopherhx/gitea-\*-artifact@v4](https://github.com/christopherHX/gitea-upload-artifact) for Gitea 1.26 compatibility). Combined coverage must be at least **90%**; the floor is set by [`fail_under` in `pyproject.toml`](pyproject.toml#L45-L48) and enforced after merging unit and integration coverage, not on unit-only runs.
To check coverage locally (requires Docker for the full suite):
```bash
uv run pytest --cov=python_repositories --cov-report=
uv run coverage report
```
`pre-commit` is included in the dev dependency group. `uv sync` installs the CLI, but git does not run hooks until you install them with `pre-commit install` (one time per clone). After that, commits run the checks defined in [`.pre-commit-config.yaml`](.pre-commit-config.yaml) (ruff, mypy, pyupgrade, prettier, and general file hygiene).
To run all hooks manually without committing:
@@ -173,9 +182,9 @@ Docs-, CI-, and test-only PRs do not need a prefix and will not trigger a releas
| Prefix | Bump | Example |
| ------------------------- | ---------- | --------------------- |
| `[patch]` or `[fix]` | patch | `0.3.1``0.3.2` |
| `[minor]` or `[feat]` | minor | `0.3.1``0.4.0` |
| `[major]` or `[breaking]` | major | `0.3.1``1.0.0` |
| `[patch]` or `[fix]` | patch | `1.2.3``1.2.4` |
| `[minor]` or `[feat]` | minor | `1.2.3``1.3.0` |
| `[major]` or `[breaking]` | major | `1.2.3``2.0.0` |
| _(none)_ | no release | docs / CI / deps only |
Example titles:
@@ -189,4 +198,4 @@ Release notes are generated from commits since the previous tag (see [`scripts/c
### Manual release
You can still push a `v*.*.*` tag manually; `publish.yml` will build and publish. The current baseline version is **0.3.1**.
You can still push a `v*.*.*` tag manually; `publish.yml` will build and publish. The current released version is in [`pyproject.toml`](pyproject.toml) (and on the latest `v*.*.*` tag).
+9 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "python-repositories"
version = "0.5.0"
version = "0.5.1"
description = "Various python repository interfaces exposed as a python package."
authors = [
{ name = "Brian Bjarke Jensen", email = "[email protected]" }
@@ -39,6 +39,14 @@ markers = [
"integration: tests requiring Docker containers (deselect with '-m \"not integration\"')",
]
[tool.coverage.run]
source = ["python_repositories"]
[tool.coverage.report]
fail_under = 100
show_missing = true
precision = 2
[tool.uv.sources]
python-utils = { index = "gitea" }
@@ -152,6 +152,7 @@ class MinioAdapter(ObjectRepositoryInterface, ConnectionAwareAdapter):
assert self._client is not None and self._bucket_name is not None
# Get data from bucket
# N.B. bucket name is set when connecting
response = None
try:
response = self._client.get_object(
bucket_name=self._bucket_name,
@@ -175,6 +176,10 @@ class MinioAdapter(ObjectRepositoryInterface, ConnectionAwareAdapter):
self.logger.error(repr(exc))
except Exception as exc: # pylint: disable=broad-except
self.logger.error(repr(exc))
finally:
if response is not None:
response.close()
response.release_conn()
return None
def delete(self, object_name: str) -> None:
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -euo pipefail
# Fetch the current PR title from the Gitea API.
# Requires: API_URL, REPO_OWNER, REPO_NAME, PR_NUMBER, CI_RUNNER_TOKEN
: "${API_URL:?API_URL is required}"
: "${REPO_OWNER:?REPO_OWNER is required}"
: "${REPO_NAME:?REPO_NAME is required}"
: "${PR_NUMBER:?PR_NUMBER is required}"
: "${CI_RUNNER_TOKEN:?CI_RUNNER_TOKEN is required}"
curl -sf \
"${API_URL}/repos/${REPO_OWNER}/${REPO_NAME}/pulls/${PR_NUMBER}" \
-H "Authorization: token ${CI_RUNNER_TOKEN}" \
| python3 -c 'import json, sys; print(json.load(sys.stdin)["title"])'
+21
View File
@@ -117,3 +117,24 @@ def test_adapters_subpackage_lazy_import_succeeds() -> None:
from python_repositories.adapters import RedisAdapter
assert RedisAdapter.__name__ == "RedisAdapter"
def test_adapters_dir_exposes_lazy_exports() -> None:
"""dir(adapters) includes lazy adapter names for tab completion."""
import python_repositories.adapters as adapters
assert {"RedisAdapter", "MinioAdapter"}.issubset(set(dir(adapters)))
def test_adapters_getattr_raises_for_unknown() -> None:
"""Unknown adapter names raise AttributeError."""
import python_repositories.adapters as adapters
with pytest.raises(AttributeError, match="has no attribute 'NoSuchAdapter'"):
_ = adapters.NoSuchAdapter
def test_top_level_dir_exposes_lazy_exports() -> None:
"""dir(python_repositories) includes lazy adapter names for tab completion."""
assert "RedisAdapter" in dir(python_repositories)
assert "MinioAdapter" in dir(python_repositories)
+71
View File
@@ -53,3 +53,74 @@ def test_raises_when_client_provided_without_config() -> None:
mock_client = MagicMock(spec=Minio)
with pytest.raises(ValueError, match="config is required"):
MinioAdapter(client=mock_client)
def test_connect_with_injected_client_succeeds() -> None:
mock_client = MagicMock(spec=Minio)
adapter = MinioAdapter(config=TEST_MINIO_CONFIG, client=mock_client)
adapter.connect()
mock_client.list_buckets.assert_called_once()
def test_connect_with_injected_client_raises_on_failure() -> None:
mock_client = MagicMock(spec=Minio)
mock_client.list_buckets.side_effect = Exception("connection lost")
adapter = MinioAdapter(config=TEST_MINIO_CONFIG, client=mock_client)
with pytest.raises(ConnectionError, match="Could not connect to Minio"):
adapter.connect()
def test_connect_disconnects_before_reconnect(
monkeypatch: pytest.MonkeyPatch,
) -> None:
stale_client = MagicMock(spec=Minio)
new_client = MagicMock(spec=Minio)
adapter = MinioAdapter(config=TEST_MINIO_CONFIG)
adapter._client = stale_client
adapter._bucket_name = None
monkeypatch.setattr(
"python_repositories.adapters.minio_adapter.minio.Minio",
lambda *args, **kwargs: new_client,
)
adapter.connect()
assert adapter._client is new_client
new_client.list_buckets.assert_called_once()
def test_get_closes_response_on_success() -> None:
"""get() must close and release the get_object HTTP response."""
mock_client = MagicMock(spec=Minio)
mock_client.bucket_exists.return_value = True
mock_response = MagicMock()
mock_response.read.side_effect = [b"data", b""]
mock_client.get_object.return_value = mock_response
adapter = MinioAdapter(config=TEST_MINIO_CONFIG, client=mock_client)
result = adapter.get("some-object")
assert result is not None
assert result.read() == b"data"
mock_response.close.assert_called_once()
mock_response.release_conn.assert_called_once()
def test_get_closes_response_when_read_fails() -> None:
"""get() must close and release the response even if read() raises."""
mock_client = MagicMock(spec=Minio)
mock_client.bucket_exists.return_value = True
mock_response = MagicMock()
mock_response.read.side_effect = OSError("connection reset")
mock_client.get_object.return_value = mock_response
adapter = MinioAdapter(config=TEST_MINIO_CONFIG, client=mock_client)
result = adapter.get("some-object")
assert result is None
mock_response.close.assert_called_once()
mock_response.release_conn.assert_called_once()
+45
View File
@@ -69,3 +69,48 @@ def test_subclass_custom_env_var_name(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("CUSTOM_REDIS_URI", "redis://custom:6379")
adapter = CustomEnvRedisAdapter()
assert adapter._config.uri == "redis://custom:6379"
def test_connect_with_injected_client_succeeds_when_ping_ok() -> None:
mock_client = MagicMock(spec=redis.Redis)
mock_client.ping.return_value = True
adapter = RedisAdapter(config=TEST_REDIS_CONFIG, client=mock_client)
adapter.connect()
mock_client.ping.assert_called_once()
def test_connect_with_injected_client_raises_when_ping_false() -> None:
mock_client = MagicMock(spec=redis.Redis)
mock_client.ping.return_value = False
adapter = RedisAdapter(config=TEST_REDIS_CONFIG, client=mock_client)
with pytest.raises(ConnectionError, match="Could not connect to Redis"):
adapter.connect()
def test_connect_with_injected_client_raises_on_redis_error() -> None:
mock_client = MagicMock(spec=redis.Redis)
mock_client.ping.side_effect = redis.ConnectionError("connection lost")
adapter = RedisAdapter(config=TEST_REDIS_CONFIG, client=mock_client)
with pytest.raises(ConnectionError, match="Could not connect to Redis"):
adapter.connect()
def test_connect_closes_existing_non_injected_client(
monkeypatch: pytest.MonkeyPatch,
) -> None:
stale_client = MagicMock(spec=redis.Redis)
new_client = MagicMock(spec=redis.Redis)
new_client.ping.return_value = True
adapter = RedisAdapter(config=TEST_REDIS_CONFIG)
adapter._client = stale_client
monkeypatch.setattr("redis.Redis.from_url", lambda *args, **kwargs: new_client)
adapter.connect()
stale_client.close.assert_called_once()
assert adapter._client is new_client
Generated
+1 -1
View File
@@ -1056,7 +1056,7 @@ wheels = [
[[package]]
name = "python-repositories"
version = "0.5.0"
version = "0.5.1"
source = { editable = "." }
dependencies = [
{ name = "python-dotenv" },