The PyTest workflow requests python-version: "3.x", which now resolves to
CPython 3.14. Pipfile.lock pins scipy==1.15.3, whose newest wheels are
cp313, so pip falls back to building scipy from its sdist. That build
needs OpenBLAS, which ubuntu-latest does not provide, and 'make setup-dev'
fails before any test runs.
Pinning to 3.13 is the newest interpreter the current lockfile resolves
against: scipy, numpy, pandas and shapely all publish cp313 manylinux
wheels, and the one sdist-only dependency (turfpy 0.0.7) is pure Python.
The publish workflow runs the same pipenv install against the same
lockfile, so it is pinned identically.
The PyTest workflow currently fails on every PR, before any test runs.
Cause
pytest.yml requests python-version: "3.x", which resolves to whatever the newest CPython on the runner is — today 3.14.7. Pipfile.lock pins scipy==1.15.3, and that release publishes wheels only up to cp313. With no matching wheel, pip falls back to building scipy from its sdist, which needs BLAS:
ubuntu-latest has no OpenBLAS, so the build dies and make setup-dev exits non-zero:
(scipy is not a direct dependency — it arrives transitively via turfpy.)
This is time-based rot rather than a regression from any one commit: the last green run of this workflow on main was 2025-07-21. Python advanced to 3.14 while the lockfile stayed frozen, so the unpinned "3.x" drifted off the end of what the lockfile can resolve.
Fix
Pin python-version to "3.13" — the newest interpreter the current lockfile resolves against. I checked all 73 locked packages against PyPI: every one either ships a universal wheel or a cp313 manylinux wheel, and the single sdist-only dependency (turfpy==0.0.7) is pure Python with no build requirements.
pypi-publish.yml runs the same pipenv install --dev against the same lockfile and carries the same "3.x", so it is pinned identically — otherwise the next push to main would fail the same way at publish time.
Alternative considered
Regenerating Pipfile.lock for 3.14 would also work and would let CI track "3.x" again, but it is a dependency refresh across 73 packages and a much larger change to review. The pin restores the signal with a two-line change; refreshing the lockfile is worth doing separately and deliberately.
Notes
Out of scope, but noticed nearby and worth a follow-up:
Test plan
CI on this PR is the test: the build job should now get through Install dependencies and run black, flake8 and pytest.