From 7466058c81eec115cf56296b29c81e95e43f0b09 Mon Sep 17 00:00:00 2001 From: Erik Welch Date: Wed, 5 Aug 2026 04:00:43 -0500 Subject: [PATCH 1/2] Keep the CI numba pick solvable against numpy 1.25 and 1.26 The overnight matrix hit a conda solver failure on the bottom rung: the picker drew numpy 1.25 with numba 0.57, and conda-forge numba 0.57 requires numpy <1.25, so the environment could not solve and the job died before running anything. The picker's constraints covered numba's numpy 2.x boundaries but not this 1.x-era ceiling. Bump numba 0.57 to 0.58 whenever the numpy pick is 1.25 or 1.26, following the existing 0.62/0.63-to-0.64 pattern, and teach validate() the pairing. The boundary is verified by dry-run solves against conda-forge: 0.57+1.25 conflicts; 0.58+1.25, 0.58+1.26, and 0.59+1.26 all solve. The --validate stress test passes 160000 combos, and 200 fresh draws produce zero bad pairings. --- scripts/ci_pick_versions.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/ci_pick_versions.py b/scripts/ci_pick_versions.py index 5b8fe0f7e..64fed5c9f 100755 --- a/scripts/ci_pick_versions.py +++ b/scripts/ci_pick_versions.py @@ -264,6 +264,13 @@ def apply_constraints(v, pyver, scipy_pool, numba_pool): if _ver(v["numpy"]) >= (2, 4) and v["numba"] in ("0.62", "0.63"): v["numba"] = "0.64" + # conda-forge numba 0.57 requires numpy <1.25, so that pairing fails the + # conda solve outright. Verified by dry-run solves: 0.57+1.25 conflicts; + # 0.58+1.25, 0.58+1.26, and 0.59+1.26 all solve. + # MAINT: 2026-08-05 confirmed against conda-forge with mamba dry-runs + if v["numba"] == "0.57" and np_is_1x and _ver(v["numpy"]) >= (1, 25): + v["numba"] = "0.58" + # numba <0.62 doesn't support numpy 2.x if not np_is_1x and v["numba"] not in ("", "NA") and _ver(v["numba"]) < (0, 62): v["numba"] = "NA" @@ -503,6 +510,10 @@ def validate(v, pyver): if v["numpy"] and _ver(v["numpy"]) < (1, 25) and v.get("matplotlib", "") != "<3.11": errors.append(f"matplotlib unpinned alongside numpy {v['numpy']} (needs <3.11)") + # conda-forge numba 0.57 requires numpy <1.25 (fails the conda solve) + if v["numba"] == "0.57" and v["numpy"] and _ver(v["numpy"]) >= (1, 25) and np_is_1x: + errors.append(f"numba 0.57 requires numpy <1.25, got {v['numpy']}") + # awkward <2.10 requires numpy <2.5 (generic-unit datetime64("NaT") at import) if ( _ver(v["numpy"]) >= (2, 5) From f5eb23d5f24a6797f17a4963566c8151c1392fb1 Mon Sep 17 00:00:00 2001 From: Erik Welch Date: Thu, 6 Aug 2026 00:41:33 -0700 Subject: [PATCH 2/2] Keep the CI scipy pick solvable against pandas 2.2 and 2.3 The matrix hit another conda solver failure: the picker drew pandas 2.2 with scipy 1.9, reachable only on the py3.11 numpy 1.x path, and the environment could not solve, so the job died before running anything. conda-forge pandas >=2.2 carries run_constrained "scipy >=1.10.0" (the latest 2.2.3 build and all 2.3 builds; pandas 2.0 and 2.1 declare no scipy constraint), and scipy 1.9.3 py311 builds exist even on win-64, so the pairing fails purely on the pandas constraint. Verified with conda search --info against conda-forge. Re-pick scipy from the pool's 1.10 through 1.14 pins whenever a pandas 2.2 or 2.3 pin lands next to a scipy pin below 1.10, and teach validate() the pairing. The replacement stays pinned below 1.15 because scipy 1.9 only survives to this point alongside numpy 1.24 or 1.25, whose scipy ceiling is 1.15. Unpinned pandas is left alone: the solver backs it off below 2.2 on its own, which keeps scipy 1.9 coverage. The --validate stress test passes 160000 combos, 4800 fresh draws produce zero bad pairings, and forcing the old bad pair through apply_constraints now always lands scipy in 1.10 through 1.14 with no validate() errors. --- scripts/ci_pick_versions.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/scripts/ci_pick_versions.py b/scripts/ci_pick_versions.py index 64fed5c9f..738ef99a8 100755 --- a/scripts/ci_pick_versions.py +++ b/scripts/ci_pick_versions.py @@ -191,6 +191,21 @@ def apply_constraints(v, pyver, scipy_pool, numba_pool): if v["scipy"] not in ("", "NA") and _ver(v["scipy"]) < (1, 15): v["scipy"] = random.choice(["1.15", "1.16", "1.17", ""]) + # conda-forge pandas >=2.2 carries run_constrained "scipy >=1.10.0" (latest 2.2.3 + # build and all 2.3 builds; 2.0/2.1 declare no scipy constraint), so a pandas + # 2.2/2.3 pin alongside a scipy 1.9 pin fails the conda solve outright. Unpinned + # pandas backs off on its own, so only pins trigger. A scipy 1.9 pick can only + # reach here with numpy 1.24/1.25 (the 1.26 conflict above already re-picked), + # so keep the replacement pinned below the scipy 1.15 ceiling those numpys impose. + # MAINT: 2026-08-06 verified with conda search --info against conda-forge + if ( + v["pandas"] not in ("", "NA") + and _ver(v["pandas"]) >= (2, 2) + and v["scipy"] not in ("", "NA") + and _ver(v["scipy"]) < (1, 10) + ): + v["scipy"] = random.choice([s for s in scipy_pool if s and (1, 10) <= _ver(s) < (1, 15)]) + # --- awkward / numpy 2.x support --- # awkward <2.6 uses numpy.AxisError, which numpy 2.0 removed (test_io.py then fails @@ -496,6 +511,15 @@ def validate(v, pyver): if v["scipy"] not in ("", "NA") and _ver(v["scipy"]) < (1, 15): errors.append(f"pandas 3.0 requires scipy >=1.14.1, got {v['scipy']}") + # conda-forge pandas >=2.2 constrains scipy >=1.10.0 (fails the conda solve) + if ( + v["pandas"] not in ("", "NA") + and _ver(v["pandas"]) >= (2, 2) + and v["scipy"] not in ("", "NA") + and _ver(v["scipy"]) < (1, 10) + ): + errors.append(f"pandas {v['pandas']} constrains scipy >=1.10.0, got {v['scipy']}") + # awkward Python availability if pyver == "3.14" and v["awkward"] not in ("", "NA") and _ver(v["awkward"]) < (2, 8): errors.append(f"awkward {v['awkward']} has no py3.14 build")