From 9660a680e2e483052387bacea5f323145a667f7c Mon Sep 17 00:00:00 2001 From: Will Ockmore Date: Tue, 7 Jul 2026 14:42:15 +1000 Subject: [PATCH] Test fork compatibility --- .github/workflows/test-suite.yml | 38 ++++++++++++++++++++++++++++ scripts/fork-compat/sitecustomize.py | 24 ++++++++++++++++++ scripts/test-fork | 19 ++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 scripts/fork-compat/sitecustomize.py create mode 100755 scripts/test-fork diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index ea2d312..f424a83 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -45,3 +45,41 @@ jobs: files: ./coverage.xml token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true + + # Tripwire: prove the suite still passes against the community httpx forks. + # Advisory (continue-on-error) — a fork's own breakage shouldn't block PRs; + # flip continue-on-error to false to make compatibility a hard requirement. + fork-compat: + name: "Fork compat: ${{ matrix.backend }}" + runs-on: "ubuntu-latest" + continue-on-error: true + + strategy: + fail-fast: false + matrix: + backend: ["httpxyz", "httpx2"] + + env: + HTTPX_BACKEND: "${{ matrix.backend }}" + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: "3.13" + allow-prereleases: true + + - name: Install uv + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + python-version: "3.13" + version: "0.11.7" + + - name: "Install dependencies" + run: uv sync --all-extras --dev + + - name: "Install the ${{ matrix.backend }} fork" + run: uv pip install "${{ matrix.backend }}" + + - name: "Run tests against ${{ matrix.backend }}" + run: "scripts/test-fork" diff --git a/scripts/fork-compat/sitecustomize.py b/scripts/fork-compat/sitecustomize.py new file mode 100644 index 0000000..3807fea --- /dev/null +++ b/scripts/fork-compat/sitecustomize.py @@ -0,0 +1,24 @@ +"""Redirect ``import httpx`` to a community fork, for CI compatibility testing. + +This is *only* active when this directory is on ``PYTHONPATH`` **and** the +``HTTPX_BACKEND`` environment variable is set. Python imports ``sitecustomize`` +automatically at interpreter startup — before pytest or ``httpx_retries`` import +``httpx`` — so the alias is guaranteed to win regardless of import order. + +Used by ``scripts/test-fork``; a no-op in normal runs. +""" + +import os +import sys + +_backend = os.environ.get("HTTPX_BACKEND") + +if _backend == "httpxyz": + # httpxyz registers itself as sys.modules["httpx"] on first import. + import httpxyz # type: ignore[import-not-found] # noqa: F401 +elif _backend == "httpx2": + # httpx2 is a rename fork with no auto-alias, so wire it up ourselves. + # It preserves httpx's public API, which is all httpx-retries touches. + import httpx2 # type: ignore[import-not-found] + + sys.modules["httpx"] = httpx2 diff --git a/scripts/test-fork b/scripts/test-fork new file mode 100755 index 0000000..06929e6 --- /dev/null +++ b/scripts/test-fork @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +# Run the test suite against a community httpx fork (httpxyz or httpx2) to prove +# httpx-retries stays compatible. The fork must already be installed in .venv +# (e.g. `uv pip install httpxyz`). See scripts/fork-compat/sitecustomize.py. + +set -euo pipefail + +: "${HTTPX_BACKEND:?set HTTPX_BACKEND to httpxyz or httpx2}" + +source .venv/bin/activate + +# Put the sitecustomize shim on PYTHONPATH so `import httpx` resolves to the fork. +export PYTHONPATH="$(pwd)/scripts/fork-compat${PYTHONPATH:+:$PYTHONPATH}" + +# Fail fast with a clear message if the shim didn't take effect. +python -c "import httpx, ${HTTPX_BACKEND} as fork; assert httpx is fork, f'shim inactive: httpx is {httpx.__name__}'; print(f'httpx -> {httpx.__name__} {getattr(httpx, \"__version__\", \"?\")}')" + +pytest