From dbe96c6f90f743590cad479c91b1594597f12f36 Mon Sep 17 00:00:00 2001 From: Alexander Hillsley Date: Thu, 3 Sep 2026 11:13:37 -0700 Subject: [PATCH] feat(deps): move latent-lens into a `diffae` extra czi-ai/latent-lens is a private repo (visibility: internal) and not on PyPI, so as a default dependency it broke `uv sync` for anyone without access to it. Its only consumers are the diffae interpretability viewer/figure scripts. Declared as a PEP 508 direct reference so it needs no [tool.uv.sources] (allow-direct-references is already set), and build_umap_montage's top-level import is now lazy inside montage_from_cache, matching the three other latent_lens imports in that directory. Install with `uv sync --extra diffae` or `pip install ops_model[diffae]`. Paired with czbiohub-sf/ops_monorepo#(pending), which drops it from the workspace root. Co-Authored-By: Claude Opus 5 (1M context) --- pyproject.toml | 4 ++++ .../interpretability/diffae/viewer/build_umap_montage.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ed3724ac..778862a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,10 @@ dependencies = [ # https://peps.python.org/pep-0621/#dependencies-optional-dependencies [project.optional-dependencies] models = ["transformers<4.40"] +# Multiscale UMAP montages for the diffae interpretability figures. A git +# dependency, so it is kept out of the default install; only +# models/interpretability/diffae/viewer/ imports it. +diffae = ["latent-lens @ git+https://github.com/czi-ai/latent-lens"] test = ["pytest>=6.0", "pytest-cov"] dev = [ "ipykernel", diff --git a/src/ops_model/models/interpretability/diffae/viewer/build_umap_montage.py b/src/ops_model/models/interpretability/diffae/viewer/build_umap_montage.py index 87bd16cf..6d16a3ee 100644 --- a/src/ops_model/models/interpretability/diffae/viewer/build_umap_montage.py +++ b/src/ops_model/models/interpretability/diffae/viewer/build_umap_montage.py @@ -15,7 +15,6 @@ import anndata as ad from PIL import Image -from latent_lens import MontageConfig, build_montage from ..classifier.config import slugify from .precompute import VIEWER_ALPHAS @@ -79,6 +78,10 @@ def montage_from_cache(h5ad, out_zarr, cell=0, alpha=2.0, modality="phase", grai placed at the gene's position in `embedding` (obsm X_, e.g. umap or phate). Crops kept GRAYSCALE (white category tint). crop_size=256 sharp; px_per_umap≈22×crop fills canvas. `border_field` (an obs column, e.g. 'leiden_r4') draws a per-cell colored border keyed on that group.""" + # Lazy: latent-lens is the `diffae` extra, not a default install + # (`uv sync --extra diffae`, or `pip install ops_model[diffae]`). + from latent_lens import MontageConfig, build_montage + al = list(VIEWER_ALPHAS) ai = int(np.argmin([abs(a - alpha) for a in al])) # frame index for the requested α a0 = int(np.argmin([abs(a) for a in al])) # α=0 frame index (shared anchor recon)