Files
python-repositories/README.md
T
Brian Bjarke JensenandCursor 5149299c1b
Code Quality Pipeline / code-quality (pull_request) Failing after 35s
PR Title Check / check-title (pull_request) Successful in 6s
Test Python Package / test (pull_request) Successful in 1m9s
Strengthen is_connected with cached health probes.
Convert is_connected to a method that verifies backend liveness via TTL-cached ping (Redis) or bucket_exists (MinIO), with cache invalidation on connect/disconnect.

Co-authored-by: Cursor <[email protected]>
2026-07-05 15:28:25 +02:00

154 lines
5.6 KiB
Markdown

# python-repositories
Unified repository interfaces and technology-specific adapters for Python projects.
Subclass an adapter in your own repository to add domain-specific methods while reusing connection management and CRUD operations.
## Architecture
| Layer | Responsibility |
| ---------------- | ----------------------------------------------------------------- |
| **Interfaces** | Abstract contracts for connection, context, and CRUD |
| **Adapters** | Technology-specific base classes (`RedisAdapter`, `MinioAdapter`) |
| **Your project** | Subclass an adapter and add domain methods |
Connection adapters expose `connect()`, `disconnect()`, and `is_connected()`. The latter verifies backend reachability with a cached health probe (default TTL: 1 second). Subclasses may override `health_check_ttl_seconds`.
## Optional dependencies
Repository **interfaces** import with the base package. **Adapters** require the matching extra; importing an adapter without its extra raises `ImportError` with install instructions.
Install with the extras you need:
```bash
uv add python-repositories[redis]
uv add python-repositories[minio]
uv add python-repositories[redis,minio]
```
### Redis (`JsonRepositoryInterface`)
Requires Redis with the RedisJSON module (e.g. redis-stack).
| Environment variable | Description |
| -------------------- | ---------------------------------------------------- |
| `REDIS_URI` | Redis connection URL (e.g. `redis://localhost:6379`) |
### MinIO (`ObjectRepositoryInterface`)
| Environment variable | Description |
| -------------------- | ------------------------------------------- |
| `MINIO_ENDPOINT` | MinIO server endpoint |
| `MINIO_ACCESS_KEY` | Access key |
| `MINIO_SECRET_KEY` | Secret key |
| `MINIO_BUCKET` | Bucket name (created on connect if missing) |
## Quick start
### JSON documents with Redis
```python
from python_repositories.examples.user_json_repository import UserJsonRepository
with UserJsonRepository() as repo:
repo.save_user("alice", {"name": "Alice", "email": "[email protected]"})
user = repo.get_user("alice")
repo.delete_user("alice")
```
### Binary objects with MinIO
```python
from io import BytesIO
from python_repositories.examples.artifact_object_repository import (
ArtifactObjectRepository,
)
with ArtifactObjectRepository() as repo:
repo.store_artifact("report-1", BytesIO(b"pdf bytes here"))
data = repo.get_artifact("report-1")
```
### Subclassing in your own project
```python
from python_repositories import RedisAdapter
class UserRepository(RedisAdapter):
def _key(self, user_id: str) -> str:
return f"user:{user_id}"
def get_user(self, user_id: str) -> dict | None:
return self.get(self._key(user_id))
def save_user(self, user_id: str, user: dict) -> None:
self.set(self._key(user_id), user)
```
## Public API
```python
from python_repositories import (
ConnectionAwareInterface,
ContextAwareInterface,
JsonRepositoryInterface,
ObjectRepositoryInterface,
RedisAdapter,
MinioAdapter,
)
```
## Development
```bash
uv sync --all-extras
uv run pre-commit install # once per clone — runs hooks on git commit
uv run pytest tests/integration/ -v
```
`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:
```bash
uv run pre-commit run --all-files
```
Integration tests require Docker (testcontainers).
## Releases
Releases are automated when a pull request is merged to `main`. CI reads the **merged PR title** to decide whether and how to bump the version.
### How it works
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).
3. On merge, [`release.yml`](.gitea/workflows/release.yml) bumps [`pyproject.toml`](pyproject.toml), commits, tags `vX.Y.Z`, creates a Gitea release with auto-generated notes, and pushes the tag.
4. [`publish.yml`](.gitea/workflows/publish.yml) builds and publishes the package to the Gitea Package Registry.
Docs-, CI-, and test-only PRs do not need a prefix and will not trigger a release.
### PR title prefixes
| 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` |
| _(none)_ | no release | docs / CI / deps only |
Example titles:
- `[minor] Add public repository interfaces and subclassable adapter CRUD API`
- `[patch] Fix mypy context manager typing for adapter subclasses`
### Release notes
Release notes are generated from commits since the previous tag (see [`scripts/ci/generate-release-notes.sh`](scripts/ci/generate-release-notes.sh)).
### Manual release
You can still push a `v*.*.*` tag manually; `publish.yml` will build and publish. The current baseline version is **0.3.1**.