From 8a7de928512362bb69367504865bde27a32f2879 Mon Sep 17 00:00:00 2001 From: Marius1311 Date: Thu, 16 Jul 2026 16:24:32 +0200 Subject: [PATCH] Make uv resolve gpcca-fast without compiling PETSc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit petsc4py/slepc4py compute their metadata dynamically at build time, so any bare `uv sync`/`uv run`/`uv lock` compiled PETSc from source just to resolve the dependency universe — and that source build fails on machines without a system BLAS on the linker path (e.g. isolated CI/uv build envs), where PETSc configure errors with "Could not find a functional BLAS". Add [[tool.uv.dependency-metadata]] entries mirroring the deps petsc4py/ slepc4py inject at build time, so uv resolves them from static metadata without ever building (resolves in ~5s). PETSc/SLEPc now compile only when the gpcca-fast group is actually installed. Also correct the (copied-from-CellRank) source-build recipe in the group comment: the documented options provide no BLAS and fail here; document the pre-built conda-forge/pixi path as the recommended install and a shared-BLAS source build as the fallback. uv.lock stays gitignored (library convention; hatch does not use it) — the static metadata is what unblocks resolution, so no lockfile is required. Local checks remain petsc-free via `hatch test` (features dev+test), which never pulls this dependency group. Co-Authored-By: Claude Opus 4.8 (1M context) --- pyproject.toml | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eb3fff0..78ed1f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,11 +94,27 @@ urls.Source = "https://github.com/quadbio/cellmapper" # correctly, so petsc needs no such workaround.) Drop this once slepc4py — or # cellrank's petsc extra — declares slepc. # -# The build needs a C compiler only (no Fortran/MPI/system libs) IF you pass -# PETSC_CONFIGURE_OPTIONS. Do NOT set SLEPC_CONFIGURE_OPTIONS — SLEPc inherits -# config from the built PETSc. Install (one-time source build, ~4 min, cached): -# PETSC_CONFIGURE_OPTIONS="--with-fc=0 --with-mpi=0 --with-debugging=0 --with-shared-libraries=1" \ -# uv sync --all-extras --group gpcca-fast +# petsc4py/slepc4py compute their metadata dynamically at build time. Without help, +# uv would therefore compile PETSc from source just to *resolve* — breaking every +# bare `uv sync` / `uv run` / `uv lock`, even when this group is NOT requested. The +# [[tool.uv.dependency-metadata]] entries under [tool.uv] give uv that metadata +# statically, so resolution/locking never builds anything; PETSc/SLEPc compile only +# when the group is actually installed. Keep those entries in sync with this group. +# +# INSTALLING the group is the fragile part. The recommended route is pre-built +# conda-forge binaries (no compiler, no BLAS hunting), e.g. with pixi/mamba: +# mamba install -c conda-forge petsc4py slepc4py # or: pixi add petsc4py slepc4py +# Building from PyPI source instead needs a C compiler AND a BLAS/LAPACK. The +# CellRank-documented options alone (--with-fc=0 --with-mpi=0 --with-debugging=0 +# --with-shared-libraries=1) only work on machines that already expose a system +# BLAS on the linker path; on others PETSc configure fails with "Could not find a +# functional BLAS". Adding --download-f2cblaslapack=1 gets PETSc to build but then +# SLEPc fails to link it (`cannot find -lf2cblas`), so for a source build point +# PETSc at a real shared BLAS instead, e.g.: +# PETSC_CONFIGURE_OPTIONS="--with-fc=0 --with-mpi=0 --with-debugging=0 \ +# --with-shared-libraries=1 --with-blaslapack-dir=$OPENBLAS_ROOT" \ +# uv sync --all-extras --group gpcca-fast +# Do NOT set SLEPC_CONFIGURE_OPTIONS — SLEPc inherits config from the built PETSc. # NB: a plain `uv sync --all-extras` (without --group gpcca-fast) will UNINSTALL # petsc/slepc if present — re-include the group on every refresh to keep them. [dependency-groups] @@ -133,6 +149,19 @@ envs.hatch-test.overrides.matrix.deps.env-vars = [ # jinja2==3.0.3, which conflicts with sphinx (doc extra). Override until a # pygpcca release relaxes it. jinja2>=3.1 is known-safe (cellrank does the same). override-dependencies = [ "jinja2>=3.1" ] +# Static metadata for the gpcca-fast source-only packages so uv can resolve/lock +# WITHOUT compiling PETSc (see the note above [dependency-groups]). These mirror +# the deps each package injects dynamically at build time: petsc4py -> petsc, +# slepc4py -> petsc4py + slepc (slepc4py's own sdist omits slepc). The `petsc`/ +# `slepc` library packages have no Python dependencies. Version omitted -> applies +# to all versions; petsc & petsc4py (and slepc & slepc4py) are always co-released +# at matching versions, so uv resolves them in lockstep. +dependency-metadata = [ + { name = "petsc", requires-dist = [] }, + { name = "slepc", requires-dist = [] }, + { name = "petsc4py", requires-dist = [ "numpy", "petsc" ] }, + { name = "slepc4py", requires-dist = [ "numpy", "petsc4py", "slepc" ] }, +] [tool.ruff] line-length = 120