From a979fcbf4e3db148a62d3d8bc69cf52be48f2802 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Sun, 11 Oct 2026 22:08:24 -0400 Subject: [PATCH] Test on Python 3.15 and lift the numpy cap to <2.6 Python 3.15.0 was released on 2026-10-09. Two things stopped it from installing: the numpy <2.5 cap in setup.cfg (the first numpy with a cp315 wheel is 2.5.2; numba 0.67 and 0.68 declare numpy<2.6, so the cap moves to match) and the libjxl=0.11.* pin in the two micromamba workflows, which conda-forge's rebuilt GDAL stack (libjxl >=0.12) can no longer satisfy. The pin's own comment asked for it to be removed once that rebuild landed. test.yml: PRs run 3.15 plus the 3.14t probe; main and nightly run 3.12 through 3.15 plus 3.14t. No 3.15t job until numba ships a cp315t wheel. test-geotiff-corpus.yml moves its newest slot to 3.15. test-cog-validator.yml stays on 3.12 with the pin removed. --- .github/workflows/test-cog-validator.yml | 17 ++++------------- .github/workflows/test-geotiff-corpus.yml | 9 +-------- .github/workflows/test.yml | 7 ++++++- setup.cfg | 8 +++++--- 4 files changed, 16 insertions(+), 25 deletions(-) diff --git a/.github/workflows/test-cog-validator.yml b/.github/workflows/test-cog-validator.yml index 727f3353a..1017ec133 100644 --- a/.github/workflows/test-cog-validator.yml +++ b/.github/workflows/test-cog-validator.yml @@ -49,12 +49,10 @@ jobs: fail-fast: false matrix: # Pin to a python version where conda-forge ships a stable - # rio-cogeo + GDAL combo. 3.12 is the safest target today; - # 3.14 wheels for some of the GDAL stack are not yet - # universally available, and the gate has to install reliably - # to be a useful required check. Add 3.13 / 3.14 here once - # conda-forge has caught up with stable rio-cogeo + GDAL - # builds for those interpreters. + # rio-cogeo + GDAL combo. 3.12 is the most conservative install + # for a required check; conda-forge now has GDAL / rasterio + # builds for 3.13 through 3.15 as well, so widening this is a + # matter of choosing to, not of availability. python: ['3.12'] defaults: run: @@ -70,12 +68,6 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up micromamba env (conda-forge rio-cogeo + GDAL) - # libjxl is pinned to 0.11.* because conda-forge published libjxl - # 0.12.0 (2026-07-03) before rebuilding libgdal-core / rasterio - # against it, so an unpinned solve pairs a GDAL linked to - # libjxl.so.0.11 with only 0.12 installed and rasterio fails to - # import. Drop the pin once conda-forge ships libgdal-core / - # rasterio builds linked against libjxl 0.12. uses: mamba-org/setup-micromamba@v1 with: environment-name: xrspatial-cog-validator @@ -86,7 +78,6 @@ jobs: rio-cogeo pyyaml tifffile - libjxl=0.11.* condarc: | channels: - conda-forge diff --git a/.github/workflows/test-geotiff-corpus.yml b/.github/workflows/test-geotiff-corpus.yml index c3c5b7e7d..625bd989c 100644 --- a/.github/workflows/test-geotiff-corpus.yml +++ b/.github/workflows/test-geotiff-corpus.yml @@ -32,7 +32,7 @@ jobs: fail-fast: false matrix: os: ${{ github.event_name == 'pull_request' && fromJson('["ubuntu-latest"]') || fromJson('["ubuntu-latest", "macos-latest", "windows-latest"]') }} - python: ${{ github.event_name == 'pull_request' && fromJson('["3.14"]') || fromJson('["3.12", "3.14"]') }} + python: ${{ github.event_name == 'pull_request' && fromJson('["3.15"]') || fromJson('["3.12", "3.15"]') }} defaults: run: # `-el` so micromamba's activation hooks fire and `rasterio` @@ -41,12 +41,6 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up micromamba env (conda-forge rasterio + GDAL) - # libjxl is pinned to 0.11.* because conda-forge published libjxl - # 0.12.0 (2026-07-03) before rebuilding libgdal-core / rasterio - # against it, so an unpinned solve pairs a GDAL linked to - # libjxl.so.0.11 with only 0.12 installed and rasterio fails to - # import. Drop the pin once conda-forge ships libgdal-core / - # rasterio builds linked against libjxl 0.12. uses: mamba-org/setup-micromamba@v1 with: environment-name: xrspatial-geotiff @@ -56,7 +50,6 @@ jobs: gdal pyyaml tifffile - libjxl=0.11.* condarc: | channels: - conda-forge diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d0d0bf06d..9b24f01ce 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,7 +34,12 @@ jobs: strategy: matrix: os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] - python: ${{ github.event_name == 'pull_request' && fromJson('["3.14", "3.14t"]') || fromJson('["3.12", "3.13", "3.14", "3.14t"]') }} + # PRs run the newest GIL interpreter plus the free-threaded probe; + # push-to-main and the nightly run every supported version. There + # is no 3.15t entry yet: numba 0.68.0 ships cp314t wheels but no + # cp315t, so that job would build numba from source. Add it once a + # numba release carries the wheel. + python: ${{ github.event_name == 'pull_request' && fromJson('["3.15", "3.14t"]') || fromJson('["3.12", "3.13", "3.14", "3.15", "3.14t"]') }} env: OS: ${{ matrix.os }} PYTHON: ${{ matrix.python }} diff --git a/setup.cfg b/setup.cfg index 56cecc796..eaf34675b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -31,12 +31,14 @@ include_package_data = True # numpy<1.27) # scipy >=1.13 first release built against numpy 2 (1.11 and # 1.12 declare numpy<1.28) -# numpy <2.5 mirrors numba: 0.64-0.66 declare numpy<2.5 and numba +# numpy <2.6 mirrors numba: 0.67-0.68 declare numpy<2.6 and numba # re-checks it at import in _ensure_critical_deps. # Without this, pip installs a numpy that makes # `import xrspatial` raise ImportError. Re-check this # on every numba bump -- nothing flags a stale cap, -# and leaving it behind blocks a numpy that works. +# and leaving it behind blocks a numpy that works +# (the old <2.5 cap blocked every numpy with a +# CPython 3.15 wheel; the first is 2.5.2). # xarray >=2025.11 earlier releases drop attrs across DataArray binary # ops, so morph_gradient / morph_white_tophat / # morph_black_tophat and the mcda and corridor @@ -52,7 +54,7 @@ install_requires = numba >=0.60 scipy >=1.13 xarray >=2025.11 - numpy >=2.0,<2.5 + numpy >=2.0,<2.6 pandas >=2.2.2 urllib3 >=2.7 packages = find: