Compare commits
20
Commits
49b6238b7d
...
v2.0.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f7b67203a | ||
|
|
a27e9e5763 | ||
|
|
fd0045d3e0 | ||
|
|
515f4bbeae | ||
|
|
ef31fb4b4e | ||
|
|
707f11f578 | ||
|
|
b1d34f8f0f | ||
|
|
565879dd52 | ||
|
|
0d0f430f6f | ||
|
|
5ac40b1ba5 | ||
|
|
fa4ff1f03c | ||
|
|
0a39151ba0 | ||
|
|
82a702db0c | ||
|
|
b886a7c147 | ||
|
|
4518a93a3a | ||
|
|
a8b7b59484 | ||
|
|
0e6941dccf | ||
|
|
a6428ccd29 | ||
|
|
655fdc4ee8 | ||
|
|
e031c549e5 |
@@ -17,7 +17,7 @@ on:
|
|||||||
env:
|
env:
|
||||||
REGISTRY: gitea.lille-vemmelund.dk
|
REGISTRY: gitea.lille-vemmelund.dk
|
||||||
REGISTRY_USER: ci-bot
|
REGISTRY_USER: ci-bot
|
||||||
IMAGE: gitea.lille-vemmelund.dk/lille-vemmelund/python-repositories-ci
|
IMAGE: gitea.lille-vemmelund.dk/lillevemmelund/python-repositories-ci
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-and-push:
|
||||||
|
|||||||
@@ -8,23 +8,17 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
code-quality:
|
code-quality:
|
||||||
runs-on: ubuntu-latest
|
runs-on: python-repositories-ci
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Sync dependencies
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version-file: .python-version
|
|
||||||
|
|
||||||
- name: Install uv
|
|
||||||
run: pip install uv
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
env:
|
env:
|
||||||
UV_LINK_MODE: copy
|
UV_LINK_MODE: copy
|
||||||
run: uv sync --all-extras
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
run: uv sync --all-extras --frozen
|
||||||
|
|
||||||
- name: Type check with mypy
|
- name: Type check with mypy
|
||||||
run: uv run mypy .
|
run: uv run mypy .
|
||||||
|
|||||||
@@ -7,24 +7,45 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-check:
|
update-check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: python-repositories-ci
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CI_RUNNER_TOKEN }}
|
token: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Sync dependencies
|
||||||
uses: actions/setup-python@v5
|
env:
|
||||||
with:
|
UV_LINK_MODE: copy
|
||||||
python-version-file: .python-version
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
- name: Install uv
|
run: uv sync --all-extras
|
||||||
run: pip install uv
|
|
||||||
|
|
||||||
- name: Upgrade dependencies
|
- name: Upgrade dependencies
|
||||||
|
env:
|
||||||
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
run: uv lock --upgrade
|
run: uv lock --upgrade
|
||||||
|
|
||||||
|
- name: Update pre-commit hook revs
|
||||||
|
env:
|
||||||
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
run: uv run pre-commit autoupdate
|
||||||
|
|
||||||
|
- name: Sync upgraded dependencies
|
||||||
|
env:
|
||||||
|
UV_LINK_MODE: copy
|
||||||
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
run: uv sync --all-extras
|
||||||
|
|
||||||
|
- name: Smoke check
|
||||||
|
run: |
|
||||||
|
uv run ruff check .
|
||||||
|
uv run ruff format --check .
|
||||||
|
uv run mypy .
|
||||||
|
|
||||||
- name: Commit and push changes
|
- name: Commit and push changes
|
||||||
env:
|
env:
|
||||||
API_URL: ${{ vars.API_URL }}
|
API_URL: ${{ vars.API_URL }}
|
||||||
|
|||||||
@@ -9,25 +9,24 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-publish:
|
build-and-publish:
|
||||||
runs-on: ubuntu-latest
|
runs-on: python-repositories-ci
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
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: Update version in pyproject.toml to match tag
|
- name: Update version in pyproject.toml to match tag
|
||||||
|
env:
|
||||||
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
run: scripts/ci/bump-version.sh --from-tag "${GITHUB_REF##*/}"
|
run: scripts/ci/bump-version.sh --from-tag "${GITHUB_REF##*/}"
|
||||||
|
|
||||||
- name: Build package
|
- name: Build package
|
||||||
|
env:
|
||||||
|
UV_LINK_MODE: copy
|
||||||
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
uv sync --no-dev
|
uv sync --no-dev --frozen
|
||||||
uv build
|
uv build
|
||||||
|
|
||||||
- name: Publish to Gitea Package Registry
|
- name: Publish to Gitea Package Registry
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
|
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: python-repositories-ci
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -22,19 +22,12 @@ jobs:
|
|||||||
COMMIT_MSG: ${{ github.event.head_commit.message }}
|
COMMIT_MSG: ${{ github.event.head_commit.message }}
|
||||||
run: scripts/ci/parse-merge-commit.sh "$COMMIT_MSG"
|
run: scripts/ci/parse-merge-commit.sh "$COMMIT_MSG"
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
if: steps.meta.outputs.bump != 'skip'
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version-file: .python-version
|
|
||||||
|
|
||||||
- name: Install uv
|
|
||||||
if: steps.meta.outputs.bump != 'skip'
|
|
||||||
run: pip install uv
|
|
||||||
|
|
||||||
- name: Bump version
|
- name: Bump version
|
||||||
if: steps.meta.outputs.bump != 'skip'
|
if: steps.meta.outputs.bump != 'skip'
|
||||||
id: bump
|
id: bump
|
||||||
|
env:
|
||||||
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
run: scripts/ci/bump-version.sh "${{ steps.meta.outputs.bump }}"
|
run: scripts/ci/bump-version.sh "${{ steps.meta.outputs.bump }}"
|
||||||
|
|
||||||
- name: Generate release notes
|
- name: Generate release notes
|
||||||
@@ -81,3 +74,23 @@ jobs:
|
|||||||
-H "Authorization: token ${CI_RUNNER_TOKEN}" \
|
-H "Authorization: token ${CI_RUNNER_TOKEN}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d "$PAYLOAD"
|
-d "$PAYLOAD"
|
||||||
|
|
||||||
|
# Publish here instead of relying on publish.yml tag trigger: release commits use
|
||||||
|
# [skip ci], which suppresses tag-push workflows, and Gitea does not emit release
|
||||||
|
# events for releases created by the CI bot account.
|
||||||
|
- name: Build package
|
||||||
|
if: steps.meta.outputs.bump != 'skip'
|
||||||
|
env:
|
||||||
|
UV_LINK_MODE: copy
|
||||||
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
run: |
|
||||||
|
uv sync --no-dev --frozen
|
||||||
|
uv build
|
||||||
|
|
||||||
|
- name: Publish to Gitea Package Registry
|
||||||
|
if: steps.meta.outputs.bump != 'skip'
|
||||||
|
env:
|
||||||
|
UV_PUBLISH_TOKEN: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
UV_PUBLISH_URL: ${{ vars.REPOSITORY_URL }}
|
||||||
|
run: uv publish
|
||||||
|
|||||||
@@ -7,23 +7,17 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
safety:
|
safety:
|
||||||
runs-on: ubuntu-latest
|
runs-on: python-repositories-ci
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Sync dependencies
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version-file: .python-version
|
|
||||||
|
|
||||||
- name: Install uv
|
|
||||||
run: pip install uv
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
env:
|
env:
|
||||||
UV_LINK_MODE: copy
|
UV_LINK_MODE: copy
|
||||||
run: uv sync
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
run: uv sync --all-extras --frozen
|
||||||
|
|
||||||
- name: Run safety check
|
- name: Run safety check
|
||||||
run: uv run safety check
|
run: uv run safety check
|
||||||
|
|||||||
+15
-33
@@ -8,23 +8,17 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
unit-tests:
|
unit-tests:
|
||||||
runs-on: ubuntu-latest
|
runs-on: python-repositories-ci
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Sync dependencies
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version-file: .python-version
|
|
||||||
|
|
||||||
- name: Install uv
|
|
||||||
run: pip install uv
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
env:
|
env:
|
||||||
UV_LINK_MODE: copy
|
UV_LINK_MODE: copy
|
||||||
run: uv sync --all-extras
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
run: uv sync --all-extras --frozen
|
||||||
|
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: |
|
run: |
|
||||||
@@ -43,23 +37,17 @@ jobs:
|
|||||||
compression-level: 0
|
compression-level: 0
|
||||||
|
|
||||||
integration-tests:
|
integration-tests:
|
||||||
runs-on: ubuntu-latest
|
runs-on: python-repositories-ci
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Sync dependencies
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version-file: .python-version
|
|
||||||
|
|
||||||
- name: Install uv
|
|
||||||
run: pip install uv
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
env:
|
env:
|
||||||
UV_LINK_MODE: copy
|
UV_LINK_MODE: copy
|
||||||
run: uv sync --all-extras
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
run: uv sync --all-extras --frozen
|
||||||
|
|
||||||
- name: Verify Docker
|
- name: Verify Docker
|
||||||
run: docker info
|
run: docker info
|
||||||
@@ -83,24 +71,18 @@ jobs:
|
|||||||
coverage-report:
|
coverage-report:
|
||||||
# Merges unit + integration coverage and enforces fail_under from pyproject.toml.
|
# Merges unit + integration coverage and enforces fail_under from pyproject.toml.
|
||||||
needs: [unit-tests, integration-tests]
|
needs: [unit-tests, integration-tests]
|
||||||
runs-on: ubuntu-latest
|
runs-on: python-repositories-ci
|
||||||
if: github.event_name == 'pull_request' || github.event_name == 'push'
|
if: github.event_name == 'pull_request' || github.event_name == 'push'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Sync dependencies
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version-file: .python-version
|
|
||||||
|
|
||||||
- name: Install uv
|
|
||||||
run: pip install uv
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
env:
|
env:
|
||||||
UV_LINK_MODE: copy
|
UV_LINK_MODE: copy
|
||||||
run: uv sync --all-extras
|
UV_INDEX_GITEA_USERNAME: ci-bot
|
||||||
|
UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
run: uv sync --all-extras --frozen
|
||||||
|
|
||||||
- name: Download unit coverage
|
- name: Download unit coverage
|
||||||
uses: https://github.com/christopherHX/gitea-download-artifact@v4
|
uses: https://github.com/christopherHX/gitea-download-artifact@v4
|
||||||
|
|||||||
+19
-17
@@ -11,28 +11,30 @@ repos:
|
|||||||
- id: name-tests-test
|
- id: name-tests-test
|
||||||
- id: check-merge-conflict
|
- id: check-merge-conflict
|
||||||
|
|
||||||
# Python linting and formatting with Ruff
|
# Python tooling via uv (versions pinned in uv.lock)
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: local
|
||||||
rev: v0.12.8
|
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff-check
|
- id: ruff-check
|
||||||
args: [--fix]
|
name: ruff check
|
||||||
|
entry: uv run ruff check --fix
|
||||||
|
language: system
|
||||||
|
types: [python]
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
|
name: ruff format
|
||||||
# Static type checking with mypy
|
entry: uv run ruff format
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
language: system
|
||||||
rev: v1.8.0
|
types: [python]
|
||||||
hooks:
|
|
||||||
- id: mypy
|
- id: mypy
|
||||||
additional_dependencies:
|
name: mypy
|
||||||
- types-redis
|
entry: uv run mypy .
|
||||||
|
language: system
|
||||||
# Python syntax modernization with pyupgrade
|
types: [python]
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
pass_filenames: false
|
||||||
rev: v3.20.0
|
|
||||||
hooks:
|
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: ["--py312-plus"]
|
name: pyupgrade
|
||||||
|
entry: uv run pyupgrade --py312-plus
|
||||||
|
language: system
|
||||||
|
types: [python]
|
||||||
|
|
||||||
# Formatting for Markdown, JSON, and YAML with Prettier
|
# Formatting for Markdown, JSON, and YAML with Prettier
|
||||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||||
|
|||||||
@@ -198,8 +198,8 @@ Releases are automated when a pull request is merged to `main`. CI reads the **m
|
|||||||
|
|
||||||
1. Open a PR targeting `main` (see [`.gitea/PULL_REQUEST_TEMPLATE.md`](.gitea/PULL_REQUEST_TEMPLATE.md)).
|
1. Open a PR targeting `main` (see [`.gitea/PULL_REQUEST_TEMPLATE.md`](.gitea/PULL_REQUEST_TEMPLATE.md)).
|
||||||
2. If the PR changes files under `python_repositories/`, the title **must** start with a version bump prefix (enforced by CI).
|
2. If the PR changes files under `python_repositories/`, the title **must** start with a version bump prefix (enforced by CI).
|
||||||
3. On merge, [`release.yml`](.gitea/workflows/release.yml) bumps [`pyproject.toml`](pyproject.toml) and syncs [`uv.lock`](uv.lock), commits, tags `vX.Y.Z`, creates a Gitea release with auto-generated notes, and pushes the tag.
|
3. On merge, [`release.yml`](.gitea/workflows/release.yml) bumps [`pyproject.toml`](pyproject.toml) and syncs [`uv.lock`](uv.lock), commits, tags `vX.Y.Z`, creates a Gitea release with auto-generated notes, pushes the tag, and publishes the package to the Gitea Package Registry.
|
||||||
4. [`publish.yml`](.gitea/workflows/publish.yml) builds and publishes the package to the Gitea Package Registry.
|
4. [`publish.yml`](.gitea/workflows/publish.yml) handles manual `v*.*.*` tag pushes only (automated releases publish from `release.yml` because release commits use `[skip ci]`, which suppresses tag-push workflows).
|
||||||
|
|
||||||
Docs-, CI-, and test-only PRs do not need a prefix and will not trigger a release.
|
Docs-, CI-, and test-only PRs do not need a prefix and will not trigger a release.
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -14,10 +14,10 @@ Built from [`docker/ci/Dockerfile`](../docker/ci/Dockerfile):
|
|||||||
- Docker CLI (integration tests via testcontainers)
|
- Docker CLI (integration tests via testcontainers)
|
||||||
- Dev dependencies from `uv.lock` (`uv sync --all-extras --no-install-project`)
|
- Dev dependencies from `uv.lock` (`uv sync --all-extras --no-install-project`)
|
||||||
|
|
||||||
Published to the Gitea container registry:
|
Published to the Gitea container registry (owner segment must be lowercase for Docker):
|
||||||
|
|
||||||
- `gitea.lille-vemmelund.dk/lille-vemmelund/python-repositories-ci:latest`
|
- `gitea.lille-vemmelund.dk/lillevemmelund/python-repositories-ci:latest`
|
||||||
- `gitea.lille-vemmelund.dk/lille-vemmelund/python-repositories-ci:YYYYMMDDHHmm` (timestamped rollback tag)
|
- `gitea.lille-vemmelund.dk/lillevemmelund/python-repositories-ci:YYYYMMDDHHmm` (timestamped rollback tag)
|
||||||
|
|
||||||
## Rebuild triggers
|
## Rebuild triggers
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ homelab-platform
|
|||||||
[`platform/gitea-runners/values.yaml`](https://gitea.lille-vemmelund.dk/LilleVemmelund/homelab-platform/src/branch/main/platform/gitea-runners/values.yaml):
|
[`platform/gitea-runners/values.yaml`](https://gitea.lille-vemmelund.dk/LilleVemmelund/homelab-platform/src/branch/main/platform/gitea-runners/values.yaml):
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
python-repositories-ci:docker://gitea.lille-vemmelund.dk/lille-vemmelund/python-repositories-ci:latest
|
python-repositories-ci:docker://gitea.lille-vemmelund.dk/lillevemmelund/python-repositories-ci:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
After label changes, roll runner pods so they re-register with Gitea.
|
After label changes, roll runner pods so they re-register with Gitea.
|
||||||
@@ -137,7 +137,7 @@ bash scripts/ci/build-ci-image.sh --push
|
|||||||
```
|
```
|
||||||
|
|
||||||
Run from the repo root on the branch you want to test. Runners pull
|
Run from the repo root on the branch you want to test. Runners pull
|
||||||
`gitea.lille-vemmelund.dk/lille-vemmelund/python-repositories-ci:latest` from the registry;
|
`gitea.lille-vemmelund.dk/lillevemmelund/python-repositories-ci:latest` from the registry;
|
||||||
they do not care which git branch built it.
|
they do not care which git branch built it.
|
||||||
|
|
||||||
Override registry settings if needed:
|
Override registry settings if needed:
|
||||||
|
|||||||
+17
-5
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "python-repositories"
|
name = "python-repositories"
|
||||||
version = "2.0.2"
|
version = "2.0.4"
|
||||||
description = "Various python repository interfaces exposed as a python package."
|
description = "Various python repository interfaces exposed as a python package."
|
||||||
authors = [
|
authors = [
|
||||||
{ name = "Brian Bjarke Jensen", email = "schnitzelen@gmail.com" }
|
{ name = "Brian Bjarke Jensen", email = "schnitzelen@gmail.com" }
|
||||||
@@ -60,6 +60,18 @@ name = "gitea"
|
|||||||
url = "https://gitea.lille-vemmelund.dk/api/packages/brian/pypi/simple/"
|
url = "https://gitea.lille-vemmelund.dk/api/packages/brian/pypi/simple/"
|
||||||
explicit = true
|
explicit = true
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 88
|
||||||
|
target-version = "py312"
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
extend-select = ["I"]
|
||||||
|
|
||||||
|
[tool.ruff.lint.isort]
|
||||||
|
known-first-party = ["python_repositories", "tests"]
|
||||||
|
combine-as-imports = true
|
||||||
|
force-sort-within-sections = true
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
python_version = "3.12"
|
python_version = "3.12"
|
||||||
warn_return_any = true # nudge to use stricter types
|
warn_return_any = true # nudge to use stricter types
|
||||||
@@ -87,12 +99,12 @@ ignore_missing_imports = true
|
|||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
"mypy>=1.17.1",
|
"mypy>=2.1.0",
|
||||||
"pre-commit>=4.3.0",
|
"pre-commit>=4.6.0",
|
||||||
"pytest>=8.4.1",
|
"pytest>=8.4.1",
|
||||||
"pytest-cov>=7.0.0",
|
"pytest-cov>=7.0.0",
|
||||||
"pyupgrade>=3.20.0",
|
"pyupgrade>=3.21.2",
|
||||||
"ruff>=0.12.11",
|
"ruff>=0.15.20",
|
||||||
"safety>=3.6.0",
|
"safety>=3.6.0",
|
||||||
"testcontainers>=4.13.0",
|
"testcontainers>=4.13.0",
|
||||||
"types-redis>=4.6.0.20241004",
|
"types-redis>=4.6.0.20241004",
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import time
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
import time
|
||||||
from typing import Self
|
from typing import Self
|
||||||
|
|
||||||
import structlog
|
import structlog
|
||||||
@@ -73,7 +73,7 @@ class ConnectionAwareAdapter(ConnectionAwareInterface, ContextAwareInterface):
|
|||||||
self._invalidate_health_cache()
|
self._invalidate_health_cache()
|
||||||
return
|
return
|
||||||
if self._is_client_ready() and self.is_connected():
|
if self._is_client_ready() and self.is_connected():
|
||||||
self.logger.info(f"Already connected to {self.connection_name}")
|
self.logger.info("Already connected", connection_name=self.connection_name)
|
||||||
return
|
return
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
self._establish_connection()
|
self._establish_connection()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""Definition of MinioAdapter class."""
|
"""Definition of MinioAdapter class."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from python_repositories.adapters.connection_aware_adapter import (
|
from python_repositories.adapters.connection_aware_adapter import (
|
||||||
@@ -88,7 +89,7 @@ class MinioAdapter(ObjectRepositoryInterface, ConnectionAwareAdapter):
|
|||||||
raise ConnectionError(
|
raise ConnectionError(
|
||||||
f"Bucket '{bucket}' does not exist on Minio at {endpoint}"
|
f"Bucket '{bucket}' does not exist on Minio at {endpoint}"
|
||||||
)
|
)
|
||||||
self.logger.info(f"Creating bucket '{bucket}'")
|
self.logger.info("Creating bucket", bucket=bucket)
|
||||||
client.make_bucket(bucket)
|
client.make_bucket(bucket)
|
||||||
self._client = client
|
self._client = client
|
||||||
self._bucket_name = bucket
|
self._bucket_name = bucket
|
||||||
@@ -138,7 +139,7 @@ class MinioAdapter(ObjectRepositoryInterface, ConnectionAwareAdapter):
|
|||||||
content_type=content_type,
|
content_type=content_type,
|
||||||
)
|
)
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
f"Put object '{object_name}' into bucket '{self._bucket_name}'"
|
"Put object", object_name=object_name, bucket=self._bucket_name
|
||||||
)
|
)
|
||||||
|
|
||||||
def get(self, object_name: str) -> BytesIO | None:
|
def get(self, object_name: str) -> BytesIO | None:
|
||||||
@@ -163,13 +164,15 @@ class MinioAdapter(ObjectRepositoryInterface, ConnectionAwareAdapter):
|
|||||||
buffer.write(chunk)
|
buffer.write(chunk)
|
||||||
buffer.seek(0)
|
buffer.seek(0)
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
f"Got object '{object_name}' from bucket '{self._bucket_name}'"
|
"Got object", object_name=object_name, bucket=self._bucket_name
|
||||||
)
|
)
|
||||||
return buffer
|
return buffer
|
||||||
except minio.S3Error as exc:
|
except minio.S3Error as exc:
|
||||||
if exc.code == "NoSuchKey":
|
if exc.code == "NoSuchKey":
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
f"Object '{object_name}' not found in bucket '{self._bucket_name}'"
|
"Object not found",
|
||||||
|
object_name=object_name,
|
||||||
|
bucket=self._bucket_name,
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
raise
|
raise
|
||||||
@@ -193,7 +196,7 @@ class MinioAdapter(ObjectRepositoryInterface, ConnectionAwareAdapter):
|
|||||||
object_name=object_name,
|
object_name=object_name,
|
||||||
)
|
)
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
f"Deleted object '{object_name}' from bucket '{self._bucket_name}'"
|
"Deleted object", object_name=object_name, bucket=self._bucket_name
|
||||||
)
|
)
|
||||||
|
|
||||||
def list_objects(self, prefix: str = "") -> list[str]:
|
def list_objects(self, prefix: str = "") -> list[str]:
|
||||||
@@ -215,6 +218,9 @@ class MinioAdapter(ObjectRepositoryInterface, ConnectionAwareAdapter):
|
|||||||
obj.object_name for obj in objects if obj.object_name is not None
|
obj.object_name for obj in objects if obj.object_name is not None
|
||||||
]
|
]
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
f"Listed {len(object_names)} object(s) in bucket '{self._bucket_name}' with prefix '{prefix}'"
|
"Listed objects",
|
||||||
|
count=len(object_names),
|
||||||
|
bucket=self._bucket_name,
|
||||||
|
prefix=prefix,
|
||||||
)
|
)
|
||||||
return object_names
|
return object_names
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""Definition of RedisAdapter class."""
|
"""Definition of RedisAdapter class."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Iterator
|
from collections.abc import Iterator
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
@@ -101,7 +102,7 @@ class RedisAdapter(JsonRepositoryInterface, ConnectionAwareAdapter):
|
|||||||
assert self._client is not None
|
assert self._client is not None
|
||||||
# Set data
|
# Set data
|
||||||
self._client.json().set(key, self.path, data)
|
self._client.json().set(key, self.path, data)
|
||||||
self.logger.debug(f"Set {key} to {data}")
|
self.logger.debug("Set key", key=key, data_keys=list(data.keys()))
|
||||||
|
|
||||||
def get(self, key: str) -> dict[str, Any] | None:
|
def get(self, key: str) -> dict[str, Any] | None:
|
||||||
"""Get a JSON object from Redis."""
|
"""Get a JSON object from Redis."""
|
||||||
@@ -116,7 +117,7 @@ class RedisAdapter(JsonRepositoryInterface, ConnectionAwareAdapter):
|
|||||||
dict[str, Any] | None,
|
dict[str, Any] | None,
|
||||||
self._client.json().get(key),
|
self._client.json().get(key),
|
||||||
)
|
)
|
||||||
self.logger.debug(f"Got {data} from {key}")
|
self.logger.debug("Got value", key=key, found=data is not None)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def delete(self, key: str) -> None:
|
def delete(self, key: str) -> None:
|
||||||
@@ -129,7 +130,7 @@ class RedisAdapter(JsonRepositoryInterface, ConnectionAwareAdapter):
|
|||||||
assert self._client is not None
|
assert self._client is not None
|
||||||
# Delete data
|
# Delete data
|
||||||
self._client.json().delete(key)
|
self._client.json().delete(key)
|
||||||
self.logger.debug(f"Deleted {key}")
|
self.logger.debug("Deleted key", key=key)
|
||||||
|
|
||||||
def _validate_pattern(self, pattern: str) -> None:
|
def _validate_pattern(self, pattern: str) -> None:
|
||||||
if not isinstance(pattern, str) or len(pattern) == 0:
|
if not isinstance(pattern, str) or len(pattern) == 0:
|
||||||
@@ -147,7 +148,7 @@ class RedisAdapter(JsonRepositoryInterface, ConnectionAwareAdapter):
|
|||||||
self._client.keys(pattern),
|
self._client.keys(pattern),
|
||||||
)
|
)
|
||||||
keys: list[str] = [key.decode(self.encoding) for key in keys_raw]
|
keys: list[str] = [key.decode(self.encoding) for key in keys_raw]
|
||||||
self.logger.debug(f"Got {keys} matching {pattern}")
|
self.logger.debug("Listed keys", pattern=pattern, count=len(keys))
|
||||||
return keys
|
return keys
|
||||||
|
|
||||||
def scan_keys(
|
def scan_keys(
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
import os
|
||||||
|
|
||||||
from python_utils import check_env
|
from python_utils import check_env
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
import os
|
||||||
|
|
||||||
from python_utils import check_env
|
from python_utils import check_env
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Definition of JsonRepositoryInterface abstract base class."""
|
"""Definition of JsonRepositoryInterface abstract base class."""
|
||||||
|
|
||||||
from collections.abc import Iterator
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
from collections.abc import Iterator
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# Optional overrides:
|
# Optional overrides:
|
||||||
# REGISTRY=gitea.lille-vemmelund.dk
|
# REGISTRY=gitea.lille-vemmelund.dk
|
||||||
# REGISTRY_USER=ci-bot
|
# REGISTRY_USER=ci-bot
|
||||||
# IMAGE_OWNER=lille-vemmelund
|
# IMAGE_OWNER=lillevemmelund
|
||||||
# IMAGE_NAME=python-repositories-ci
|
# IMAGE_NAME=python-repositories-ci
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|||||||
|
|
||||||
REGISTRY="${REGISTRY:-gitea.lille-vemmelund.dk}"
|
REGISTRY="${REGISTRY:-gitea.lille-vemmelund.dk}"
|
||||||
REGISTRY_USER="${REGISTRY_USER:-ci-bot}"
|
REGISTRY_USER="${REGISTRY_USER:-ci-bot}"
|
||||||
IMAGE_OWNER="${IMAGE_OWNER:-lille-vemmelund}"
|
IMAGE_OWNER="${IMAGE_OWNER:-lillevemmelund}"
|
||||||
IMAGE_NAME="${IMAGE_NAME:-python-repositories-ci}"
|
IMAGE_NAME="${IMAGE_NAME:-python-repositories-ci}"
|
||||||
IMAGE="${IMAGE:-${REGISTRY}/${IMAGE_OWNER}/${IMAGE_NAME}}"
|
IMAGE="${IMAGE:-${REGISTRY}/${IMAGE_OWNER}/${IMAGE_NAME}}"
|
||||||
|
|
||||||
|
|||||||
@@ -11,15 +11,16 @@ set -euo pipefail
|
|||||||
BRANCH="${BRANCH:-renovate/auto-deps-update}"
|
BRANCH="${BRANCH:-renovate/auto-deps-update}"
|
||||||
BASE_BRANCH="${BASE_BRANCH:-main}"
|
BASE_BRANCH="${BASE_BRANCH:-main}"
|
||||||
LOCKFILE="${LOCKFILE:-uv.lock}"
|
LOCKFILE="${LOCKFILE:-uv.lock}"
|
||||||
|
PRE_COMMIT_CONFIG="${PRE_COMMIT_CONFIG:-.pre-commit-config.yaml}"
|
||||||
|
|
||||||
if git diff --quiet "$LOCKFILE"; then
|
if git diff --quiet "$LOCKFILE" && git diff --quiet "$PRE_COMMIT_CONFIG"; then
|
||||||
echo "No dependency updates available."
|
echo "No dependency updates available."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
git config user.name "CI Bot"
|
git config user.name "CI Bot"
|
||||||
git config user.email "ci-bot@example.com"
|
git config user.email "ci-bot@example.com"
|
||||||
git add "$LOCKFILE"
|
git add "$LOCKFILE" "$PRE_COMMIT_CONFIG"
|
||||||
git commit -m "chore(deps): update dependencies [automated]"
|
git commit -m "chore(deps): update dependencies [automated]"
|
||||||
|
|
||||||
git remote set-url origin "https://x-access-token:${CI_RUNNER_TOKEN}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git"
|
git remote set-url origin "https://x-access-token:${CI_RUNNER_TOKEN}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git"
|
||||||
@@ -48,7 +49,12 @@ print(
|
|||||||
json.dumps(
|
json.dumps(
|
||||||
{
|
{
|
||||||
"title": "chore(deps): update dependencies",
|
"title": "chore(deps): update dependencies",
|
||||||
"body": "This PR was created automatically to update dependencies.",
|
"body": (
|
||||||
|
"This PR was created automatically to update dependencies.\n\n"
|
||||||
|
"- `uv.lock`: upgraded Python dependencies\n"
|
||||||
|
"- `.pre-commit-config.yaml`: updated remote hook revs via "
|
||||||
|
"`pre-commit autoupdate`"
|
||||||
|
),
|
||||||
"head": os.environ["BRANCH"],
|
"head": os.environ["BRANCH"],
|
||||||
"base": os.environ["BASE_BRANCH"],
|
"base": os.environ["BASE_BRANCH"],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
"""Integration tests configuration."""
|
"""Integration tests configuration."""
|
||||||
|
|
||||||
import logging
|
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
|
import logging
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
|
from minio import Minio
|
||||||
import pytest
|
import pytest
|
||||||
import redis
|
import redis
|
||||||
import structlog
|
import structlog
|
||||||
from minio import Minio
|
|
||||||
from testcontainers.core.container import DockerContainer
|
from testcontainers.core.container import DockerContainer
|
||||||
from testcontainers.core.waiting_utils import WaitStrategy, WaitStrategyTarget
|
from testcontainers.core.waiting_utils import WaitStrategy, WaitStrategyTarget
|
||||||
from testcontainers.minio import MinioContainer
|
from testcontainers.minio import MinioContainer
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ from io import BytesIO
|
|||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import pytest
|
|
||||||
from minio import Minio
|
from minio import Minio
|
||||||
|
import pytest
|
||||||
|
|
||||||
from python_repositories.examples.artifact_object_repository import (
|
from python_repositories.examples.artifact_object_repository import (
|
||||||
ArtifactObjectRepository,
|
ArtifactObjectRepository,
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
from dataclasses import replace
|
from dataclasses import replace
|
||||||
|
from io import BytesIO
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
from io import BytesIO
|
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
|
||||||
from minio import Minio, S3Error
|
from minio import Minio, S3Error
|
||||||
|
import pytest
|
||||||
from urllib3.response import BaseHTTPResponse
|
from urllib3.response import BaseHTTPResponse
|
||||||
|
|
||||||
from python_repositories.adapters.minio_adapter import MinioAdapter
|
from python_repositories.adapters.minio_adapter import MinioAdapter
|
||||||
@@ -102,7 +102,8 @@ def test_should_log_info_when_already_connected(
|
|||||||
"""Test that the MinioAdapter logs info when connect is called while already connected."""
|
"""Test that the MinioAdapter logs info when connect is called while already connected."""
|
||||||
with caplog.at_level(logging.INFO):
|
with caplog.at_level(logging.INFO):
|
||||||
minio_adapter.connect()
|
minio_adapter.connect()
|
||||||
assert "Already connected to Minio" in caplog.text
|
assert "Already connected" in caplog.text
|
||||||
|
assert "Minio" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
def test_should_raise_connection_error_when_unable_to_connect() -> None:
|
def test_should_raise_connection_error_when_unable_to_connect() -> None:
|
||||||
@@ -150,7 +151,8 @@ def test_connect_creates_bucket_when_create_bucket_if_missing_enabled(
|
|||||||
with caplog.at_level(logging.INFO):
|
with caplog.at_level(logging.INFO):
|
||||||
adapter.connect()
|
adapter.connect()
|
||||||
|
|
||||||
assert f"Creating bucket '{bucket_name}'" in caplog.text
|
assert "Creating bucket" in caplog.text
|
||||||
|
assert bucket_name in caplog.text
|
||||||
|
|
||||||
|
|
||||||
def test_should_log_error_on_exception_during_exit(
|
def test_should_log_error_on_exception_during_exit(
|
||||||
@@ -233,10 +235,11 @@ def test_should_log_warning_when_getting_nonexistent_object(
|
|||||||
with caplog.at_level("WARNING"):
|
with caplog.at_level("WARNING"):
|
||||||
result = adapter.get(object_name)
|
result = adapter.get(object_name)
|
||||||
assert result is None
|
assert result is None
|
||||||
assert (
|
assert "Object not found" in caplog.text
|
||||||
f"Object '{object_name}' not found in bucket '{adapter._bucket_name}'"
|
assert object_name in caplog.text
|
||||||
in caplog.text
|
bucket_name = adapter._bucket_name
|
||||||
)
|
assert bucket_name is not None
|
||||||
|
assert bucket_name in caplog.text
|
||||||
|
|
||||||
|
|
||||||
def test_should_reraise_s3error_other_than_no_such_key() -> None:
|
def test_should_reraise_s3error_other_than_no_such_key() -> None:
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ def test_should_log_info_when_already_connected(
|
|||||||
"""Test that the RedisAdapter logs info when connect is called while already connected."""
|
"""Test that the RedisAdapter logs info when connect is called while already connected."""
|
||||||
with caplog.at_level(logging.INFO):
|
with caplog.at_level(logging.INFO):
|
||||||
redis_adapter.connect()
|
redis_adapter.connect()
|
||||||
assert "Already connected to Redis" in caplog.text
|
assert "Already connected" in caplog.text
|
||||||
|
assert "Redis" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
def test_should_raise_connection_error_when_unable_to_connect() -> None:
|
def test_should_raise_connection_error_when_unable_to_connect() -> None:
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import builtins
|
import builtins
|
||||||
|
from collections.abc import Callable, Mapping, Sequence
|
||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from collections.abc import Callable, Mapping, Sequence
|
|
||||||
from pathlib import Path
|
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from minio import Minio
|
||||||
import pytest
|
import pytest
|
||||||
import redis
|
import redis
|
||||||
from minio import Minio
|
|
||||||
|
|
||||||
from python_repositories.adapters.minio_adapter import MinioAdapter
|
from python_repositories.adapters.minio_adapter import MinioAdapter
|
||||||
from python_repositories.adapters.redis_adapter import RedisAdapter
|
from python_repositories.adapters.redis_adapter import RedisAdapter
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""Unit tests for ConnectionAwareInterface."""
|
"""Unit tests for ConnectionAwareInterface."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from python_repositories.interfaces.connection_aware_interface import (
|
from python_repositories.interfaces.connection_aware_interface import (
|
||||||
ConnectionAwareInterface,
|
ConnectionAwareInterface,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from python_repositories.interfaces.context_aware_interface import ContextAwareInterface
|
from python_repositories.interfaces.context_aware_interface import ContextAwareInterface
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from python_repositories.interfaces.json_repository_interface import (
|
from python_repositories.interfaces.json_repository_interface import (
|
||||||
JsonRepositoryInterface,
|
JsonRepositoryInterface,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ from __future__ import annotations
|
|||||||
from dataclasses import replace
|
from dataclasses import replace
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
|
||||||
from minio import Minio, S3Error
|
from minio import Minio, S3Error
|
||||||
|
import pytest
|
||||||
from urllib3.response import BaseHTTPResponse
|
from urllib3.response import BaseHTTPResponse
|
||||||
|
|
||||||
from python_repositories.adapters.minio_adapter import MinioAdapter
|
from python_repositories.adapters.minio_adapter import MinioAdapter
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from python_repositories.interfaces.object_repository_interface import (
|
from python_repositories.interfaces.object_repository_interface import (
|
||||||
ObjectRepositoryInterface,
|
ObjectRepositoryInterface,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
version = 1
|
version = 1
|
||||||
revision = 3
|
revision = 2
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
resolution-markers = [
|
resolution-markers = [
|
||||||
"python_full_version >= '3.15'",
|
"python_full_version >= '3.15'",
|
||||||
@@ -1056,7 +1056,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-repositories"
|
name = "python-repositories"
|
||||||
version = "2.0.2"
|
version = "2.0.4"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "python-dotenv" },
|
{ name = "python-dotenv" },
|
||||||
@@ -1097,12 +1097,12 @@ provides-extras = ["redis", "minio"]
|
|||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [
|
dev = [
|
||||||
{ name = "mypy", specifier = ">=1.17.1" },
|
{ name = "mypy", specifier = ">=2.1.0" },
|
||||||
{ name = "pre-commit", specifier = ">=4.3.0" },
|
{ name = "pre-commit", specifier = ">=4.6.0" },
|
||||||
{ name = "pytest", specifier = ">=8.4.1" },
|
{ name = "pytest", specifier = ">=8.4.1" },
|
||||||
{ name = "pytest-cov", specifier = ">=7.0.0" },
|
{ name = "pytest-cov", specifier = ">=7.0.0" },
|
||||||
{ name = "pyupgrade", specifier = ">=3.20.0" },
|
{ name = "pyupgrade", specifier = ">=3.21.2" },
|
||||||
{ name = "ruff", specifier = ">=0.12.11" },
|
{ name = "ruff", specifier = ">=0.15.20" },
|
||||||
{ name = "safety", specifier = ">=3.6.0" },
|
{ name = "safety", specifier = ">=3.6.0" },
|
||||||
{ name = "testcontainers", specifier = ">=4.13.0" },
|
{ name = "testcontainers", specifier = ">=4.13.0" },
|
||||||
{ name = "types-redis", specifier = ">=4.6.0.20241004" },
|
{ name = "types-redis", specifier = ">=4.6.0.20241004" },
|
||||||
|
|||||||
Reference in New Issue
Block a user