From dbe2c33e2f5911ae00517e4687fc8d26060ad8ce Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Mon, 21 Sep 2026 16:42:14 +0300 Subject: [PATCH] ci: resolve the declared dependency floors on every PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `pytest` and `scheduled` both resolve highest, so the declared lower bounds ship untested. That is how faststream-stomp kept `faststream~=0.7` until 0.7.6 made `address` a required field of `SubscriberSpec` and broke AsyncAPI generation for anyone resolving fresh. The new `lowest` leg resolves `--resolution lowest-direct` and runs the suite against it on every supported interpreter — wheel coverage is per-interpreter, so two of them resolving the same versions can still disagree on whether those versions install. `--no-build` keeps it a resolution error rather than a quiet sdist compile. `faststream>=0.7` holds: the suite passes against 0.7.0 on all five interpreters, and nothing here touches the endpoint-specification API 0.7.6 changed. What did not hold was the harness. Every dev name was unbounded, so the floors resolved pytest 2.7.1 and pytest-asyncio 0.1, which cannot run the suite at all. Both typing-extensions floors are pydantic wheel coverage: uv runs one resolution over every group, so an unbounded lint-group name reaches the dev set and holds pydantic back to a build whose pydantic-core ships no wheel for the interpreter under test. --- .github/workflows/_checks.yml | 30 ++++++++++++++++++++++++++++++ pyproject.toml | 22 +++++++++++++++------- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/.github/workflows/_checks.yml b/.github/workflows/_checks.yml index 0a03cea..e9978b7 100644 --- a/.github/workflows/_checks.yml +++ b/.github/workflows/_checks.yml @@ -43,6 +43,36 @@ jobs: run: uv run --no-sync python -c "import sys, modern_di_faststream; assert not sys._is_gil_enabled(), 'GIL is enabled on a t-build'" - run: just test-ci + lowest: + # The declared floors are part of what we ship, and nothing else in CI installs + # them: `pytest` and `scheduled` both resolve highest. This leg resolves the lower + # bound instead, on every supported interpreter: a floor's wheel coverage is + # per-interpreter, so two interpreters resolving the same versions can still + # disagree on whether those versions install. + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - "3.10" + - "3.11" + - "3.12" + - "3.13" + - "3.14" + 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: a floor with no wheel for this interpreter must fail here rather + # than quietly compile its sdist. Without it the leg passes on a floor that + # still breaks anyone installing into an image with no build toolchain. + - run: uv sync --all-extras --no-install-project --resolution lowest-direct --no-build + - run: uv run --no-sync pytest . + links: runs-on: ubuntu-latest steps: diff --git a/pyproject.toml b/pyproject.toml index 93da3bb..d8dfa0d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,18 +30,26 @@ Changelog = "https://github.com/modern-python/modern-di-faststream/releases" [dependency-groups] dev = [ - "faststream[nats]", - "pytest", - "pytest-cov", - "pytest-asyncio", - "httpx", - "asgi-lifespan", + # Floored so `uv sync --resolution lowest-direct` resolves a usable harness: an + # unbounded name there resolves to the project's first-ever release. + "faststream[nats]>=0.7,<0.8", + "pytest>=8", + "pytest-cov>=5", + "pytest-asyncio>=0.24", + "httpx>=0.27", + "asgi-lifespan>=2.1", ] lint = [ "ty", "ruff", "eof-fixer", - "typing-extensions", + # Both floors are pydantic wheel coverage, reached through the one resolution uv + # runs over every group: floored lower, typing-extensions holds pydantic back to a + # build whose pydantic-core ships no wheel for the interpreter. pydantic needs + # 4.12.2 from 3.13, and 2.12 — the first release with a cp314 pydantic-core — + # needs 4.14.1. + "typing-extensions>=4.12.2; python_version < '3.14'", + "typing-extensions>=4.14.1; python_version >= '3.14'", ] [build-system]