Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ venv.bak/
# and the lockfile has never been tracked. Ignore it rather than commit a
# pinned-dep reproducibility promise the project hasn't made. Flip to tracked
# if we decide to pin deps via uv.
uv.lock
# uv.lock is committed — it is the reproducible pin the container installs from.

# Spyder project settings
.spyderproject
Expand Down
40 changes: 22 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,28 @@ RUN apt-get update -y --quiet --fix-missing && \
npm \
tmux

# The base image installs into the system interpreter (/usr/local); use `uv pip`
# so the heavy scientific stack and our deps land where `python` resolves.
RUN uv pip install --no-cache-dir \
snakemake

# The base shapepipe image ships cs_util 0.1.9, and `uv pip install -e` does NOT
# upgrade an already-satisfied dependency to meet a *new* lower bound (astral-sh/uv
# #8410). sp_validation now needs `cs_util.size` (cs_util>=0.2.1), so upgrade it
# explicitly here — otherwise the editable install silently keeps 0.1.9 and the
# galaxy import smoke test fails. shear_psf_leakage@develop allows cs-util<0.3,
# so 0.2.x satisfies the whole graph.
RUN uv pip install --no-cache-dir --upgrade 'cs_util>=0.2.1'
# The base shapepipe image provides a uv-managed venv at /app/.venv (exported as
# VIRTUAL_ENV); install sp_validation's deps into that same venv rather than
# spawning a second one under /sp_validation.
ENV UV_PROJECT_ENVIRONMENT=/app/.venv

WORKDIR /sp_validation
COPY . /sp_validation

# Install with the test + glass extras so the image can run the unit suite in CI
# *and* the GLASS map-level mock test. `glass` (Generator for Large Scale
# Structure) ships `glass.ext.camb`; `cosmology` provides the `Cosmology` wrapper
# (`Cosmology.from_camb`) GLASS consumes. Both come in via the `[glass]` extra.
RUN uv pip install --no-cache-dir -e '.[test,glass]'
# uv.lock is the SSOT: `uv sync --frozen` installs exactly what it pins, so an
# image build can never silently re-resolve and drift a base-image version (the
# numpy-past-numba drift this lockfile exists to prevent). `--inexact` keeps the
# base image's ShapePipe stack (shapepipe, ngmix, galsim, …) — packages not in
# our lock — instead of pruning them. Copy the lock + manifest first so this
# layer caches independently of source edits. Extras: test (CI unit suite),
# glass (GLASS map-level mock — pulls glass.ext.camb + the cosmology wrapper),
# workflow (Snakemake + mpi4py runners). cs_util 0.2.2 (with cs_util.size) and a
# numba-safe numpy 2.4.6 come straight from the lock, so the old ad-hoc snakemake
# and cs_util `--upgrade` layers are gone.
COPY pyproject.toml uv.lock /sp_validation/
RUN uv sync --frozen --inexact --no-install-project \
--extra test --extra glass --extra workflow

# Install sp_validation itself (editable) into the same venv; deps are already
# satisfied by the sync above.
COPY . /sp_validation
RUN uv pip install --no-deps -e .
57 changes: 54 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ authors = [
]
license = {text = "MIT"}
readme = "README.md"
requires-python = ">=3.11"
# 3.12 floor: cosmo-numba (a hard dependency below) requires >=3.12, and the
# production container is Python 3.12 (shapepipe base image). Keeping the floor
# in sync with the container is what makes `uv lock` resolvable.
requires-python = ">=3.12"
classifiers = [
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
Expand All @@ -31,7 +34,27 @@ dependencies = [
# get_theo_c_ell / get_theo_xi / PLANCK18 in cs_util.cosmo, which land via
# CosmoStat/cs_util#76 — so this goes green once #76 merges into develop.
"cs_util @ git+https://github.com/CosmoStat/cs_util.git@develop",
# Fast numba B-mode kernels (Schneider et al. 2022): the Schneider E/B split
# and COSEBIS live here, imported in b_modes.py. Tracks aguinot/cosmo-numba
# main (not published on PyPI). main carries the numpy-2 FFT fix via its
# rocket-fft dependency (which teaches numba's nopython mode to handle
# np.fft), and declares numba/numpy/rocket-fft from its requirements.txt so
# those constraints reach the resolver.
"cosmo-numba @ git+https://github.com/aguinot/cosmo-numba.git@main",
"emcee",
# numba is the load-bearing pin of this whole environment: its numpy ceiling
# (numba 0.66 -> numpy<2.5) is what keeps the resolver from drifting numpy
# forward and breaking numba/ngmix — the failure this lockfile exists to
# prevent. cosmo-numba above also carries this constraint, but we pin numba
# ourselves too: it makes the one critical constraint visible and resilient
# to cosmo-numba's dependency metadata (which has silently emptied out
# between refs before). We pin numba, never numpy directly.
"numba",
# Imported directly across src/ (calibration, plots) alongside seaborn —
# declared explicitly rather than leaned on as a seaborn transitive.
"matplotlib",
"pandas",
"pyyaml",
# SHA-pinned snapshot of getdist branch `upper_triangle_whisker`.
"getdist @ git+https://github.com/benabed/getdist.git@113cd22a9a0d013b6f72fe734be81f260f3d3be5",
"h5py",
Expand Down Expand Up @@ -78,6 +101,13 @@ dependencies = [
[project.urls]
Homepage = "https://github.com/CosmoStat/sp_validation"

[tool.uv]
# The reproducibility target is the Linux container; scope the lock to Linux
# (mirrors shapepipe) so `uv lock` resolves the linux-centric stack (pymaster,
# mpi4py) without hunting for macOS/Windows wheels. macOS dev installs still
# work via `uv pip install -e .` (unlocked), just not `uv sync` from the lock.
environments = ["sys_platform == 'linux'"]

[project.optional-dependencies]
test = [
"pytest",
Expand Down Expand Up @@ -105,6 +135,20 @@ glass = [
"glass==2025.1",
"glass.ext.camb==2023.6",
"cosmology==2022.10.9",
# fitsio: make_unions_glass_sim.py writes the mock catalogue as FITS.
"fitsio",
]
# Cosmo-inference workflow runners (workflow/scripts/*). Kept optional: the core
# library resolves without them, but the container installs this extra so the
# Snakemake workflow and cross-validation runners are available.
workflow = [
"snakemake",
# run_2pcf_highres.py drives the MPI convergence run; the container ships
# OpenMPI (/opt/ompi) so mpi4py builds against it.
"mpi4py",
# NOTE: workflow/scripts/cv_*.py also import `cv_runner`, which is not
# published or resolvable (no public repo found) — left undeclared pending
# its source. Same for `unions_wl` (scripts/check_footprint.py).
]
develop = ["sp_validation[test,docs]"]

Expand All @@ -115,7 +159,14 @@ addopts = [
"--cov=sp_validation",
"--cov-report=term",
"--cov-report=xml",
"--junitxml=pytest.xml"
"--junitxml=pytest.xml",
# The base ShapePipe image's test extra ships old pytest-pydocstyle /
# pytest-pycodestyle, whose pytest_collect_file hooks use the `path` arg the
# newer pytest our lock installs has removed — they crash collection.
# sp_validation lints with ruff, not these, so don't load them. Harmless if
# absent (`-p no:` just skips an unregistered plugin).
"-p", "no:pydocstyle",
"-p", "no:pycodestyle"
]
markers = [
"fast: marks tests as fast (deselect with '-m \"not fast\"')",
Expand All @@ -124,7 +175,7 @@ markers = [

[tool.ruff]
line-length = 88
target-version = "py311"
target-version = "py312"

# Snakemake injects a `snakemake` object into rule scripts at runtime, so ruff
# can't see where it's defined. Declaring it a builtin silences the false
Expand Down
Loading
Loading