From cd0be5f735659e96e57711a481bd47a8611d420b Mon Sep 17 00:00:00 2001 From: Erik Welch Date: Wed, 5 Aug 2026 02:54:30 -0500 Subject: [PATCH] Keep the CI matplotlib pick compatible with the numpy pick The overnight matrix produced the stack's first two post-restack failures, both the same one line: the notebooks task on macos-latest and windows-latest picked numpy 1.24 while installing matplotlib unpinned, and matplotlib 3.11.0's runtime check requires numpy >=1.25. Its conda-forge metadata does not carry that floor, so the solver pairs them happily and the notebooks die at import. Same class and same fix shape as the networkx and awkward pick constraints: the version picker now emits mplver, a bare ceiling of <3.11 whenever the numpy pick sits under 1.25 and empty otherwise, the notebooks install line consumes it, and validate() checks the pairing. The --validate stress test passes 160000 combos with zero failures, and both emission cases are confirmed by running the picker. --- .github/workflows/test_and_build.yml | 2 +- scripts/ci_pick_versions.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test_and_build.yml b/.github/workflows/test_and_build.yml index 9ece8cfed..735b33889 100644 --- a/.github/workflows/test_and_build.yml +++ b/.github/workflows/test_and_build.yml @@ -222,7 +222,7 @@ jobs: pyyaml${yamlver} ${sparse} pandas${pdver} scipy${spver} numpy${npver} ${awkward} \ networkx${nxver} ${numba} ${psg} \ ${{ matrix.slowtask == 'pytest_bizarro' && 'black' || '' }} \ - ${{ matrix.slowtask == 'notebooks' && 'matplotlib nbconvert jupyter "ipython>=7" drawsvg' || '' }} \ + ${{ matrix.slowtask == 'notebooks' && '"matplotlib${mplver}" nbconvert jupyter "ipython>=7" drawsvg' || '' }} \ ${{ steps.sourcetype.outputs.selected == 'upstream' && 'cython' || '' }} \ ${{ steps.sourcetype.outputs.selected != 'wheel' && '"graphblas>=7.4"' || '' }} \ ${{ contains(steps.pyver.outputs.selected, 'pypy') && 'pypy' || '' }} \ diff --git a/scripts/ci_pick_versions.py b/scripts/ci_pick_versions.py index 68a435165..5b8fe0f7e 100755 --- a/scripts/ci_pick_versions.py +++ b/scripts/ci_pick_versions.py @@ -237,6 +237,19 @@ def apply_constraints(v, pyver, scipy_pool, numba_pool): # Only the numpy 1.x pools reach here, and those Pythons all have pre-3.5 networkx. v["networkx"] = random.choice([n for n in NETWORKX_VERSIONS[pyver] if _ver(n) < (3, 5)]) + # --- matplotlib / numpy floor (notebooks job) --- + + # matplotlib is installed unpinned for the notebooks task. matplotlib 3.11.0's + # runtime check requires numpy >=1.25, but its conda-forge metadata does not, + # so the solver happily pairs matplotlib 3.11 with a numpy 1.24 pin and the + # notebooks then die at `import matplotlib`. Pin below 3.11 whenever the + # numpy pick sits under that floor; empty means latest is fine. + # MAINT: 2026-08-05 confirmed with matplotlib 3.11.0 + numpy 1.24.4 + if v["numpy"] and _ver(v["numpy"]) < (1, 25): + v["matplotlib"] = "<3.11" + else: + v["matplotlib"] = "" + # --- numba constraints --- # numba minimum by Python version: 0.59 for 3.12, 0.61 for 3.13, 0.63 for 3.14 @@ -380,6 +393,7 @@ def _pick_psg(npver, pyver, source_type): "sparse": "sparse", "numba": "numba", "psg": "psg", + "matplotlib": "mpl", } @@ -401,6 +415,8 @@ def format_output(v): # psg already has = or == prefix lines.append(f"psgver='{v['psg']}'") + # matplotlib carries a bare ceiling (e.g. "<3.11") or is empty for latest + lines.append(f"mplver='{v['matplotlib']}'") return "\n".join(lines) @@ -417,6 +433,7 @@ def format_summary(v): "pyyaml", "sparse", "psg", + "matplotlib", ): name = _SUMMARY_NAMES[key] val = v[key] @@ -482,6 +499,10 @@ def validate(v, pyver): if not np_is_1x and v["awkward"] not in ("", "NA") and _ver(v["awkward"]) < (2, 6): errors.append(f"awkward {v['awkward']} doesn't support numpy 2.x") + # matplotlib 3.11 requires numpy >=1.25 at runtime (notebooks job) + 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)") + # awkward <2.10 requires numpy <2.5 (generic-unit datetime64("NaT") at import) if ( _ver(v["numpy"]) >= (2, 5)