From a7684da8e3829c18d759c66ef065443035e654cc Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Tue, 22 Sep 2026 19:03:11 +0300 Subject: [PATCH] ci: resolve the declared dependency floors on every matrix entry --- .github/workflows/_checks.yml | 50 +++++++++++++++++++++++++++++++++++ pyproject.toml | 20 ++++++++------ 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/.github/workflows/_checks.yml b/.github/workflows/_checks.yml index 67626dd..2ef4e76 100644 --- a/.github/workflows/_checks.yml +++ b/.github/workflows/_checks.yml @@ -60,6 +60,56 @@ jobs: PYTHONUNBUFFERED: 1 DB_DSN: postgresql+asyncpg://postgres:password@127.0.0.1/postgres + floors: + # Every other job resolves newest, so the declared floors are a claim nothing installs. + # This one resolves the bottom of each range, on every matrix entry: wheel coverage is + # per interpreter, so two interpreters resolving the same versions can still disagree + # on whether those versions install. + runs-on: ubuntu-latest + env: + # SQLAlchemy's cyext does not declare free-thread safety (fixed upstream for 2.1): use the pure-Python fallback on the t build. + DISABLE_SQLALCHEMY_CEXT_RUNTIME: ${{ matrix.python-version == '3.14t' && '1' || '' }} + strategy: + fail-fast: false + matrix: + python-version: + - "3.11" + - "3.12" + - "3.13" + - "3.14" + - "3.14t" + services: + postgres: + image: postgres:latest + env: + POSTGRES_DB: postgres + POSTGRES_PASSWORD: password + POSTGRES_USER: postgres + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: + - uses: actions/checkout@v6 + - uses: astral-sh/setup-uv@v8.2.0 + with: + enable-cache: true + cache-dependency-glob: "**/pyproject.toml" + - run: uv python install ${{ matrix.python-version }} + - run: uv python pin ${{ matrix.python-version }} + # --no-build so a floor with no wheel for this interpreter fails here instead of + # quietly compiling its sdist; --no-install-project because that flag would refuse to + # build this project too, and the tests import it from the checkout. + - run: uv sync --all-extras --no-install-project --resolution lowest-direct --no-build + - run: uv run --no-sync pytest + env: + PYTHONDONTWRITEBYTECODE: 1 + PYTHONUNBUFFERED: 1 + DB_DSN: postgresql+asyncpg://postgres:password@127.0.0.1/postgres + links: runs-on: ubuntu-latest steps: diff --git a/pyproject.toml b/pyproject.toml index b8539c2..b994044 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,11 +24,14 @@ dependencies = [ "tenacity>=8.4.1", # 2.0.31 is the first release that tolerates the __static_attributes__ and __firstlineno__ # attributes Python 3.13 added; below it SQLAlchemy's TypingOnly check fails at import. - "sqlalchemy[asyncio]>=2.0.18; python_version < '3.13'", + # 2.0.20, not 2.0.18: advanced-alchemy requires it, so nothing here can exercise 2.0.18. + "sqlalchemy[asyncio]>=2.0.20; python_version < '3.13'", "sqlalchemy[asyncio]>=2.0.31; python_version >= '3.13'", - # asyncpg declares requires-python >=3.8 throughout but ships no cp313 wheel before 0.30 and no - # cp314 wheel before 0.31, so a resolver picks an sdist that cannot build rather than conflicting. - "asyncpg>=0.28; python_version < '3.13'", + # asyncpg declares requires-python >=3.8 throughout but ships no cp312 wheel before 0.29, no + # cp313 wheel before 0.30 and no cp314 wheel before 0.31, so a resolver picks an sdist that + # cannot build rather than conflicting. + "asyncpg>=0.28; python_version < '3.12'", + "asyncpg>=0.29; python_version == '3.12'", "asyncpg>=0.30; python_version == '3.13'", "asyncpg>=0.31; python_version >= '3.14'", ] @@ -40,11 +43,12 @@ Issues = "https://github.com/modern-python/db-retry/issues" Changelog = "https://github.com/modern-python/db-retry/releases" [dependency-groups] +# Floored so `uv sync --resolution lowest-direct` resolves a usable harness, not each name's first release. dev = [ - "pytest", - "pytest-cov", - "pytest-asyncio", - "advanced-alchemy", + "pytest>=8", + "pytest-cov>=5", + "pytest-asyncio>=0.24", + "advanced-alchemy>=1", ] lint = [ "ruff",