diff --git a/.cursor/rules/nf-test-assertions.mdc b/.cursor/rules/nf-test-assertions.mdc new file mode 100644 index 00000000..fc15e45b --- /dev/null +++ b/.cursor/rules/nf-test-assertions.mdc @@ -0,0 +1,216 @@ +--- +description: nf-test assertion patterns for scdownstream — how to write platform-independent, targeted tests +globs: "**/*.nf.test" +alwaysApply: false +--- + +# nf-test Assertion Patterns + +## Core principle + +Omit **platform-sensitive** content from snapshots when outputs are **non-deterministic** (randomised ML, unstable floats in matrices, live APIs): use **`structural`** snapshots (`versions` YAML + `adata.yaml`, no `process.out` MD5s). + +When a module is **deterministic** (see [`docs/reproducibility.md`](../docs/reproducibility.md)) and **emits H5AD**, **`hash`** snapshots **include** `process.out` file MD5s plus `adata.yaml` — that is intentional regression coverage, not “raw float arrays” in the snap. + +## Assertion order — sequential, no `assertAll` + +All `then {}` blocks use **plain sequential `assert` statements** in this fixed order: + +1. `assert process.success` / `assert workflow.success` — bare, so the real failure mode is visible before deeper checks +2. `def adata = anndata(...)` — when an output H5AD (or similar) is used in field checks or in `adata.yaml` inside `snapshot()`; extract once if referenced **2+** times +3. **Field checks** — specific assertions before the snapshot (e.g. `assert "X_pca" in adata.obsm`) +4. `assert snapshot(...).match()` — last + +**Why this order**: missing fields fail in step 3 with a short message; the snapshot is the final regression net. + +If a test **must** open AnnData only after success and you keep `def adata` before `assert success` for historical reasons, treat **success before field checks and snapshot** as the hard rule when refactoring. + +**Never use `assertAll`** — it groups all failures into one report which makes CI output harder to read when a process fails. + +## Stub tests + +Stub tests always use the simple pattern: + +```groovy +test("Should run without failures - stub") { + options '-stub' + then { + assert process.success + assert snapshot(process.out).match() + } +} +``` + +## Non-stub tests — full example + +```groovy +then { + assert process.success + def adata = anndata(process.out.h5ad[0][1]) + assert "X_pca" in adata.obsm // field checks BEFORE snapshot + assert "X_pca" in adata.uns + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() // snapshot LAST — comprehensive regression +} +``` + +## `def adata` variable + +When `anndata(path)` would appear more than once in the same `then {}` block, always extract it: + +```groovy +def adata = anndata(process.out.h5ad[0][1]) +// then use adata.obsm, adata.yaml, with(adata) { ... } +``` + +For subworkflow tests, the path comes from `workflow.out`: + +```groovy +def adata = anndata(workflow.out.h5ad[0][1]) +// or workflow.out.integrations[0][1] etc. +``` + +## `with(adata)` for grouped checks + +When asserting multiple properties of the same AnnData object, use `with(adata)`: + +```groovy +assert process.success +def adata = anndata(process.out.h5ad[0][1]) +with(adata) { + assert "batch" in obs.colnames + assert "label" in obs.colnames + assert !("counts" in layers) +} +assert snapshot(process.out, path(process.out.versions[0]).yaml, adata.yaml).match() +``` + +## What to include in `snapshot()` + +Strategy names are **identical** to [`docs/reproducibility.md`](../docs/reproducibility.md) → **Test strategy (this branch)**. The doc assigns each module/subworkflow to a strategy; this table is the **default `snapshot(...)` shape per strategy** (modules use `process.*`; subworkflows use `workflow.out.*` as in the examples below). + +### Module strategies — default snapshot contents + +| Strategy | Typical `snapshot(...)` arguments | +|----------|----------------------------------| +| `hash` | `process.out`, `path(process.out.versions[0]).yaml`, `adata.yaml` — module **emits H5AD** | +| `hash (no H5AD output)` | `process.out`, `path(process.out.versions[0]).yaml` — **no** `adata.yaml` | +| `hash + structural` | Same as **`hash`** (label in doc marks modules like `scanpy/filter` with multiple scenarios) | +| `structural` | `path(process.out.versions[0]).yaml`, `adata.yaml` — **omit** `process.out` | +| `column names` | e.g. `path(process.out.versions[0]).yaml`, `adata.obs.colnames` — **omit** `process.out` MD5s | +| `column names only` | Same as **`column names`** (shorthand in `docs/reproducibility.md` module tables only) | +| `obs CSV + file names` | Per module row in doc (obs artefacts + versions; not full H5AD hash) | +| `range assertion` | Imperative range checks **plus** the snapshot mix given in that doc row | +| `stub only` | No non-stub test; stub only: `snapshot(process.out).match()` | + +### Subworkflow tests + +Patterns vary by workflow. Use the **Subworkflows** table in `docs/reproducibility.md` as the source of truth. Common building blocks: + +```groovy +// Versions as YAML (often + adata.yaml); omit full workflow.out when unstable +assert snapshot( + workflow.out.versions.collect { path(it).yaml }, + adata.yaml +).match() +``` + +```groovy +// Deterministic outputs + versions + schema +assert snapshot( + workflow.out, + workflow.out.versions.collect { path(it).yaml }, + adata.yaml +).match() +``` + +**Passthrough / unstaged H5AD paths:** `snapshot(workflow.out)` only — see later section. + +## Common mistake — dropping `process.out` from **`hash`** modules that emit H5AD + +For modules whose strategy is **`hash`** (H5AD output) in `docs/reproducibility.md`, **`process.out` must stay** in the snapshot. + +Do **not** apply this to **`structural`**, **`column names`**, **`hash (no H5AD output)`**, or other strategies that intentionally omit output MD5s. + +```groovy +// ❌ WRONG for strategy `hash` (H5AD) — drops output file hashes +assert snapshot(path(process.out.versions[0]).yaml, adata.yaml).match() + +// ✅ CORRECT for strategy `hash` (H5AD) +assert snapshot(process.out, path(process.out.versions[0]).yaml, adata.yaml).match() +``` + +## Versions channel + +- **Module tests**: `path(process.out.versions[0]).yaml` — reads the single `versions.yml` as YAML +- **Subworkflow tests**: `workflow.out.versions.collect { path(it).yaml }` — parses each file for human-readable version names + +The versions channel should never include `meta`. In module tests, `process.out.versions[0]` is a plain path (no tuple). + +## Spread multi-argument snapshots over multiple lines + +```groovy +// ✅ readable +assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml +).match() + +// ❌ hard to read +assert snapshot(process.out, path(process.out.versions[0]).yaml, adata.yaml).match() +``` + +## One snapshot call per test + +Each test can only have **one** `snapshot(...).match()` call — nf-test keys snapshots by test name. Always combine into one call. + +## Explicit field checks — always assert created fields + +Every test should explicitly assert the key outputs/fields that the module creates: +- `assert "X_pca" in adata.obsm` for new embeddings +- `assert "leiden" in adata.obs.colnames` for new obs columns +- `assert "rank_genes_groups" in adata.uns` for uns keys +- `assert "ambient_corrected" in adata.layers` for new layers + +## Known nft-anndata limitation: `uns` is top-level keys only + +`adata.uns` (and `uns` inside a `with(adata)` block) is a `Set` — it exposes only the **top-level key names**, not the nested values. This means: + +```groovy +assert "paga" in adata.uns // ✅ works — checks key presence +assert "connectivities" in adata.uns["paga"] // ❌ fails — cannot navigate into nested uns +``` + +Sub-key structure of nested `uns` entries (e.g. `uns["paga"]["connectivities"]`) is only verifiable via `adata.yaml` in the snapshot. + +## Known nft-anndata limitation: passthrough h5ad files + +`nft-anndata 0.4.0` tries to open `.h5ad` files when they appear as **staged** files in snapshot serialisation. It does **NOT** open files that were never staged into the Nextflow work directory (e.g., direct references to `/nf-core/test-datasets/...`). + +**What triggers HDF5 read** (fails on unstaged files): +- `workflow.out.h5ad.toList()` inside a snapshot +- Explicit `anndata(path).yaml` where path is a passthrough/unstaged file + +**What does NOT trigger HDF5 read** (safe for passthrough): +- `snapshot(workflow.out)` — passthrough paths are serialised as raw strings +- `workflow.out.h5ad.size()` — only counts elements + +For **load_h5ad** (which passes through files from test datasets), use: + +```groovy +then { + assert workflow.success + assert snapshot(workflow.out).match() +} +``` + +Do NOT use `anndata(workflow.out.h5ad[0][1]).yaml` for passthrough files. + +## API references + +- **nft-anndata**: [github.com/nictru/nft-anndata](https://github.com/nictru/nft-anndata) +- **nf-test path API** (yaml, json, md5, linesGzip): [nf-test.com/docs/assertions/files](https://www.nf-test.com/docs/assertions/files/) diff --git a/.cursor/rules/nf-test-snapshots.mdc b/.cursor/rules/nf-test-snapshots.mdc new file mode 100644 index 00000000..9332b64e --- /dev/null +++ b/.cursor/rules/nf-test-snapshots.mdc @@ -0,0 +1,35 @@ +--- +description: Never directly edit nf-test snapshot files; always use nftu to regenerate them +globs: "**/*.nf.test.snap" +alwaysApply: false +--- + +# nf-test Snapshot Files + +**Never manually edit `.nf.test.snap` files.** + +Directly editing snapshots cannot guarantee that the written content matches what the pipeline would actually produce. Always regenerate them using the `--update-snapshot` flag of `nf-test`: + +```bash +nf-test test --update-snapshot +``` + +The exact invocation depends on the environment (profiles, container engine, etc.). Check local aliases or project documentation for the recommended command on the current machine. + +## Example + +```bash +# ✅ GOOD — regenerate snapshots from actual test output +nf-test test --update-snapshot modules/local/scanpy/filter/tests/main.nf.test + +# ❌ BAD — manually editing the snap file +# vim modules/local/scanpy/filter/tests/main.nf.test.snap +``` + +You can pass multiple test files in one invocation: + +```bash +nf-test test --update-snapshot \ + modules/local/scanpy/filter/tests/main.nf.test \ + modules/local/scanpy/leiden/tests/main.nf.test +``` diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml index 0c547d58..7645993d 100644 --- a/.github/workflows/nf-test.yml +++ b/.github/workflows/nf-test.yml @@ -29,7 +29,7 @@ concurrency: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NFT_VER: "0.9.3" + NFT_VER: "0.9.5" NFT_WORKDIR: "~" NXF_ANSI_LOG: false NXF_SINGULARITY_CACHEDIR: ${{ github.workspace }}/.singularity diff --git a/docs/reproducibility.md b/docs/reproducibility.md new file mode 100644 index 00000000..b94c984f --- /dev/null +++ b/docs/reproducibility.md @@ -0,0 +1,176 @@ +# Module Reproducibility + +Classification of all local modules and subworkflows by output reproducibility. + +**Paired docs:** Strategy labels in the **Test strategy (this branch)** column are the same vocabulary as [`.cursor/rules/nf-test-assertions.mdc`](../.cursor/rules/nf-test-assertions.mdc). This file is the **catalog** (every component + the exact snapshot story per row). That rule is the **how-to** (assertion order, stubs, `versions` channel, passthrough H5AD, common mistakes). + +## Legend + +| Level | Meaning | +| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Fully deterministic** | Same input always produces bit-identical output across all platforms and library versions. | +| **Seeded / quasi-deterministic** | A fixed random seed is set, but floating-point results (PCA coordinates, embeddings) can differ slightly across hardware, LAPACK/BLAS backends, or library versions. File hashes may differ between platforms even when logic is correct. | +| **Non-deterministic** | Output varies between runs or platforms even with identical inputs — either due to unseeded stochasticity, iterative ML training, or live external API/download calls. | + +The **Test strategy (this branch)** column describes what the tests on this branch actually assert. Default `snapshot(...)` contents for each strategy label are in [`.cursor/rules/nf-test-assertions.mdc`](../.cursor/rules/nf-test-assertions.mdc) under **Module strategies — default snapshot contents** (and **Subworkflow tests** there for shared patterns). + +### Module tests + +| Strategy | What is checked | +| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `hash` | Module **emits H5AD**: `process.out`, `path(process.out.versions[0]).yaml`, and `adata.yaml` (AnnData read from the staged output file). Field checks run before the snapshot. Only appropriate when outputs are **deterministic** (or you accept the risk on quasi-deterministic rows such as `scanpy/sample`). | +| `hash (no H5AD output)` | Module **does not emit H5AD** (e.g. RDS, PNG, MultiQC JSON, TSV). Tests snapshot **`process.out` + `path(process.out.versions[0]).yaml` only** — no `adata.yaml` (nothing to parse as AnnData). Same row in nf-test-assertions **Module strategies — default snapshot contents**. | +| `structural` | `path(process.out.versions[0]).yaml` and `adata.yaml`; **`process.out` file hashes omitted** so matrix floats and unstable binaries do not break CI. | +| `hash + structural` | Same snapshot shape as **`hash`** (outputs + versions YAML + `adata.yaml`); the label is kept for modules that also emphasize schema checks in the test name or have multiple scenarios (e.g. `scanpy/filter`). | +| `column names` | `versions.yml` as YAML plus **obs column names** (or similar) — **no** `process.out` file MD5s. Used where cell-level values are intentionally excluded from the snapshot (e.g. annotation scores) or may drift across R/package stacks. | +| `column names only` | Shorthand in tables: same idea as `column names`. | +| `obs CSV + file names` | SingleR tests snapshot **obs-related outputs** (e.g. CSV paths/names) plus versions — not a full H5AD hash. | +| `range assertion` | A numeric value (e.g. cluster count, cell count) is asserted **outside** or **alongside** the snapshot window. | +| `stub only` | No non-stub test; stub uses `snapshot(process.out).match()` only. | + +### Subworkflow tests + +| Strategy | What is checked | +| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `structural` | Typically `workflow.out.versions.collect { path(it).yaml }` and optionally `adata.yaml`, **`workflow.out` omitted** for unstable integration outputs. | +| `hash` | **Deterministic** workflows: often `snapshot(workflow.out)` **or** a deliberate subset (e.g. `workflow.out.h5ad`) **plus** collected versions as YAML and **`adata.yaml`** when the merged H5AD is read from the work directory. **Exact `snapshot(...)` arguments differ per subworkflow** — the **Subworkflows** table below is authoritative; nf-test-assertions links subworkflow authors here. | + +**Passthrough outputs:** when workflow outputs still point at **unstaged** test-dataset paths, tests use `snapshot(workflow.out)` only and do **not** call `anndata(...).yaml` on those paths (see **Known nft-anndata limitation: passthrough h5ad files** in [`.cursor/rules/nf-test-assertions.mdc`](../.cursor/rules/nf-test-assertions.mdc)). + +--- + +## Modules + +### `adata/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| ----------------------- | -------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `adata/entropy` | Computes per-group normalised Shannon entropy of a categorical obs column and optionally plots it. | Fully deterministic | hash | +| `adata/extend` | Extends an AnnData object with additional obs/var/obsm/obsp/uns/layers data from pickle or CSV files. | Fully deterministic | hash | +| `adata/merge` | Concatenates multiple AnnData objects into inner (gene intersection) and outer (union) merged datasets. | Fully deterministic | hash | +| `adata/mergeembeddings` | Merges embeddings from a newly integrated AnnData back into the combined base+integrated AnnData by cell-index alignment. | Fully deterministic | hash | +| `adata/mygene` | Translates gene identifiers (Ensembl/Entrez/symbol) to HGNC symbols via the MyGene.info REST API. | **Non-deterministic** — live external API call; results depend on database state at query time. | ⚠️ **hash** (`process.out` + versions YAML + `adata.yaml`) — same shape as deterministic modules; **snapshots can drift** when the API response changes. | +| `adata/prepcellxgene` | Prepares an AnnData object for CellxGene by renaming embedding keys and converting counts to log-normalised float32. | Fully deterministic | hash | +| `adata/readcsv` | Reads a CSV file and writes it as an AnnData H5AD. | Fully deterministic | hash | +| `adata/readrds` | Converts an RDS file (Seurat or SingleCellExperiment) to AnnData H5AD via anndata2ri/rpy2. | Fully deterministic | hash | +| `adata/setindex` | Sets a specified obs or var column as the new AnnData index. | Fully deterministic | hash | +| `adata/splitcol` | Splits an AnnData object into one H5AD file per unique value of a specified obs column. | Fully deterministic | hash | +| `adata/splitembeddings` | Splits multiple named embeddings from a single AnnData into separate H5AD files each containing `X_emb`. | Fully deterministic | hash | +| `adata/tords` | Converts an AnnData H5AD to an RDS SingleCellExperiment object using anndataR. | Fully deterministic | hash (no H5AD output — `.rds` + versions) | +| `adata/unify` | Normalises gene symbols, resolves duplicates, unifies batch/label/condition columns, and prefixes barcodes with sample ID. | Fully deterministic | hash | +| `adata/upsetgenes` | Plots an UpSet diagram of gene set overlaps across multiple AnnData objects and outputs a MultiQC JSON image. | Fully deterministic | hash (no H5AD output — plot / MultiQC JSON + versions) | + +### `celda/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| --------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------ | +| `celda/decontx` | Removes ambient RNA contamination using the decontX variational EM algorithm (celda R package). | **Non-deterministic** — decontX uses stochastic initialisation with no fixed seed. | structural — h5ad hash omitted; versions + schema only | + +### `celldex/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| ------------------------ | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | --------------------------- | +| `celldex/fetchreference` | Downloads a named celldex reference dataset and saves it as a tar-compressed HDF5 SummarizedExperiment. | **Non-deterministic** — live download from ExperimentHub; database version varies over time. | structural | + +### `celltypes/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| ---------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | +| `celltypes/celltypist` | Annotates cell types using one or more CellTypist logistic regression models after normalising and log-transforming counts. | Fully deterministic — uses a fixed, pre-trained model with no stochastic inference at prediction time. | column names — `path(process.out.versions[0]).yaml` + `adata.obs.colnames` (no `process.out` MD5s) | +| `celltypes/singler` | Assigns cell types using the SingleR correlation-based method against one or more celldex reference datasets. | Fully deterministic — correlation/label-transfer method with no randomness. | obs CSV + file names | + +### `custom/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| --------------------- | ------------------------------------------------------------------------------------------- | ------------------- | ----------------------------------------------------- | +| `custom/collectsizes` | Pivots a TSV of per-sample cell counts at different QC stages into a MultiQC summary table. | Fully deterministic | hash (no H5AD output — TSV / MultiQC JSON + versions) | + +### `doublet_detection/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------ | +| `doublet_detection/doublet_removal` | Removes doublet cells from an AnnData object based on a threshold applied to aggregated doublet-caller predictions. | Fully deterministic | hash | +| `doublet_detection/scds` | Scores and calls doublets using bcds + cxds + hybrid (scds R package) with `set.seed(0)`. | Seeded / quasi-deterministic — seed is fixed, but internal boosting results may vary slightly across R/package versions. | column names — `versions` YAML + obs column names; no `process.out` MD5s | + +### `hugounifier/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| ------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | +| `hugounifier/get` | Computes a cross-dataset gene symbol renaming change table using the `hugo-unifier` CLI tool. | **Non-deterministic** — uses the HUGO Gene Nomenclature Committee REST API; results depend on database state at query time. | structural — CSV column names + versions only | +| `hugounifier/apply` | Applies a gene symbol renaming change table to a single AnnData H5AD file. | Fully deterministic once the change table is fixed; but see `hugounifier/get` above. | structural — versions + schema only | + +### `liana/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| --------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | +| `liana/rankaggregate` | Runs LIANA rank-aggregate ligand–receptor interaction analysis on a clustered AnnData object. | **Seeded / quasi-deterministic** — scoring methods are deterministic but floating-point aggregation can vary across BLAS/NumPy backends. | structural — versions + schema only | + +### `scanpy/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| ------------------------ | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| `scanpy/bbknn` | Constructs a batch-balanced k-nearest-neighbour graph (BBKNN) on a PCA embedding. | Fully deterministic — kNN construction is deterministic given the input embedding. | structural — versions + schema only | +| `scanpy/cellcycle` | Scores each cell for S-phase and G2M-phase activity and assigns a predicted cell cycle phase. | Fully deterministic | hash | +| `scanpy/combat` | Applies ComBat batch correction and then runs PCA, storing the result as `X_emb`. | Seeded / quasi-deterministic — ComBat is deterministic; downstream PCA floats may vary across LAPACK backends. | structural — versions + schema only | +| `scanpy/filter` | Filters cells and genes by count, gene, and mitochondrial percentage thresholds. | Fully deterministic | hash + structural — standard `hash` triple; multiple parameter scenarios | +| `scanpy/harmony` | Runs Harmony batch integration after log-normalisation and PCA, storing the corrected embedding as `X_emb`. | **Non-deterministic** — Harmony is an iterative optimisation with no fixed seed; upstream PCA is also unseeded. | structural — versions + schema only; `variance_ratio` output removed | +| `scanpy/hvgs` | Selects highly variable genes and subsets the AnnData to those genes. | Seeded / quasi-deterministic — HVG variance statistics rely on NumPy/SciPy floating-point operations that can produce slightly different results across library versions. | structural — versions + schema only | +| `scanpy/leiden` | Performs Leiden community-detection clustering at a specified resolution. | **Non-deterministic** — Leiden uses random restarts with no fixed seed. | structural — range assertion on cluster count + versions + schema | +| `scanpy/neighbors` | Computes a k-nearest-neighbour graph on a specified embedding. | Fully deterministic given a fixed input embedding. | structural — versions + schema only | +| `scanpy/paga` | Computes PAGA coarse-grained cluster connectivity and saves a graph and plot. | Fully deterministic — PAGA is a deterministic graph-summarisation step given fixed Leiden labels. | hash | +| `scanpy/pca` | Runs PCA with `random_state=0` and stores the result under a specified key. | Seeded / quasi-deterministic — seed is fixed, but float coordinates can differ across LAPACK/MKL backends. | structural — versions + schema only | +| `scanpy/plotqc` | Calculates QC metrics and produces a counts-vs-genes scatter plot for MultiQC. | Fully deterministic | hash (no H5AD output — PNG / MultiQC JSON + versions) | +| `scanpy/rankgenesgroups` | Runs differential gene expression (rank genes groups) across clusters using a configurable statistical method. | **Seeded / quasi-deterministic** — wilcoxon and t-test are deterministic in theory, but tied-rank handling and floating-point tie-breaking can differ across SciPy versions. | structural — versions + `adata.yaml`; one path with **empty h5ad** snapshots **versions only** | +| `scanpy/readh5` | Reads a 10x Genomics HDF5 (`.h5`) file and writes it as an AnnData H5AD. | Fully deterministic | hash | +| `scanpy/sample` | Down-samples cells to a fixed count or fraction using `rng=0`. | Seeded / quasi-deterministic — seed is fixed, but sampled cell set may vary across NumPy versions. | hash | +| `scanpy/umap` | Computes a UMAP embedding from a pre-built neighbour graph using `random_state=0`. | Seeded / quasi-deterministic — seed is fixed, but float coordinates vary across umap-learn/numba versions. | structural — versions + schema only | + +### `scimilarity/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| ------------------------ | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | +| `scimilarity/annotate` | Annotates cells with cell type labels using SCimilarity's kNN lookup into the pretrained reference embedding. | Fully deterministic — pure kNN lookup against a fixed reference with no stochastic inference. ⚠️ No non-stub test exists: the SCimilarity model file (~30 GB) exceeds practical test data limits. | stub only | +| `scimilarity/embed` | Embeds cells into SCimilarity's pretrained metric-learning latent space. | Fully deterministic — inference-only forward pass through a fixed pretrained network (no dropout at inference). ⚠️ No non-stub test exists: the SCimilarity model file (~30 GB) exceeds practical test data limits. | stub only | +| `scimilarity/pseudobulk` | Aggregates single-cell counts into pseudobulk profiles grouped by specified metadata columns. | Fully deterministic | hash | + +### `scvitools/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| ------------------ | ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | +| `scvitools/scanvi` | Trains a scANVI semi-supervised VAE for batch integration and label transfer with `seed=0` and deterministic CUDA ops. | Seeded / quasi-deterministic — seed and `torch.use_deterministic_algorithms(True)` are set, but variational training and early stopping can still differ across GPU drivers and torch/scvi versions. | structural — file names + versions + schema | +| `scvitools/scvi` | Trains a scVI VAE for batch integration with `seed=0` and deterministic CUDA ops. | Seeded / quasi-deterministic — same caveats as scANVI above. | structural — versions + schema only | + +### `seurat/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------- | +| `seurat/integration` | Performs Seurat v5 CCA-based batch integration after SCTransform and PCA with `set.seed(0)`, storing the corrected embedding as `X_emb`. | Seeded / quasi-deterministic — seed is fixed, but CCA/SCTransform involve floating-point iterative optimisation that can vary across Seurat/LAPACK versions. | structural — versions + schema only | + +### `soupx/` + +| Module | Description | Reproducibility | Test strategy (this branch) | +| ------- | --------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | +| `soupx` | Estimates and removes ambient RNA contamination using SoupX, preceded by Seurat clustering to define cluster-level contamination. | **Non-deterministic** — Seurat clustering is seeded but graph-based steps (Louvain/Leiden) vary across library versions; soup fraction estimates can differ across platforms. | structural — h5ad hash omitted; versions + schema only | + +--- + +## Subworkflows + +| Subworkflow | Description | Reproducibility | Test strategy (this branch) | +| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ambient_correction` | Dispatches ambient RNA correction to decontX, SoupX, or none based on a parameter. | **Non-deterministic** for decontX (no seed) and SoupX (seeded clustering but variable results); fully deterministic for the `none` passthrough. | **Scenario-dependent:** often `versions` as YAML + `adata.yaml` when an H5AD is produced; **`none` / meta-disabled** paths may snapshot **only `versions` + `workflow.out.h5ad.size()`** (counts, not hashes). | +| `celltype_assignment` | Orchestrates cell type annotation by running SingleR and/or CellTypist. | Fully deterministic — both methods are deterministic at inference time. | **`workflow.out.versions` + `workflow.out.obs.size()`** — not a full obs-file MD5 snapshot. | +| `cluster` | Full clustering pipeline: neighbours → UMAP → Leiden at multiple resolutions → Shannon entropy. | Seeded / quasi-deterministic for UMAP; **non-deterministic** due to unseeded Leiden. | structural — **`workflow.out.versions` only** (each as YAML); graph / embedding presence asserted in code outside `snapshot`. | +| `combine` | Merges all samples and runs all configured integration methods. | Inherits from constituent modules — ranges from fully deterministic (no integration) to seeded/quasi-deterministic (scVI, Harmony, Seurat). | structural — **`workflow.out.versions` (YAML) + `adata.yaml`** on merged H5AD. | +| `differential_expression` | Runs rank-genes-groups DE analysis across all combinations of clustering labels, conditions, and cell-type subsets. | Fully deterministic for the default wilcoxon/t-test methods. | structural — **`workflow.out.versions` only** (YAML); DE / MultiQC presence asserted outside `snapshot` where needed. | +| `doublet_detection` | Runs one or more doublet-detection methods (scds, solo, scrublet, doubletdetection) and removes called doublets. | **Non-deterministic** — solo, scrublet, and doubletdetection have stochastic components; scds is seeded. | structural + **range assertion** on **`n_obs`**; snapshot uses **`versions` (YAML) + `adata.yaml`**. | +| `finalize` | Assembles the final AnnData by extending it with all collected obs/obsm/uns/layers outputs. | Fully deterministic | hash — **`workflow.out.h5ad` + `workflow.out.versions` (YAML) + `adata.yaml`** — not a bare `snapshot(workflow.out)` in non-stub tests. | +| `integrate` | Applies HVG selection then one or more integration methods (scVI, scANVI, Harmony, BBKNN, ComBat, Seurat, SCimilarity). | Seeded / quasi-deterministic for scVI/scANVI/ComBat/Seurat/BBKNN; **non-deterministic** for Harmony. | structural — **`workflow.out.versions` (YAML) + `adata.yaml`** on integration H5AD (e.g. Harmony / BBKNN / ComBat tests). | +| `load_h5ad` | Loads input files in H5AD, 10x H5, RDS, or CSV format and converts all to AnnData H5AD. | Fully deterministic | hash — **`snapshot(workflow.out)` only** (passthrough-safe; avoids `anndata().yaml` on unstaged inputs per nf-test rules). | +| `per_group` | Runs PAGA, LIANA rank-aggregate, and rank-genes DE per cluster. | **Seeded / quasi-deterministic** — inherits from constituent `liana/rankaggregate` and `scanpy/rankgenesgroups` modules. | structural — **`workflow.out.versions` only** (YAML). | +| `pseudobulking` | Aggregates single-cell data into pseudobulk profiles grouped by specified metadata columns. | Fully deterministic | hash — **`workflow.out` + `versions` (YAML) + `adata.yaml`** on pseudobulk H5AD. | +| `quality_control` | Full per-sample QC pipeline: empty droplet filtering, ambient correction, gene unification, cell/gene filtering, optional downsampling, doublet detection, and optional cell cycle scoring. | Seeded / quasi-deterministic to **non-deterministic** depending on configured ambient and doublet-detection methods. | structural — **`versions` (YAML) + `workflow.out.multiqc_files`**; **heavier paths** (e.g. ambient + doublet) also add **`adata.yaml` and/or `n_obs` / `n_vars`**. | +| `scimilarity` | Embeds cells into the SCimilarity pretrained latent space and annotates with cell type labels. | Fully deterministic — fixed pretrained model, inference-only. | stub only | +| `singler` | Downloads (or uses pre-provided) celldex reference datasets and runs SingleR annotation. | Fully deterministic for annotation; **non-deterministic** if downloading references at runtime via ExperimentHub. | hash — **`workflow.out.obs` + `versions` (YAML)** — **not** full `workflow.out` MD5s. | +| `unify` | Standardises gene symbols (optionally via MyGene.info and HUGO-unifier) and normalises metadata columns (batch, label, condition). | **Non-deterministic** when `symbol_col == "none"` (triggers MyGene.info API call); fully deterministic otherwise. | hash — **`workflow.out` + `adata.yaml`**. | +| `unify_genes` | Applies HUGO-unifier to compute and apply a cross-dataset gene symbol renaming table. | **Non-deterministic** — `hugounifier/get` uses a live HUGO API; results depend on database state at query time. | structural — **`workflow.out.versions` (YAML) + `adata.yaml`** (multi-sample tests may include two `adata.yaml`). | diff --git a/modules.json b/modules.json index d4074a41..39a8e374 100644 --- a/modules.json +++ b/modules.json @@ -7,7 +7,7 @@ "nf-core": { "anndata/barcodes": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "be8a8b740b7e58b8b992774f26307f3d7df9a250", "installed_by": ["h5ad_removebackground_barcodes_cellbender_anndata", "modules"] }, "anndata/getsize": { @@ -17,13 +17,12 @@ }, "cellbender/merge": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], - "patch": "modules/nf-core/cellbender/merge/cellbender-merge.diff" + "git_sha": "380cb90926b8c28558cb11479da5ff45bc4f1c5d", + "installed_by": ["modules"] }, "cellbender/removebackground": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "b7d92b962382d64514f6c5ec6901078d90cc5a44", "installed_by": ["h5ad_removebackground_barcodes_cellbender_anndata", "modules"] }, "doubletdetection": { @@ -33,7 +32,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "5bdb098216aaf5df9c3b6343e6204cd932503c16", + "git_sha": "79b36b51048048374b642289bfe9e591ef56fe05", "installed_by": ["modules"] }, "scanpy/scrublet": { @@ -44,18 +43,16 @@ "scvitools/scar": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], - "patch": "modules/nf-core/scvitools/scar/scvitools-scar.diff" + "installed_by": ["modules"] }, "scvitools/solo": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], - "patch": "modules/nf-core/scvitools/solo/scvitools-solo.diff" + "installed_by": ["modules"] }, "untar": { "branch": "master", - "git_sha": "00ee87ebb541af0008596400ce6d5f66d79d5408", + "git_sha": "447f7bc0fa41dfc2400c8cad4c0291880dc060cf", "installed_by": ["modules"] } } @@ -64,7 +61,7 @@ "nf-core": { "h5ad_removebackground_barcodes_cellbender_anndata": { "branch": "master", - "git_sha": "ed115522edb3c5ed73a891a5d00ee839d157c650", + "git_sha": "b7d92b962382d64514f6c5ec6901078d90cc5a44", "installed_by": ["subworkflows"] }, "utils_nextflow_pipeline": { diff --git a/modules/local/adata/entropy/templates/entropy.py b/modules/local/adata/entropy/templates/entropy.py index 59b4c8c6..4c7080f4 100644 --- a/modules/local/adata/entropy/templates/entropy.py +++ b/modules/local/adata/entropy/templates/entropy.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import json import base64 diff --git a/modules/local/adata/entropy/tests/main.nf.test b/modules/local/adata/entropy/tests/main.nf.test index 8444d174..a6f708f1 100644 --- a/modules/local/adata/entropy/tests/main.nf.test +++ b/modules/local/adata/entropy/tests/main.nf.test @@ -28,10 +28,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -58,10 +61,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/entropy/tests/main.nf.test.snap b/modules/local/adata/entropy/tests/main.nf.test.snap index 8ba842dd..4edb7149 100644 --- a/modules/local/adata/entropy/tests/main.nf.test.snap +++ b/modules/local/adata/entropy/tests/main.nf.test.snap @@ -93,9 +93,55 @@ "versions": [ "versions.yml:md5,06c3be8b97dfd251b6aef3221b56d5fc" ] + }, + { + "ADATA_ENTROPY": { + "python": "3.13.12", + "scanpy": "1.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 38234, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "leiden", + "sample", + "test:entropy" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_pca" + ], + "varm": [ + "PCs" + ], + "obsp": [ + "connectivities", + "distances" + ], + "varp": [ + + ], + "uns": [ + "leiden", + "neighbors", + "pca" + ] } ], - "timestamp": "2026-03-22T09:52:42.901052235", + "timestamp": "2026-03-29T12:57:45.425691493", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/adata/extend/templates/extend.py b/modules/local/adata/extend/templates/extend.py index bf555ffd..7d75b12b 100644 --- a/modules/local/adata/extend/templates/extend.py +++ b/modules/local/adata/extend/templates/extend.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility +import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import pickle import importlib.metadata diff --git a/modules/local/adata/extend/tests/main.nf.test b/modules/local/adata/extend/tests/main.nf.test index 83a2cb77..2739c92e 100644 --- a/modules/local/adata/extend/tests/main.nf.test +++ b/modules/local/adata/extend/tests/main.nf.test @@ -31,16 +31,16 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "scvi-global-1.0_leiden" in obs.colnames - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "scvi-global-1.0_leiden" in obs.colnames + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -69,16 +69,16 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "X_scvi" in obsm - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "X_scvi" in obsm + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -113,19 +113,19 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "scvi-global-1.0_leiden" in obs.colnames - assert "scvi-global-1.0:entropy" in obs.colnames - assert "X_scvi" in obsm - assert "X_scvi-global_umap" in obsm - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "scvi-global-1.0_leiden" in obs.colnames + assert "scvi-global-1.0:entropy" in obs.colnames + assert "X_scvi" in obsm + assert "X_scvi-global_umap" in obsm + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -154,16 +154,16 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "scvi-global-1.0_paga" in uns - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "scvi-global-1.0_paga" in uns + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -192,10 +192,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -226,10 +229,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/extend/tests/main.nf.test.snap b/modules/local/adata/extend/tests/main.nf.test.snap index 1f2670f4..cb27194c 100644 --- a/modules/local/adata/extend/tests/main.nf.test.snap +++ b/modules/local/adata/extend/tests/main.nf.test.snap @@ -40,12 +40,68 @@ "versions": [ "versions.yml:md5,b2a073150918c118c3858cf4e82145f7" ] + }, + { + "ADATA_EXTEND": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "pandas": "2.3.3", + "python": "3.13.12" + } + }, + { + "n_obs": 23373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "celltypist:Adult_Human_Skin", + "celltypist:Adult_Human_Skin:conf", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "scvi-global-1.0:entropy", + "scvi-global-1.0_leiden", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_scvi", + "X_scvi-global_umap" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:14:17.984419949", + "timestamp": "2026-03-29T14:30:06.774357979", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should extend with obsm data": { @@ -89,12 +145,65 @@ "versions": [ "versions.yml:md5,b2a073150918c118c3858cf4e82145f7" ] + }, + { + "ADATA_EXTEND": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "pandas": "2.3.3", + "python": "3.13.12" + } + }, + { + "n_obs": 23373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "celltypist:Adult_Human_Skin", + "celltypist:Adult_Human_Skin:conf", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_scvi" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:13:53.551305616", + "timestamp": "2026-03-29T14:29:47.492628938", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should extend with uns data": { @@ -138,12 +247,65 @@ "versions": [ "versions.yml:md5,b2a073150918c118c3858cf4e82145f7" ] + }, + { + "ADATA_EXTEND": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "pandas": "2.3.3", + "python": "3.13.12" + } + }, + { + "n_obs": 23373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "celltypist:Adult_Human_Skin", + "celltypist:Adult_Human_Skin:conf", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + "scvi-global-1.0_paga" + ] } ], - "timestamp": "2026-03-16T15:14:39.805580912", + "timestamp": "2026-03-29T14:30:26.284065573", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should extend with obs data": { @@ -187,12 +349,66 @@ "versions": [ "versions.yml:md5,b2a073150918c118c3858cf4e82145f7" ] + }, + { + "ADATA_EXTEND": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "pandas": "2.3.3", + "python": "3.13.12" + } + }, + { + "n_obs": 23373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "celltypist:Adult_Human_Skin", + "celltypist:Adult_Human_Skin:conf", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "scvi-global-1.0_leiden", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:13:30.793377663", + "timestamp": "2026-03-29T14:29:26.551795343", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - stub": { @@ -285,12 +501,65 @@ "versions": [ "versions.yml:md5,b2a073150918c118c3858cf4e82145f7" ] + }, + { + "ADATA_EXTEND": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "pandas": "2.3.3", + "python": "3.13.12" + } + }, + { + "n_obs": 23373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "celltypist:Adult_Human_Skin", + "celltypist:Adult_Human_Skin:conf", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:14:59.60059937", + "timestamp": "2026-03-29T14:30:51.255096363", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/adata/merge/main.nf b/modules/local/adata/merge/main.nf index b5ada8d2..7d24b262 100644 --- a/modules/local/adata/merge/main.nf +++ b/modules/local/adata/merge/main.nf @@ -9,7 +9,7 @@ process ADATA_MERGE { 'community.wave.seqera.io/library/harmonypy_anndata_leidenalg_numpy_pruned:43066d5f86f18261' }" input: - tuple val(meta), path(h5ads) + tuple val(meta), path(h5ads, stageAs: 'input/sample_?.h5ad') tuple val(meta2), path(base) output: diff --git a/modules/local/adata/merge/templates/merge.py b/modules/local/adata/merge/templates/merge.py index 153f0c15..b230f5f5 100644 --- a/modules/local/adata/merge/templates/merge.py +++ b/modules/local/adata/merge/templates/merge.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform from collections import defaultdict diff --git a/modules/local/adata/merge/tests/main.nf.test b/modules/local/adata/merge/tests/main.nf.test index e9570946..b4f033f0 100644 --- a/modules/local/adata/merge/tests/main.nf.test +++ b/modules/local/adata/merge/tests/main.nf.test @@ -41,15 +41,24 @@ nextflow_process { } process { """ - input[0] = ADATA_UNIFY.out.h5ad.map{ _meta, h5ad -> [[id: 'combined'], h5ad] }.groupTuple() + input[0] = ADATA_UNIFY.out.h5ad.map{ _meta, h5ad -> [[id: 'combined'], h5ad] }.groupTuple().map{ meta, h5ads -> [meta, h5ads.sort{ a, b -> a.name <=> b.name }] } input[1] = [[], []] """ } } then { + def adata_outer = anndata(process.out.outer[0][1]) + def adata_inner = anndata(process.out.inner[0][1]) + def adata_integrate = anndata(process.out.integrate[0][1]) assert process.success - assert snapshot(process.out).match() + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata_outer.yaml, + adata_inner.yaml, + adata_integrate.yaml + ).match() } } @@ -64,7 +73,7 @@ nextflow_process { } process { """ - input[0] = ADATA_UNIFY.out.h5ad.map{ _meta, h5ad -> [[id: 'combined'], h5ad] }.groupTuple() + input[0] = ADATA_UNIFY.out.h5ad.map{ _meta, h5ad -> [[id: 'combined'], h5ad] }.groupTuple().map{ meta, h5ads -> [meta, h5ads.sort{ it.name }] } input[1] = [[], []] """ } @@ -96,8 +105,17 @@ nextflow_process { } then { + def adata_outer = anndata(process.out.outer[0][1]) + def adata_inner = anndata(process.out.inner[0][1]) + def adata_integrate = anndata(process.out.integrate[0][1]) assert process.success - assert snapshot(process.out).match() + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata_outer.yaml, + adata_inner.yaml, + adata_integrate.yaml + ).match() } } diff --git a/modules/local/adata/merge/tests/main.nf.test.snap b/modules/local/adata/merge/tests/main.nf.test.snap index a00ab4b1..9c03c681 100644 --- a/modules/local/adata/merge/tests/main.nf.test.snap +++ b/modules/local/adata/merge/tests/main.nf.test.snap @@ -62,12 +62,134 @@ "versions": [ "versions.yml:md5,f90dc837c47fb9c2207d021f2201c357" ] + }, + { + "ADATA_MERGE": { + "anndata": "0.12.10", + "python": "3.13.12", + "scanpy": "1.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 20313, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + }, + { + "n_obs": 20313, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + }, + { + "n_obs": 20313, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:43:43.452579031", + "timestamp": "2026-03-29T15:46:45.952212141", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run with base": { @@ -133,12 +255,134 @@ "versions": [ "versions.yml:md5,f90dc837c47fb9c2207d021f2201c357" ] + }, + { + "ADATA_MERGE": { + "anndata": "0.12.10", + "python": "3.13.12", + "scanpy": "1.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 20313, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + }, + { + "n_obs": 20313, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:44:08.746876922", + "timestamp": "2026-03-29T12:58:39.973626992", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without base - stub": { diff --git a/modules/local/adata/mergeembeddings/templates/merge_embeddings.py b/modules/local/adata/mergeembeddings/templates/merge_embeddings.py index c88ed493..45c0a99d 100644 --- a/modules/local/adata/mergeembeddings/templates/merge_embeddings.py +++ b/modules/local/adata/mergeembeddings/templates/merge_embeddings.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility +import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import numpy as np diff --git a/modules/local/adata/mergeembeddings/tests/main.nf.test b/modules/local/adata/mergeembeddings/tests/main.nf.test index 0146473f..a114e553 100644 --- a/modules/local/adata/mergeembeddings/tests/main.nf.test +++ b/modules/local/adata/mergeembeddings/tests/main.nf.test @@ -26,22 +26,19 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "X_emb" in obsm - // Should have cells from both base (50) and integrated (30) - assert obs.rownames.size() == 80 - } - }, - // obsm pickle should be created - { assert file(process.out.obsm[0]).name == "X_scvi.pkl" }, - // obs pickle should NOT be created for non-scanvi - { assert process.out.obs.size() == 0 } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "X_emb" in obsm + assert obs.rownames.size() == 80 + } + assert file(process.out.obsm[0]).name == "X_scvi.pkl" + assert process.out.obs.size() == 0 + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -65,22 +62,20 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "X_emb" in obsm - assert "label:scANVI" in obs.colnames - assert obs.rownames.size() == 80 - } - }, - // obsm pickle should be created - { assert file(process.out.obsm[0]).name == "X_scanvi.pkl" }, - // obs pickle SHOULD be created for scanvi - { assert file(process.out.obs[0]).name == "scanvi.pkl" } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "X_emb" in obsm + assert "label:scANVI" in obs.colnames + assert obs.rownames.size() == 80 + } + assert file(process.out.obsm[0]).name == "X_scanvi.pkl" + assert file(process.out.obs[0]).name == "scanvi.pkl" + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -106,10 +101,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/mergeembeddings/tests/main.nf.test.snap b/modules/local/adata/mergeembeddings/tests/main.nf.test.snap index a34b8b1a..f23f720f 100644 --- a/modules/local/adata/mergeembeddings/tests/main.nf.test.snap +++ b/modules/local/adata/mergeembeddings/tests/main.nf.test.snap @@ -36,12 +36,52 @@ "versions": [ "versions.yml:md5,3d07e17bd07e6c00aca3a44b734c7932" ] + }, + { + "ADATA_MERGEEMBEDDINGS": { + "anndata": "0.12.10", + "python": "3.13.12" + } + }, + { + "n_obs": 80, + "n_vars": 100, + "obs": { + "index": "_index", + "columns": [ + "label:scANVI" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_emb" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:44:44.292571618", + "timestamp": "2026-03-29T14:52:29.252580895", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - stub": { @@ -126,12 +166,52 @@ "versions": [ "versions.yml:md5,3d07e17bd07e6c00aca3a44b734c7932" ] + }, + { + "ADATA_MERGEEMBEDDINGS": { + "anndata": "0.12.10", + "python": "3.13.12" + } + }, + { + "n_obs": 80, + "n_vars": 100, + "obs": { + "index": "_index", + "columns": [ + + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_emb" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:44:33.161545572", + "timestamp": "2026-03-29T14:52:09.297927484", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/adata/mygene/tests/main.nf.test b/modules/local/adata/mygene/tests/main.nf.test index 18c5839a..75cf7191 100644 --- a/modules/local/adata/mygene/tests/main.nf.test +++ b/modules/local/adata/mygene/tests/main.nf.test @@ -25,10 +25,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -53,10 +56,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/mygene/tests/main.nf.test.snap b/modules/local/adata/mygene/tests/main.nf.test.snap index b49b8fdb..9845b96d 100644 --- a/modules/local/adata/mygene/tests/main.nf.test.snap +++ b/modules/local/adata/mygene/tests/main.nf.test.snap @@ -26,11 +26,11 @@ ] } ], + "timestamp": "2025-06-01T20:33:41.374900824", "meta": { "nf-test": "0.9.0", "nextflow": "25.04.2" - }, - "timestamp": "2025-06-01T20:33:41.374900824" + } }, "Should run without failures": { "content": [ @@ -57,12 +57,53 @@ "versions": [ "versions.yml:md5,8b217b33308585e6caf9da8cf1c23e2e" ] + }, + { + "ADATA_MYGENE": { + "anndata": "0.12.7", + "mygene": "3.2.2", + "python": "3.13.11" + } + }, + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], + "timestamp": "2026-03-29T12:58:00.211862297", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2025-12-30T17:40:13.292339816" + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } } } \ No newline at end of file diff --git a/modules/local/adata/prepcellxgene/templates/prepcellxgene.py b/modules/local/adata/prepcellxgene/templates/prepcellxgene.py index 7344abe1..86634e64 100644 --- a/modules/local/adata/prepcellxgene/templates/prepcellxgene.py +++ b/modules/local/adata/prepcellxgene/templates/prepcellxgene.py @@ -1,7 +1,10 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" +os.environ["MPLCONFIGDIR"] = "./tmp" os.environ["NUMBA_CACHE_DIR"] = "./tmp/numba" import platform diff --git a/modules/local/adata/prepcellxgene/tests/main.nf.test b/modules/local/adata/prepcellxgene/tests/main.nf.test index ed8689b5..2e92aa8a 100644 --- a/modules/local/adata/prepcellxgene/tests/main.nf.test +++ b/modules/local/adata/prepcellxgene/tests/main.nf.test @@ -25,10 +25,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -53,10 +56,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/prepcellxgene/tests/main.nf.test.snap b/modules/local/adata/prepcellxgene/tests/main.nf.test.snap index 3a5dd1bc..58b78d2a 100644 --- a/modules/local/adata/prepcellxgene/tests/main.nf.test.snap +++ b/modules/local/adata/prepcellxgene/tests/main.nf.test.snap @@ -57,12 +57,106 @@ "versions": [ "versions.yml:md5,374fc58d78d5ecc45ac7cd4b1c5a4012" ] + }, + { + "ADATA_PREPCELLXGENE": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 23364, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "bbknn-global-0.5:entropy", + "bbknn-global-0.5_leiden", + "bbknn-global-1.0:entropy", + "bbknn-global-1.0_leiden", + "celltypist:Adult_Human_Skin", + "celltypist:Adult_Human_Skin:conf", + "combat-global-0.5:entropy", + "combat-global-0.5_leiden", + "combat-global-1.0:entropy", + "combat-global-1.0_leiden", + "condition", + "harmony-global-0.5:entropy", + "harmony-global-0.5_leiden", + "harmony-global-1.0:entropy", + "harmony-global-1.0_leiden", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "scvi-global-0.5:entropy", + "scvi-global-0.5_leiden", + "scvi-global-1.0:entropy", + "scvi-global-1.0_leiden", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + "intersection" + ] + }, + "layers": [ + + ], + "obsm": [ + "X_bbknn-global_umap", + "X_combat-global_umap", + "X_harmony-global_umap", + "X_scvi-global_umap", + "combat", + "harmony", + "scvi" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + "bbknn-global-0.5_characteristic_genes", + "bbknn-global-0.5_paga", + "bbknn-global-1.0_characteristic_genes", + "bbknn-global-1.0_paga", + "combat-global-0.5_characteristic_genes", + "combat-global-0.5_liana", + "combat-global-0.5_paga", + "combat-global-1.0_characteristic_genes", + "combat-global-1.0_liana", + "combat-global-1.0_paga", + "harmony-global-0.5_characteristic_genes", + "harmony-global-0.5_paga", + "harmony-global-1.0_characteristic_genes", + "harmony-global-1.0_paga", + "log1p", + "scvi-global-0.5_characteristic_genes", + "scvi-global-0.5_paga", + "scvi-global-1.0_characteristic_genes", + "scvi-global-1.0_paga" + ] } ], - "timestamp": "2026-03-16T15:35:08.942215746", + "timestamp": "2026-03-29T12:57:46.020211425", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/adata/readcsv/templates/readcsv.py b/modules/local/adata/readcsv/templates/readcsv.py index 3f535a43..45e4445d 100644 --- a/modules/local/adata/readcsv/templates/readcsv.py +++ b/modules/local/adata/readcsv/templates/readcsv.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility +import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import importlib.metadata import anndata as ad diff --git a/modules/local/adata/readcsv/tests/main.nf.test b/modules/local/adata/readcsv/tests/main.nf.test index f6f808fd..6e329327 100644 --- a/modules/local/adata/readcsv/tests/main.nf.test +++ b/modules/local/adata/readcsv/tests/main.nf.test @@ -25,10 +25,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -53,10 +56,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/readcsv/tests/main.nf.test.snap b/modules/local/adata/readcsv/tests/main.nf.test.snap index 1649095a..084a952b 100644 --- a/modules/local/adata/readcsv/tests/main.nf.test.snap +++ b/modules/local/adata/readcsv/tests/main.nf.test.snap @@ -57,12 +57,53 @@ "versions": [ "versions.yml:md5,04012b0101dd2263a1ebe8a9870dcf2c" ] + }, + { + "ADATA_READCSV": { + "anndata": "0.12.10", + "pandas": "2.3.3", + "python": "3.13.12" + } + }, + { + "n_obs": 100, + "n_vars": 100, + "obs": { + "index": "_index", + "columns": [ + + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:13:30.494289545", + "timestamp": "2026-03-29T13:50:20.11008928", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/adata/readrds/tests/main.nf.test b/modules/local/adata/readrds/tests/main.nf.test index e286456e..6e579c3e 100644 --- a/modules/local/adata/readrds/tests/main.nf.test +++ b/modules/local/adata/readrds/tests/main.nf.test @@ -25,10 +25,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -53,10 +56,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } @@ -79,10 +81,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -107,10 +112,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/readrds/tests/main.nf.test.snap b/modules/local/adata/readrds/tests/main.nf.test.snap index 17139824..329e5554 100644 --- a/modules/local/adata/readrds/tests/main.nf.test.snap +++ b/modules/local/adata/readrds/tests/main.nf.test.snap @@ -24,13 +24,59 @@ "versions": [ "versions.yml:md5,97a57daf2be7236a765bbf214c58c444" ] + }, + { + "ADATA_READRDS": { + "anndata": "0.11.1", + "anndata2ri": "1.3.2", + "rpy2": "3.5.11", + "pandas": "2.2.3", + "seurat": "5.1.0" + } + }, + { + "n_obs": 12634, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "feature_types", + "gene_ids", + "gene_symbol", + "gene_versions" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], + "timestamp": "2026-03-29T13:46:53.842611485", "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.2" - }, - "timestamp": "2025-06-02T14:05:30.580002034" + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } }, "Should read SCE file - stub": { "content": [ @@ -59,11 +105,11 @@ ] } ], + "timestamp": "2025-06-02T14:05:41.785903395", "meta": { "nf-test": "0.9.0", "nextflow": "25.04.2" - }, - "timestamp": "2025-06-02T14:05:41.785903395" + } }, "Should read seurat file": { "content": [ @@ -90,13 +136,60 @@ "versions": [ "versions.yml:md5,97a57daf2be7236a765bbf214c58c444" ] + }, + { + "ADATA_READRDS": { + "anndata": "0.11.1", + "anndata2ri": "1.3.2", + "rpy2": "3.5.11", + "pandas": "2.2.3", + "seurat": "5.1.0" + } + }, + { + "n_obs": 12650, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "ident", + "nCount_RNA", + "nFeature_RNA", + "orig.ident", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], + "timestamp": "2026-03-29T13:46:07.673656598", "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.2" - }, - "timestamp": "2025-06-02T14:04:47.09491976" + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } }, "Should read seurat file - stub": { "content": [ @@ -125,10 +218,10 @@ ] } ], + "timestamp": "2025-06-02T14:04:58.058486624", "meta": { "nf-test": "0.9.0", "nextflow": "25.04.2" - }, - "timestamp": "2025-06-02T14:04:58.058486624" + } } } \ No newline at end of file diff --git a/modules/local/adata/setindex/templates/setindex.py b/modules/local/adata/setindex/templates/setindex.py index f07a00d0..70c38d41 100644 --- a/modules/local/adata/setindex/templates/setindex.py +++ b/modules/local/adata/setindex/templates/setindex.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility +import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import importlib.metadata import anndata as ad diff --git a/modules/local/adata/setindex/tests/main.nf.test b/modules/local/adata/setindex/tests/main.nf.test index 50062bf2..9a540ba9 100644 --- a/modules/local/adata/setindex/tests/main.nf.test +++ b/modules/local/adata/setindex/tests/main.nf.test @@ -27,10 +27,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -55,10 +58,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -85,10 +91,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/setindex/tests/main.nf.test.snap b/modules/local/adata/setindex/tests/main.nf.test.snap index 8fba2435..a482f423 100644 --- a/modules/local/adata/setindex/tests/main.nf.test.snap +++ b/modules/local/adata/setindex/tests/main.nf.test.snap @@ -24,12 +24,52 @@ "versions": [ "versions.yml:md5,3849ee644c0cc7554e8328607967f0f0" ] + }, + { + "ADATA_SETINDEX": { + "anndata": "0.12.10", + "python": "3.13.12" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:13:51.064093335", + "timestamp": "2026-03-29T12:58:00.87153549", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - obs": { @@ -57,12 +97,52 @@ "versions": [ "versions.yml:md5,3849ee644c0cc7554e8328607967f0f0" ] + }, + { + "ADATA_SETINDEX": { + "anndata": "0.12.10", + "python": "3.13.12" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:13:30.688344891", + "timestamp": "2026-03-29T12:57:38.294706928", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - stub": { diff --git a/modules/local/adata/splitcol/templates/split_column.py b/modules/local/adata/splitcol/templates/split_column.py index 17ec8359..668c7f0a 100644 --- a/modules/local/adata/splitcol/templates/split_column.py +++ b/modules/local/adata/splitcol/templates/split_column.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility +import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import importlib.metadata diff --git a/modules/local/adata/splitcol/tests/main.nf.test b/modules/local/adata/splitcol/tests/main.nf.test index 8d4cc980..36c24d5c 100644 --- a/modules/local/adata/splitcol/tests/main.nf.test +++ b/modules/local/adata/splitcol/tests/main.nf.test @@ -22,8 +22,13 @@ nextflow_process { } then { + def adatas = process.out.h5ad[0][1].collect { anndata(it) } assert process.success - assert snapshot(process.out).match() + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adatas.collect { it.yaml } + ).match() } } diff --git a/modules/local/adata/splitcol/tests/main.nf.test.snap b/modules/local/adata/splitcol/tests/main.nf.test.snap index 4d9df59a..d679958a 100644 --- a/modules/local/adata/splitcol/tests/main.nf.test.snap +++ b/modules/local/adata/splitcol/tests/main.nf.test.snap @@ -71,12 +71,122 @@ "versions": [ "versions.yml:md5,a74338e0a89adfeb07bdad07af3877f7" ] - } + }, + { + "ADATA_SPLITCOL": { + "anndata": "0.12.10", + "python": "3.13.12" + } + }, + [ + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + }, + { + "n_obs": 12640, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + }, + { + "n_obs": 12654, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } + ] ], - "timestamp": "2026-03-16T15:13:30.797750659", + "timestamp": "2026-03-29T12:57:38.085403361", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/adata/splitembeddings/templates/split_embeddings.py b/modules/local/adata/splitembeddings/templates/split_embeddings.py index d0f227ac..aecef5b4 100644 --- a/modules/local/adata/splitembeddings/templates/split_embeddings.py +++ b/modules/local/adata/splitembeddings/templates/split_embeddings.py @@ -1,8 +1,11 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility +import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform -import pandas as pd import anndata as ad import yaml diff --git a/modules/local/adata/splitembeddings/tests/main.nf.test b/modules/local/adata/splitembeddings/tests/main.nf.test index 7eb6f617..2113b0e3 100644 --- a/modules/local/adata/splitembeddings/tests/main.nf.test +++ b/modules/local/adata/splitembeddings/tests/main.nf.test @@ -26,10 +26,14 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert "X_emb" in adata.obsm + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -55,10 +59,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/splitembeddings/tests/main.nf.test.snap b/modules/local/adata/splitembeddings/tests/main.nf.test.snap index 93aca767..911f0c48 100644 --- a/modules/local/adata/splitembeddings/tests/main.nf.test.snap +++ b/modules/local/adata/splitembeddings/tests/main.nf.test.snap @@ -57,12 +57,97 @@ "versions": [ "versions.yml:md5,c19d8adf68e8f111100a334d06042be0" ] + }, + { + "ADATA_SPLITEMBEDDINGS": { + "anndata": "0.12.10", + "python": "3.13.12" + } + }, + { + "n_obs": 23364, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "bbknn-global-0.5:entropy", + "bbknn-global-0.5_leiden", + "bbknn-global-1.0:entropy", + "bbknn-global-1.0_leiden", + "celltypist:Adult_Human_Skin", + "celltypist:Adult_Human_Skin:conf", + "combat-global-0.5:entropy", + "combat-global-0.5_leiden", + "combat-global-1.0:entropy", + "combat-global-1.0_leiden", + "condition", + "harmony-global-0.5:entropy", + "harmony-global-0.5_leiden", + "harmony-global-1.0:entropy", + "harmony-global-1.0_leiden", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "scvi-global-0.5:entropy", + "scvi-global-0.5_leiden", + "scvi-global-1.0:entropy", + "scvi-global-1.0_leiden", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + "intersection" + ] + }, + "layers": [ + + ], + "obsm": [ + "X_emb" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + "bbknn-global-0.5_characteristic_genes", + "bbknn-global-0.5_paga", + "bbknn-global-1.0_characteristic_genes", + "bbknn-global-1.0_paga", + "combat-global-0.5_characteristic_genes", + "combat-global-0.5_liana", + "combat-global-0.5_paga", + "combat-global-1.0_characteristic_genes", + "combat-global-1.0_liana", + "combat-global-1.0_paga", + "harmony-global-0.5_characteristic_genes", + "harmony-global-0.5_paga", + "harmony-global-1.0_characteristic_genes", + "harmony-global-1.0_paga", + "scvi-global-0.5_characteristic_genes", + "scvi-global-0.5_paga", + "scvi-global-1.0_characteristic_genes", + "scvi-global-1.0_paga" + ] } ], - "timestamp": "2026-03-16T15:13:31.208997494", + "timestamp": "2026-03-29T14:55:42.179483745", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/adata/tords/tests/main.nf.test b/modules/local/adata/tords/tests/main.nf.test index aa4bac0b..df3ddc6a 100644 --- a/modules/local/adata/tords/tests/main.nf.test +++ b/modules/local/adata/tords/tests/main.nf.test @@ -26,10 +26,11 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() } } @@ -55,10 +56,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/tords/tests/main.nf.test.snap b/modules/local/adata/tords/tests/main.nf.test.snap index 8954c160..9c896bd5 100644 --- a/modules/local/adata/tords/tests/main.nf.test.snap +++ b/modules/local/adata/tords/tests/main.nf.test.snap @@ -57,12 +57,17 @@ "versions": [ "versions.yml:md5,bf93dcd42995e7fa34eac37384568f9d" ] + }, + { + "ADATA_TORDS": { + "anndataR": "1.0.2" + } } ], - "timestamp": "2026-03-14T21:05:44.197188707", + "timestamp": "2026-03-29T14:52:16.412480466", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/adata/unify/templates/unify.py b/modules/local/adata/unify/templates/unify.py index dbd11a31..0e8126c3 100644 --- a/modules/local/adata/unify/templates/unify.py +++ b/modules/local/adata/unify/templates/unify.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" os.environ["NUMBA_CACHE_DIR"] = "./tmp/numba" diff --git a/modules/local/adata/unify/tests/main.nf.test b/modules/local/adata/unify/tests/main.nf.test index b2fc48fa..dc636c8a 100644 --- a/modules/local/adata/unify/tests/main.nf.test +++ b/modules/local/adata/unify/tests/main.nf.test @@ -36,20 +36,20 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "batch" in obs.colnames - assert "label" in obs.colnames - assert "sample" in obs.colnames - assert !("counts" in layers) - assert layers.size() == 0 - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "batch" in obs.colnames + assert "label" in obs.colnames + assert "sample" in obs.colnames + assert !("counts" in layers) + assert layers.size() == 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -78,19 +78,19 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "batch" in obs.colnames - assert "label" in obs.colnames - assert "sample" in obs.colnames - assert layers.size() == 0 - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "batch" in obs.colnames + assert "label" in obs.colnames + assert "sample" in obs.colnames + assert layers.size() == 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -123,10 +123,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -155,16 +158,16 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "original_index" in var.colnames - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "original_index" in var.colnames + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -197,11 +200,14 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert adata.var.rownames.toUnique().size() == adata.var.rownames.size() + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -230,11 +236,14 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert adata.var.rownames.toUnique().size() == adata.var.rownames.size() + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -263,11 +272,14 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert adata.var.rownames.toUnique().size() == adata.var.rownames.size() + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -296,11 +308,15 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + // make_unique adds numeric suffixes — var names are unique but not aggregated + assert adata.var.rownames.toUnique().size() == adata.var.rownames.size() + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -333,17 +349,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - // After isoform aggregation, numeric suffixes should be removed - assert var.rownames.every { !it.matches(/.*\\.\\d+$/) } - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + // After isoform aggregation, numeric suffixes should be removed + assert var.rownames.every { !it.matches(/.*\\.\\d+$/) } + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -376,18 +392,18 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "batch" in obs.colnames - assert !("batch_id" in obs.colnames) - assert obs.get("batch").unique().every { it.contains("_test") } - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "batch" in obs.colnames + assert !("batch_id" in obs.colnames) + assert obs.get("batch").unique().every { it.contains("_test") } + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -416,17 +432,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "batch" in obs.colnames - assert obs.get("batch").unique().every { it.contains("_test") } - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "batch" in obs.colnames + assert obs.get("batch").unique().every { it.contains("_test") } + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -455,17 +471,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "batch" in obs.colnames - assert obs.get("batch").unique().every { it == "test_test" } - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "batch" in obs.colnames + assert obs.get("batch").unique().every { it == "test_test" } + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -528,18 +544,18 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "label" in obs.colnames - assert !("cell_type" in obs.colnames) - assert obs.get("label").unique().size() > 0 - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "label" in obs.colnames + assert !("cell_type" in obs.colnames) + assert obs.get("label").unique().size() > 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -568,17 +584,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "label" in obs.colnames - assert obs.get("label").unique().size() > 0 - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "label" in obs.colnames + assert obs.get("label").unique().size() > 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -607,17 +623,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "label" in obs.colnames - assert obs.get("label").unique().every { it == "Unknown" } - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "label" in obs.colnames + assert obs.get("label").unique().every { it == "Unknown" } + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -646,17 +662,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "label" in obs.colnames - assert "Unknown" in obs.get("label").unique() - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "label" in obs.colnames + assert "Unknown" in obs.get("label").unique() + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -685,17 +701,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "label" in obs.colnames - assert "Unknown" in obs.get("label").unique() - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "label" in obs.colnames + assert "Unknown" in obs.get("label").unique() + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -724,18 +740,18 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "label" in obs.colnames - // Labels should be normalized (no spaces, dashes, special chars) - assert obs.get("label").unique().every { !it.contains(" ") && !it.contains("-") && !it.contains("+") } - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "label" in obs.colnames + // Labels should be normalized (no spaces, dashes, special chars) + assert obs.get("label").unique().every { !it.contains(" ") && !it.contains("-") && !it.contains("+") } + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -798,18 +814,18 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "condition" in obs.colnames - assert !("disease_state" in obs.colnames) - assert obs.get("condition").unique().size() > 0 - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "condition" in obs.colnames + assert !("disease_state" in obs.colnames) + assert obs.get("condition").unique().size() > 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -838,17 +854,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "condition" in obs.colnames - assert obs.get("condition").unique().size() > 0 - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "condition" in obs.colnames + assert obs.get("condition").unique().size() > 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -877,17 +893,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "condition" in obs.colnames - assert obs.get("condition").unique().every { it == "Unknown" } - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "condition" in obs.colnames + assert obs.get("condition").unique().every { it == "Unknown" } + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -950,10 +966,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -982,10 +1001,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -1018,17 +1040,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - // All cell names should be prefixed - assert obs.rownames.every { it.startsWith("test_") } - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + // All cell names should be prefixed + assert obs.rownames.every { it.startsWith("test_") } + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -1057,18 +1079,18 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "sample" in obs.colnames - assert "sample_original" in obs.colnames - assert obs.get("sample").unique().every { it == "test" } - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "sample" in obs.colnames + assert "sample_original" in obs.colnames + assert obs.get("sample").unique().every { it == "test" } + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -1097,17 +1119,17 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "sample" in obs.colnames - assert obs.get("sample").unique().every { it == "test" } - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "sample" in obs.colnames + assert obs.get("sample").unique().every { it == "test" } + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -1140,19 +1162,19 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert obsm.size() == 0 - assert varm.size() == 0 - assert uns.size() == 0 - assert layers.size() == 0 - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert obsm.size() == 0 + assert varm.size() == 0 + assert uns.size() == 0 + assert layers.size() == 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -1185,22 +1207,22 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "batch" in obs.colnames - assert "label" in obs.colnames - assert "sample" in obs.colnames - assert obsm.size() == 0 - assert varm.size() == 0 - assert uns.size() == 0 - assert layers.size() == 0 - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "batch" in obs.colnames + assert "label" in obs.colnames + assert "sample" in obs.colnames + assert obsm.size() == 0 + assert varm.size() == 0 + assert uns.size() == 0 + assert layers.size() == 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -1229,22 +1251,22 @@ nextflow_process { } then { - def filename = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() }, - { - with(anndata(filename)) { - assert "batch" in obs.colnames - assert "label" in obs.colnames - assert "sample" in obs.colnames - assert obsm.size() == 0 - assert varm.size() == 0 - assert uns.size() == 0 - assert layers.size() == 0 - } - } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "batch" in obs.colnames + assert "label" in obs.colnames + assert "sample" in obs.colnames + assert obsm.size() == 0 + assert varm.size() == 0 + assert uns.size() == 0 + assert layers.size() == 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -1279,10 +1301,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/unify/tests/main.nf.test.snap b/modules/local/adata/unify/tests/main.nf.test.snap index ae86783a..73121bfb 100644 --- a/modules/local/adata/unify/tests/main.nf.test.snap +++ b/modules/local/adata/unify/tests/main.nf.test.snap @@ -24,12 +24,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:17:15.684411771", + "timestamp": "2026-03-29T14:56:53.251161983", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle sample column with different value": { @@ -57,12 +103,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:19:52.912657028", + "timestamp": "2026-03-29T15:01:01.165008808", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle symbols in column": { @@ -90,12 +182,59 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "original_index", + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:14:30.460619874", + "timestamp": "2026-03-29T14:53:06.26109274", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle label column with different name": { @@ -123,12 +262,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:17:04.588955265", + "timestamp": "2026-03-29T14:56:34.900590714", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should create condition column when missing": { @@ -156,12 +341,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:18:48.352425666", + "timestamp": "2026-03-29T14:59:24.088148335", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle label column with unknown values": { @@ -189,12 +420,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:17:38.16180871", + "timestamp": "2026-03-29T14:57:31.870669065", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle duplicates with sum aggregation": { @@ -222,12 +499,59 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "original_index", + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:14:59.92375867", + "timestamp": "2026-03-29T14:53:32.347938099", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should create batch column when missing": { @@ -255,12 +579,57 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:16:42.291640291", + "timestamp": "2026-03-29T14:55:55.84386358", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - stub": { @@ -321,12 +690,59 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9937, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "original_index", + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:15:57.903315865", + "timestamp": "2026-03-29T14:54:38.882767578", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle condition column with different name": { @@ -354,12 +770,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:18:22.557718057", + "timestamp": "2026-03-29T14:58:45.748755829", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle duplicates with mean aggregation": { @@ -387,12 +849,59 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "original_index", + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:15:28.4354681", + "timestamp": "2026-03-29T14:53:56.526120053", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should aggregate isoforms": { @@ -420,12 +929,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:16:08.914108958", + "timestamp": "2026-03-29T14:54:57.071278012", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle condition column already named condition": { @@ -453,12 +1008,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:18:35.814191761", + "timestamp": "2026-03-29T14:59:04.275089995", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should normalize label column with special characters": { @@ -486,12 +1087,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:18:01.193993289", + "timestamp": "2026-03-29T14:58:09.361409579", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should create label column when missing": { @@ -519,12 +1166,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:17:26.892769495", + "timestamp": "2026-03-29T14:57:12.4063596", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle CSR sparse matrix": { @@ -552,12 +1245,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:19:12.458275697", + "timestamp": "2026-03-29T15:00:01.784544718", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle CSC sparse matrix": { @@ -585,12 +1324,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:19:26.441833105", + "timestamp": "2026-03-29T15:00:21.051026466", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle batch column with different name": { @@ -618,12 +1403,57 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:16:19.536570356", + "timestamp": "2026-03-29T14:55:16.158601868", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle label column with NaN values": { @@ -651,12 +1481,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:17:49.960531221", + "timestamp": "2026-03-29T14:57:50.573060947", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should remove obsm, varm, uns, and layers": { @@ -684,12 +1560,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:20:17.793802423", + "timestamp": "2026-03-29T15:01:41.445930077", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle duplicates with max aggregation": { @@ -717,12 +1639,59 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "original_index", + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:15:47.399791749", + "timestamp": "2026-03-29T14:54:20.647392444", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should create sample column when missing": { @@ -750,12 +1719,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:20:04.777517593", + "timestamp": "2026-03-29T15:01:21.148229802", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle batch column already named batch": { @@ -783,12 +1798,57 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:16:31.488655855", + "timestamp": "2026-03-29T14:55:35.420110559", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle complex structure": { @@ -816,12 +1876,60 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "gene_id", + "original_index", + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:20:42.731739831", + "timestamp": "2026-03-29T15:02:22.64116359", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle counts in layer": { @@ -849,12 +1957,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:13:51.662484416", + "timestamp": "2026-03-29T14:52:30.401577773", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle counts in X matrix": { @@ -882,12 +2036,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:13:30.614823898", + "timestamp": "2026-03-29T14:52:10.928524596", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle symbols as index": { @@ -915,12 +2115,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:14:12.108232932", + "timestamp": "2026-03-29T14:52:48.132443363", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle minimal structure": { @@ -948,12 +2194,57 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:20:30.122685513", + "timestamp": "2026-03-29T15:02:01.13903733", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should handle duplicate cell names": { @@ -981,12 +2272,58 @@ "versions": [ "versions.yml:md5,3584046bdacc455c1d7d03d51ded03cb" ] + }, + { + "ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:19:39.263298116", + "timestamp": "2026-03-29T15:00:41.681029229", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/adata/upsetgenes/templates/upsetplot.py b/modules/local/adata/upsetgenes/templates/upsetplot.py index 625573a5..1f87cebc 100644 --- a/modules/local/adata/upsetgenes/templates/upsetplot.py +++ b/modules/local/adata/upsetgenes/templates/upsetplot.py @@ -1,6 +1,9 @@ #!/opt/conda/bin/python +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import base64 import json diff --git a/modules/local/adata/upsetgenes/tests/main.nf.test b/modules/local/adata/upsetgenes/tests/main.nf.test index a53f8d69..a104c389 100644 --- a/modules/local/adata/upsetgenes/tests/main.nf.test +++ b/modules/local/adata/upsetgenes/tests/main.nf.test @@ -29,10 +29,11 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() } } @@ -61,10 +62,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/adata/upsetgenes/tests/main.nf.test.snap b/modules/local/adata/upsetgenes/tests/main.nf.test.snap index 64402386..1e2ad56c 100644 --- a/modules/local/adata/upsetgenes/tests/main.nf.test.snap +++ b/modules/local/adata/upsetgenes/tests/main.nf.test.snap @@ -69,12 +69,20 @@ "versions": [ "versions.yml:md5,e45c6196557674c1f638289fd20f6cf3" ] + }, + { + "ADATA_UPSETGENES": { + "anndata": "0.12.10", + "matplotlib": "3.10.8", + "python": "3.13.12", + "upsetplot": "0.9.0" + } } ], - "timestamp": "2026-03-16T15:15:06.26124523", + "timestamp": "2026-03-29T14:52:10.760796153", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/celda/decontx/tests/main.nf.test b/modules/local/celda/decontx/tests/main.nf.test index acceff33..03dcfaba 100644 --- a/modules/local/celda/decontx/tests/main.nf.test +++ b/modules/local/celda/decontx/tests/main.nf.test @@ -29,12 +29,14 @@ nextflow_process { } then { - def h5ad = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out.versions).match() }, - { assert anndata(h5ad).obs.rownames.size() > 0 } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + // output written to X, so no named decontx layer + assert !("ambient_corrected_decontx" in adata.layers) + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -61,12 +63,14 @@ nextflow_process { } then { - def h5ad = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out.versions).match() }, - { assert anndata(h5ad).obs.rownames.size() > 0 } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + // output written to X, so no named decontx layer + assert !("ambient_corrected_decontx" in adata.layers) + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -93,12 +97,14 @@ nextflow_process { } then { - def h5ad = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out.versions).match() }, - { assert anndata(h5ad).obs.rownames.size() > 0 } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + // output written to X, so no named decontx layer + assert !("ambient_corrected_decontx" in adata.layers) + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -127,10 +133,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } @@ -157,12 +162,14 @@ nextflow_process { } then { - def h5ad = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out.versions).match() }, - { assert anndata(h5ad).obs.rownames.size() > 0 } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + // output written to X, so no named decontx layer + assert !("ambient_corrected_decontx" in adata.layers) + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -189,12 +196,15 @@ nextflow_process { } then { - def h5ad = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out.versions).match() }, - { assert "ambient_corrected_decontx" in anndata(h5ad).layers } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + + assert "ambient_corrected_decontx" in adata.layers + + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -223,10 +233,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/celda/decontx/tests/main.nf.test.snap b/modules/local/celda/decontx/tests/main.nf.test.snap index b44c22ec..6dac3570 100644 --- a/modules/local/celda/decontx/tests/main.nf.test.snap +++ b/modules/local/celda/decontx/tests/main.nf.test.snap @@ -1,23 +1,99 @@ { "Should run without failures without batch column": { "content": [ - [ - "versions.yml:md5,7aee6256bf034aaa7fef6492db7bcb88" - ] + { + "CELDA_DECONTX": { + "r": "4.5.3", + "anndataR": "1.0.2", + "celda": "1.26.0" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T22:48:36.887205847", + "timestamp": "2026-03-29T11:18:08.048436803", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures without raw - single batch": { "content": [ - [ - "versions.yml:md5,7aee6256bf034aaa7fef6492db7bcb88" - ] + { + "CELDA_DECONTX": { + "r": "4.5.3", + "anndataR": "1.0.2", + "celda": "1.26.0" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T22:55:17.598632412", + "timestamp": "2026-03-29T11:21:17.900019258", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -25,11 +101,49 @@ }, "Should run without failures with raw": { "content": [ - [ - "versions.yml:md5,7aee6256bf034aaa7fef6492db7bcb88" - ] + { + "CELDA_DECONTX": { + "r": "4.5.3", + "anndataR": "1.0.2", + "celda": "1.26.0" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T22:58:14.087588206", + "timestamp": "2026-03-29T11:24:51.060377162", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -37,11 +151,50 @@ }, "Should write to a custom output layer": { "content": [ - [ - "versions.yml:md5,7aee6256bf034aaa7fef6492db7bcb88" - ] + { + "CELDA_DECONTX": { + "r": "4.5.3", + "anndataR": "1.0.2", + "celda": "1.26.0" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "ambient_corrected_decontx", + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T22:59:07.21446379", + "timestamp": "2026-03-29T11:25:48.190196709", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -74,19 +227,57 @@ ] } ], - "timestamp": "2026-03-15T21:35:01.416848398", + "timestamp": "2026-03-25T16:08:49.849468757", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures without raw - multi-batch": { "content": [ - [ - "versions.yml:md5,7aee6256bf034aaa7fef6492db7bcb88" - ] + { + "CELDA_DECONTX": { + "r": "4.5.3", + "anndataR": "1.0.2", + "celda": "1.26.0" + } + }, + { + "n_obs": 38234, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T22:57:05.67552094", + "timestamp": "2026-03-29T11:23:38.441578672", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -119,10 +310,10 @@ ] } ], - "timestamp": "2026-03-15T21:28:55.554328929", + "timestamp": "2026-03-25T16:06:07.366572356", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/celldex/fetchreference/tests/main.nf.test.snap b/modules/local/celldex/fetchreference/tests/main.nf.test.snap index cf32a325..876e1f02 100644 --- a/modules/local/celldex/fetchreference/tests/main.nf.test.snap +++ b/modules/local/celldex/fetchreference/tests/main.nf.test.snap @@ -26,11 +26,11 @@ ] } ], + "timestamp": "2025-07-12T19:01:49.530052242", "meta": { "nf-test": "0.9.2", "nextflow": "25.04.6" - }, - "timestamp": "2025-07-12T19:01:49.530052242" + } }, "Should run without failures": { "content": [ @@ -48,10 +48,10 @@ } } ], + "timestamp": "2025-07-12T19:01:38.261026661", "meta": { "nf-test": "0.9.2", "nextflow": "25.04.6" - }, - "timestamp": "2025-07-12T19:01:38.261026661" + } } } \ No newline at end of file diff --git a/modules/local/celltypes/celltypist/tests/main.nf.test b/modules/local/celltypes/celltypist/tests/main.nf.test index 4c22a760..81477ffa 100644 --- a/modules/local/celltypes/celltypist/tests/main.nf.test +++ b/modules/local/celltypes/celltypist/tests/main.nf.test @@ -27,10 +27,16 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "celltypist:Adult_COVID19_PBMC" in obs.colnames + assert "celltypist:Adult_COVID19_PBMC:conf" in obs.colnames + } + assert snapshot( + path(process.out.versions[0]).yaml, + adata.obs.colnames + ).match() } } @@ -55,10 +61,16 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "celltypist:Adult_COVID19_PBMC" in obs.colnames + assert "celltypist:Adult_COVID19_PBMC:conf" in obs.colnames + } + assert snapshot( + path(process.out.versions[0]).yaml, + adata.obs.colnames + ).match() } } @@ -83,9 +95,7 @@ nextflow_process { } then { - assertAll( - { assert process.failed } - ) + assert process.failed } } @@ -111,10 +121,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/celltypes/celltypist/tests/main.nf.test.snap b/modules/local/celltypes/celltypist/tests/main.nf.test.snap index e1c674fd..0ecca1b5 100644 --- a/modules/local/celltypes/celltypist/tests/main.nf.test.snap +++ b/modules/local/celltypes/celltypist/tests/main.nf.test.snap @@ -2,51 +2,24 @@ "Should run with a symbol column other than index": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test_celltypist.h5ad:md5,ef49126cbbaec817d468f2b196a7cc63" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "test_celltypist.pkl:md5,b75851d6e4a34bd2e820234bf466cb8f" - ] - ], - "2": [ - "versions.yml:md5,d30822b1ba7cc7a7dc35c749b2353b57" - ], - "h5ad": [ - [ - { - "id": "test" - }, - "test_celltypist.h5ad:md5,ef49126cbbaec817d468f2b196a7cc63" - ] - ], - "obs": [ - [ - { - "id": "test" - }, - "test_celltypist.pkl:md5,b75851d6e4a34bd2e820234bf466cb8f" - ] - ], - "versions": [ - "versions.yml:md5,d30822b1ba7cc7a7dc35c749b2353b57" - ] - } + "CELLTYPES_CELLTYPIST": { + "python": "3.12.8", + "pandas": "2.2.3", + "scanpy": "1.10.4", + "celltypist": "1.6.3" + } + }, + [ + "celltypist:Adult_COVID19_PBMC", + "celltypist:Adult_COVID19_PBMC:conf", + "sample" + ] ], + "timestamp": "2026-03-25T15:44:41.940273199", "meta": { - "nf-test": "0.9.2", + "nf-test": "0.9.4", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-25T17:07:47.293607016" + } }, "Should run without failures - stub": { "content": [ @@ -91,59 +64,32 @@ ] } ], + "timestamp": "2026-03-25T15:45:36.6350805", "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.2" - }, - "timestamp": "2025-06-01T22:03:47.365626813" + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } }, "Should run without failures": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test_celltypist.h5ad:md5,ef49126cbbaec817d468f2b196a7cc63" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "test_celltypist.pkl:md5,b75851d6e4a34bd2e820234bf466cb8f" - ] - ], - "2": [ - "versions.yml:md5,d30822b1ba7cc7a7dc35c749b2353b57" - ], - "h5ad": [ - [ - { - "id": "test" - }, - "test_celltypist.h5ad:md5,ef49126cbbaec817d468f2b196a7cc63" - ] - ], - "obs": [ - [ - { - "id": "test" - }, - "test_celltypist.pkl:md5,b75851d6e4a34bd2e820234bf466cb8f" - ] - ], - "versions": [ - "versions.yml:md5,d30822b1ba7cc7a7dc35c749b2353b57" - ] - } + "CELLTYPES_CELLTYPIST": { + "python": "3.12.8", + "pandas": "2.2.3", + "scanpy": "1.10.4", + "celltypist": "1.6.3" + } + }, + [ + "celltypist:Adult_COVID19_PBMC", + "celltypist:Adult_COVID19_PBMC:conf", + "sample" + ] ], + "timestamp": "2026-03-25T15:44:12.70140271", "meta": { - "nf-test": "0.9.2", + "nf-test": "0.9.4", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-25T17:07:21.807969437" + } } } \ No newline at end of file diff --git a/modules/local/celltypes/singler/tests/main.nf.test b/modules/local/celltypes/singler/tests/main.nf.test index 4523a664..654452da 100644 --- a/modules/local/celltypes/singler/tests/main.nf.test +++ b/modules/local/celltypes/singler/tests/main.nf.test @@ -40,12 +40,20 @@ nextflow_process { } then { + def predictions = path(process.out.obs[0][1]).csv assert process.success + with(predictions) { + assert rowCount > 0 + assert columnNames.any { it.endsWith("labels_test") } + assert columnNames.any { it.endsWith("pruned.labels_test") } + } + assert process.out.distribution.size() == 1 + assert process.out.heatmap.size() == 1 assert snapshot( process.out.obs, file(process.out.distribution[0][1]).name, file(process.out.heatmap[0][1]).name, - process.out.versions + path(process.out.versions[0]).yaml ).match() } @@ -79,12 +87,20 @@ nextflow_process { } then { + def predictions = path(process.out.obs[0][1]).csv assert process.success + with(predictions) { + assert rowCount > 0 + assert columnNames.any { it.endsWith("labels_hpca") } + assert columnNames.any { it.endsWith("pruned.labels_hpca") } + } + assert process.out.distribution.size() == 1 + assert process.out.heatmap.size() == 1 assert snapshot( process.out.obs, file(process.out.distribution[0][1]).name, file(process.out.heatmap[0][1]).name, - process.out.versions + path(process.out.versions[0]).yaml ).match() } @@ -118,12 +134,20 @@ nextflow_process { } then { + def predictions = path(process.out.obs[0][1]).csv assert process.success + with(predictions) { + assert rowCount > 0 + assert columnNames.any { it.endsWith("labels_hpca") } + assert columnNames.any { it.endsWith("pruned.labels_hpca") } + } + assert process.out.distribution.size() == 1 + assert process.out.heatmap.size() == 1 assert snapshot( process.out.obs, file(process.out.distribution[0][1]).name, file(process.out.heatmap[0][1]).name, - process.out.versions + path(process.out.versions[0]).yaml ).match() } @@ -191,13 +215,22 @@ nextflow_process { } then { + def predictions = path(process.out.obs[0][1]).csv assert process.success + with(predictions) { + assert rowCount > 0 + // one set of label columns per reference + assert columnNames.any { it.endsWith("labels_hpca") } + assert columnNames.any { it.endsWith("pruned.labels_hpca") } + assert columnNames.any { it.endsWith("labels_monaco_immune") } + assert columnNames.any { it.endsWith("pruned.labels_monaco_immune") } + } + // one distribution and heatmap pdf per reference + assert process.out.distribution[0][1].size() == 2 + assert process.out.heatmap[0][1].size() == 2 assert snapshot( process.out.obs, - // Cannot capture names because there are multiple files - // file(process.out.distribution[0][1]).name, - // file(process.out.heatmap[0][1]).name, - process.out.versions + path(process.out.versions[0]).yaml ).match() } diff --git a/modules/local/celltypes/singler/tests/main.nf.test.snap b/modules/local/celltypes/singler/tests/main.nf.test.snap index d5fe7716..40e225a1 100644 --- a/modules/local/celltypes/singler/tests/main.nf.test.snap +++ b/modules/local/celltypes/singler/tests/main.nf.test.snap @@ -11,14 +11,20 @@ ], "test_singler_hpca_distribution.pdf", "test_singler_hpca_heatmap.pdf", - [ - "versions.yml:md5,70b80d9d31fab709351b4448a54a0528" - ] + { + "CELLTYPES_SINGLER": { + "R": "R version 4.5.3 (2026-03-11)", + "SingleR": "2.12.0", + "celldex": "1.20.0", + "anndataR": "1.0.2", + "ggplot2": "4.0.2" + } + } ], - "timestamp": "2026-03-16T12:37:54.417981638", + "timestamp": "2026-03-28T18:59:53.764238934", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run after celldex reference is fetched": { @@ -33,14 +39,20 @@ ], "test_singler_test_distribution.pdf", "test_singler_test_heatmap.pdf", - [ - "versions.yml:md5,70b80d9d31fab709351b4448a54a0528" - ] + { + "CELLTYPES_SINGLER": { + "R": "R version 4.5.3 (2026-03-11)", + "SingleR": "2.12.0", + "celldex": "1.20.0", + "anndataR": "1.0.2", + "ggplot2": "4.0.2" + } + } ], - "timestamp": "2026-03-16T11:40:03.222322422", + "timestamp": "2026-03-28T18:54:39.185673723", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run with a single reference": { @@ -55,14 +67,20 @@ ], "test_singler_hpca_distribution.pdf", "test_singler_hpca_heatmap.pdf", - [ - "versions.yml:md5,70b80d9d31fab709351b4448a54a0528" - ] + { + "CELLTYPES_SINGLER": { + "R": "R version 4.5.3 (2026-03-11)", + "SingleR": "2.12.0", + "celldex": "1.20.0", + "anndataR": "1.0.2", + "ggplot2": "4.0.2" + } + } ], - "timestamp": "2026-03-16T12:35:27.022696083", + "timestamp": "2026-03-28T18:57:17.216120097", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run with a single reference - stub": { @@ -140,14 +158,20 @@ "test_singler_predictions.csv:md5,11a52bcaca3f7e8ad88a9fe7d26b49c5" ] ], - [ - "versions.yml:md5,70b80d9d31fab709351b4448a54a0528" - ] + { + "CELLTYPES_SINGLER": { + "R": "R version 4.5.3 (2026-03-11)", + "SingleR": "2.12.0", + "celldex": "1.20.0", + "anndataR": "1.0.2", + "ggplot2": "4.0.2" + } + } ], - "timestamp": "2026-03-16T12:40:51.446458814", + "timestamp": "2026-03-28T19:03:07.666721816", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/custom/collectsizes/templates/collectsizes.py b/modules/local/custom/collectsizes/templates/collectsizes.py index f1a0c38b..be2d7c6e 100644 --- a/modules/local/custom/collectsizes/templates/collectsizes.py +++ b/modules/local/custom/collectsizes/templates/collectsizes.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility +import os +os.environ["KMP_AFFINITY"] = "disabled" + import json import platform diff --git a/modules/local/custom/collectsizes/tests/main.nf.test b/modules/local/custom/collectsizes/tests/main.nf.test index d1519bc2..bbc63ad2 100644 --- a/modules/local/custom/collectsizes/tests/main.nf.test +++ b/modules/local/custom/collectsizes/tests/main.nf.test @@ -23,10 +23,11 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() } } @@ -49,10 +50,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/custom/collectsizes/tests/main.nf.test.snap b/modules/local/custom/collectsizes/tests/main.nf.test.snap index 792e40a7..56e8df9f 100644 --- a/modules/local/custom/collectsizes/tests/main.nf.test.snap +++ b/modules/local/custom/collectsizes/tests/main.nf.test.snap @@ -69,12 +69,18 @@ "versions": [ "versions.yml:md5,9d20a6e34fd08f441c0efb937cf52806" ] + }, + { + "CUSTOM_COLLECTSIZES": { + "pandas": "2.3.3", + "python": "3.13.12" + } } ], - "timestamp": "2026-03-16T19:04:34.30658104", + "timestamp": "2026-03-29T14:52:06.15939485", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/doublet_detection/doublet_removal/templates/doublet_removal.py b/modules/local/doublet_detection/doublet_removal/templates/doublet_removal.py index 552ca08e..7bd8c4df 100644 --- a/modules/local/doublet_detection/doublet_removal/templates/doublet_removal.py +++ b/modules/local/doublet_detection/doublet_removal/templates/doublet_removal.py @@ -1,6 +1,9 @@ #!/opt/conda/bin/python +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import base64 import json diff --git a/modules/local/doublet_detection/doublet_removal/tests/main.nf.test b/modules/local/doublet_detection/doublet_removal/tests/main.nf.test index ea1715e8..69e1531e 100644 --- a/modules/local/doublet_detection/doublet_removal/tests/main.nf.test +++ b/modules/local/doublet_detection/doublet_removal/tests/main.nf.test @@ -32,8 +32,13 @@ nextflow_process { } then { + def adata = anndata(process.out.h5ad[0][1]) assert process.success - assert snapshot(process.out).match() + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } diff --git a/modules/local/doublet_detection/doublet_removal/tests/main.nf.test.snap b/modules/local/doublet_detection/doublet_removal/tests/main.nf.test.snap index 9c5f2a39..5a9cb2e9 100644 --- a/modules/local/doublet_detection/doublet_removal/tests/main.nf.test.snap +++ b/modules/local/doublet_detection/doublet_removal/tests/main.nf.test.snap @@ -69,12 +69,55 @@ "versions": [ "versions.yml:md5,893433c90a0287b3000a0ccf2e680fec" ] + }, + { + "DOUBLET_REMOVAL": { + "anndata": "0.12.10", + "matplotlib": "3.10.8", + "pandas": "2.3.3", + "python": "3.13.12", + "upsetplot": "0.9.0" + } + }, + { + "n_obs": 5901, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:15:35.811807967", + "timestamp": "2026-03-29T12:57:40.009249885", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/doublet_detection/scds/tests/main.nf.test b/modules/local/doublet_detection/scds/tests/main.nf.test index b1ddb738..513bf125 100644 --- a/modules/local/doublet_detection/scds/tests/main.nf.test +++ b/modules/local/doublet_detection/scds/tests/main.nf.test @@ -25,17 +25,16 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - process.out.predictions, - // Hashing does not work due to this issue: - // https://github.com/scverse/anndataR/issues/272 - file(process.out.h5ad.get(0).get(1)).exists(), - file(process.out.h5ad.get(0).get(1)).size() - ).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "hybrid_call" in obs.colnames + assert "hybrid_score" in obs.colnames + } + assert snapshot( + path(process.out.versions[0]).yaml, + adata.obs.colnames + ).match() } } @@ -60,10 +59,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/doublet_detection/scds/tests/main.nf.test.snap b/modules/local/doublet_detection/scds/tests/main.nf.test.snap index e2305bbb..6fceac91 100644 --- a/modules/local/doublet_detection/scds/tests/main.nf.test.snap +++ b/modules/local/doublet_detection/scds/tests/main.nf.test.snap @@ -42,32 +42,34 @@ ] } ], + "timestamp": "2026-03-25T15:44:42.961362081", "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.2" - }, - "timestamp": "2025-05-30T16:52:57.673676107" + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } }, "Should run without failures": { "content": [ + { + "SCDS": { + "R": "4.3.3", + "scds": "1.18.0" + } + }, [ - "versions.yml:md5,c8683fe6c044ab53b908d2fd7c38f8f7" - ], - [ - [ - { - "id": "test" - }, - "test_scds.csv:md5,6bedc66c5fc2517cea4808a72c29e17f" - ] - ], - true, - 7541879 + "bcds_call", + "bcds_score", + "cxds_call", + "cxds_score", + "hybrid_call", + "hybrid_score", + "sample" + ] ], + "timestamp": "2026-03-25T15:44:28.452040006", "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.2" - }, - "timestamp": "2025-05-30T16:52:47.324747683" + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } } } \ No newline at end of file diff --git a/modules/local/hugounifier/apply/tests/main.nf.test b/modules/local/hugounifier/apply/tests/main.nf.test index 1cb039bb..edc22b63 100644 --- a/modules/local/hugounifier/apply/tests/main.nf.test +++ b/modules/local/hugounifier/apply/tests/main.nf.test @@ -45,15 +45,16 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { - with(anndata(process.out.h5ad[0][1])) { - assert var.rownames.size() > 0 - assert obs.rownames.size() > 0 - } + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert var.rownames.size() > 0 + assert obs.rownames.size() > 0 } - ) + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -79,10 +80,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/hugounifier/apply/tests/main.nf.test.snap b/modules/local/hugounifier/apply/tests/main.nf.test.snap index b3a1e4bd..dd565734 100644 --- a/modules/local/hugounifier/apply/tests/main.nf.test.snap +++ b/modules/local/hugounifier/apply/tests/main.nf.test.snap @@ -31,5 +31,53 @@ "nf-test": "0.9.2", "nextflow": "25.04.6" } + }, + "Should run without failures": { + "content": [ + { + "HUGOUNIFIER_APPLY": { + "hugo-unifier": "0.3.1" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } + ], + "timestamp": "2026-03-29T14:29:56.746430632", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } } -} +} \ No newline at end of file diff --git a/modules/local/hugounifier/get/tests/main.nf.test b/modules/local/hugounifier/get/tests/main.nf.test index d111058f..f822a6b2 100644 --- a/modules/local/hugounifier/get/tests/main.nf.test +++ b/modules/local/hugounifier/get/tests/main.nf.test @@ -29,20 +29,17 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert process.out.changes[0][1].size() == 2 }, - { - with(path(process.out.changes[0][1][0]).csv) { - assert columnNames == ["action", "symbol", "new", "reason"] - } - }, - { - with(path(process.out.changes[0][1][1]).csv) { - assert columnNames == ["action", "symbol", "new", "reason"] - } + assert process.success + assert process.out.changes[0][1].size() == 2 + with(path(process.out.changes[0][1][0]).csv) { + assert columnNames == ["action", "symbol", "new", "reason"] } - ) + with(path(process.out.changes[0][1][1]).csv) { + assert columnNames == ["action", "symbol", "new", "reason"] + } + assert snapshot( + path(process.out.versions[0]).yaml + ).match() } } @@ -71,10 +68,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/hugounifier/get/tests/main.nf.test.snap b/modules/local/hugounifier/get/tests/main.nf.test.snap index f9b67f8e..fabeb6a5 100644 --- a/modules/local/hugounifier/get/tests/main.nf.test.snap +++ b/modules/local/hugounifier/get/tests/main.nf.test.snap @@ -37,5 +37,19 @@ "nf-test": "0.9.2", "nextflow": "25.04.6" } + }, + "Should run without failures": { + "content": [ + { + "HUGOUNIFIER_GET": { + "hugo-unifier": "0.3.1" + } + } + ], + "timestamp": "2026-03-29T14:29:45.757744", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } } -} +} \ No newline at end of file diff --git a/modules/local/liana/rankaggregate/tests/main.nf.test b/modules/local/liana/rankaggregate/tests/main.nf.test index 06ce8f2c..71f54e4b 100644 --- a/modules/local/liana/rankaggregate/tests/main.nf.test +++ b/modules/local/liana/rankaggregate/tests/main.nf.test @@ -27,10 +27,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert "liana_res" in adata.uns + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -55,10 +58,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/liana/rankaggregate/tests/main.nf.test.snap b/modules/local/liana/rankaggregate/tests/main.nf.test.snap index 21fb0e19..c8e7b781 100644 --- a/modules/local/liana/rankaggregate/tests/main.nf.test.snap +++ b/modules/local/liana/rankaggregate/tests/main.nf.test.snap @@ -32,46 +32,61 @@ ] } ], - "timestamp": "2026-01-10T22:29:55.568090889", + "timestamp": "2026-03-25T15:47:27.037482832", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } }, "Should run without failures": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test_liana.h5ad:md5,c227d198aa472576b58ffe61ff37027b" + "liana": "1.6.1", + "python": "3.12.12", + "scanpy": "1.11.5" + }, + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "leiden", + "sample" ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + ], - "1": [ - "test_liana.pkl:md5,058214ae3910f43472b791830a606047" + "obsm": [ + "X_pca" ], - "2": [ - "versions.yml:md5,44f181a9b2e8bebcda641e7400af14cd" + "varm": [ + "X_pca" ], - "h5ad": [ - [ - { - "id": "test" - }, - "test_liana.h5ad:md5,c227d198aa472576b58ffe61ff37027b" - ] + "obsp": [ + "connectivities", + "distances" ], - "uns": [ - "test_liana.pkl:md5,058214ae3910f43472b791830a606047" + "varp": [ + ], - "versions": [ - "versions.yml:md5,44f181a9b2e8bebcda641e7400af14cd" + "uns": [ + "X_pca", + "leiden", + "liana_res", + "log1p", + "neighbors" ] } ], - "timestamp": "2026-03-22T09:53:42.436168666", + "timestamp": "2026-03-30T09:51:34.987832204", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scanpy/bbknn/tests/main.nf.test b/modules/local/scanpy/bbknn/tests/main.nf.test index 6a942c7b..7fb1827a 100644 --- a/modules/local/scanpy/bbknn/tests/main.nf.test +++ b/modules/local/scanpy/bbknn/tests/main.nf.test @@ -28,10 +28,17 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "X_pca" in obsm + assert "connectivities" in obsp + assert "distances" in obsp + } + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -57,10 +64,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/bbknn/tests/main.nf.test.snap b/modules/local/scanpy/bbknn/tests/main.nf.test.snap index ef3abb17..f6f4bfac 100644 --- a/modules/local/scanpy/bbknn/tests/main.nf.test.snap +++ b/modules/local/scanpy/bbknn/tests/main.nf.test.snap @@ -26,43 +26,63 @@ ] } ], - "timestamp": "2025-06-03T07:44:27.274185863", + "timestamp": "2026-03-25T15:44:42.434469309", "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.2" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } }, "Should run without failures": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test.h5ad:md5,d83039db76dd28a01f459cfe7a1e1b6c" + "SCANPY_BBKNN": { + "bbknn": "1.6.0", + "pandas": "2.3.3", + "python": "3.12.12", + "scanpy": "1.11.5" + } + }, + { + "n_obs": 38234, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + ], - "1": [ - "versions.yml:md5,0e8d49948d318a0226fecc9b8d3372bb" + "obsm": [ + "X_pca" ], - "h5ad": [ - [ - { - "id": "test" - }, - "test.h5ad:md5,d83039db76dd28a01f459cfe7a1e1b6c" - ] + "varm": [ + "PCs" ], - "versions": [ - "versions.yml:md5,0e8d49948d318a0226fecc9b8d3372bb" + "obsp": [ + "connectivities", + "distances" + ], + "varp": [ + + ], + "uns": [ + "neighbors", + "pca" ] } ], - "timestamp": "2026-03-18T00:12:12.879701725", + "timestamp": "2026-03-29T11:17:44.928430046", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/scanpy/cellcycle/templates/cellcycle.py b/modules/local/scanpy/cellcycle/templates/cellcycle.py index 6ab74a34..7e696817 100644 --- a/modules/local/scanpy/cellcycle/templates/cellcycle.py +++ b/modules/local/scanpy/cellcycle/templates/cellcycle.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform os.environ["MPLCONFIGDIR"] = "./tmp/mpl" diff --git a/modules/local/scanpy/cellcycle/tests/main.nf.test b/modules/local/scanpy/cellcycle/tests/main.nf.test index b86ad0c8..cb964fd6 100644 --- a/modules/local/scanpy/cellcycle/tests/main.nf.test +++ b/modules/local/scanpy/cellcycle/tests/main.nf.test @@ -28,10 +28,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -59,10 +62,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/cellcycle/tests/main.nf.test.snap b/modules/local/scanpy/cellcycle/tests/main.nf.test.snap index 0b0c4bd9..3020e38f 100644 --- a/modules/local/scanpy/cellcycle/tests/main.nf.test.snap +++ b/modules/local/scanpy/cellcycle/tests/main.nf.test.snap @@ -40,12 +40,55 @@ "versions": [ "versions.yml:md5,835e61377485d04a9622f14de885ffe8" ] + }, + { + "SCANPY_CELLCYCLE": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "G2M_score", + "S_score", + "phase", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:15:03.013574886", + "timestamp": "2026-03-29T12:57:44.699366263", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - stub": { diff --git a/modules/local/scanpy/combat/templates/combat.py b/modules/local/scanpy/combat/templates/combat.py index 79e56331..cb7f8ded 100644 --- a/modules/local/scanpy/combat/templates/combat.py +++ b/modules/local/scanpy/combat/templates/combat.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform os.environ["MPLCONFIGDIR"] = "./tmp/mpl" @@ -38,7 +41,6 @@ adata.obsm["X_pca"] = np.round(adata.obsm["X_pca"].astype(np.float64), args.decimals) adata.varm["PCs"] = np.round(adata.varm["PCs"].astype(np.float64), args.decimals) adata.uns["pca"]["variance"] = np.round(adata.uns["pca"]["variance"].astype(np.float64), args.decimals) - adata.uns["pca"]["variance_ratio"] = np.round(adata.uns["pca"]["variance_ratio"].astype(np.float64), args.decimals) adata.obsm["X_emb"] = adata.obsm["X_pca"] diff --git a/modules/local/scanpy/combat/tests/main.nf.test b/modules/local/scanpy/combat/tests/main.nf.test index be81d268..cf68a3a5 100644 --- a/modules/local/scanpy/combat/tests/main.nf.test +++ b/modules/local/scanpy/combat/tests/main.nf.test @@ -41,10 +41,16 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "X_emb" in obsm + assert "X_pca" in obsm + } + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -66,10 +72,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/combat/tests/main.nf.test.snap b/modules/local/scanpy/combat/tests/main.nf.test.snap index c75c04ea..d06f446c 100644 --- a/modules/local/scanpy/combat/tests/main.nf.test.snap +++ b/modules/local/scanpy/combat/tests/main.nf.test.snap @@ -38,52 +38,64 @@ ] } ], - "timestamp": "2025-06-03T07:48:07.847500785", + "timestamp": "2026-03-25T15:44:57.270966951", "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.2" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } }, "Should run without failures": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test.h5ad:md5,c03a96f7779dc1c979d1dd920d4217b6" + "SCANPY_COMBAT": { + "numpy": "2.3.5", + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 38234, + "n_vars": 100, + "obs": { + "index": "_index", + "columns": [ + "sample" ] - ], - "1": [ - "X_test.pkl:md5,8997a5b3f6b3e7cbfc21f8c1e4dff221" - ], - "2": [ - "test.npy:md5,5f2ff24403d91d7ed811542e97092393" - ], - "3": [ - "versions.yml:md5,9e3850fe91d236b81ba7557c47344e64" - ], - "h5ad": [ - [ - { - "id": "test" - }, - "test.h5ad:md5,c03a96f7779dc1c979d1dd920d4217b6" + }, + "var": { + "index": "_index", + "columns": [ + "dispersions", + "dispersions_norm", + "highly_variable", + "means" ] - ], + }, "layers": [ - "test.npy:md5,5f2ff24403d91d7ed811542e97092393" + ], "obsm": [ - "X_test.pkl:md5,8997a5b3f6b3e7cbfc21f8c1e4dff221" + "X_emb", + "X_pca" ], - "versions": [ - "versions.yml:md5,9e3850fe91d236b81ba7557c47344e64" + "varm": [ + "PCs" + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + "hvg", + "log1p", + "pca" ] } ], - "timestamp": "2026-03-22T14:16:42.06841452", + "timestamp": "2026-03-29T11:17:34.118271552", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scanpy/filter/templates/filter.py b/modules/local/scanpy/filter/templates/filter.py index 12f81f6a..83ef45cf 100644 --- a/modules/local/scanpy/filter/templates/filter.py +++ b/modules/local/scanpy/filter/templates/filter.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform os.environ["MPLCONFIGDIR"] = "./tmp/mpl" diff --git a/modules/local/scanpy/filter/tests/main.nf.test b/modules/local/scanpy/filter/tests/main.nf.test index dc21ef14..69025afb 100644 --- a/modules/local/scanpy/filter/tests/main.nf.test +++ b/modules/local/scanpy/filter/tests/main.nf.test @@ -32,10 +32,17 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "mt" in var.colnames + assert "pct_counts_mt" in obs.colnames + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -66,10 +73,17 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "mt" in var.colnames + assert "pct_counts_mt" in obs.colnames + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -99,10 +113,9 @@ nextflow_process { } then { - assertAll( - { assert process.failed }, - { assert snapshot(process.out).match() } - ) + assert process.failed + + assert snapshot(process.out).match() } } @@ -133,10 +146,17 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "mt" in var.colnames + assert "pct_counts_mt" in obs.colnames + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -168,10 +188,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/filter/tests/main.nf.test.snap b/modules/local/scanpy/filter/tests/main.nf.test.snap index ae4e19e9..5ba7fb15 100644 --- a/modules/local/scanpy/filter/tests/main.nf.test.snap +++ b/modules/local/scanpy/filter/tests/main.nf.test.snap @@ -47,12 +47,65 @@ "versions": [ "versions.yml:md5,b522587d103606ffd4959a6297fb9476" ] + }, + { + "SCANPY_FILTER": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 5719, + "n_vars": 992, + "obs": { + "index": "_index", + "columns": [ + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + "mean_counts", + "mt", + "n_cells", + "n_cells_by_counts", + "n_counts", + "pct_dropout_by_counts", + "symbols", + "total_counts" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:33:26.743121974", + "timestamp": "2026-03-29T11:18:14.694442933", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - stub": { @@ -113,12 +166,65 @@ "versions": [ "versions.yml:md5,b522587d103606ffd4959a6297fb9476" ] + }, + { + "SCANPY_FILTER": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 5719, + "n_vars": 992, + "obs": { + "index": "_index", + "columns": [ + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + "mean_counts", + "mt", + "n_cells", + "n_cells_by_counts", + "n_counts", + "pct_dropout_by_counts", + "symbols", + "total_counts" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:33:11.353190554", + "timestamp": "2026-03-29T11:17:17.630245843", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - with custom mito genes": { @@ -146,12 +252,65 @@ "versions": [ "versions.yml:md5,b522587d103606ffd4959a6297fb9476" ] + }, + { + "SCANPY_FILTER": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 5719, + "n_vars": 992, + "obs": { + "index": "_index", + "columns": [ + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + "mean_counts", + "mt", + "n_cells", + "n_cells_by_counts", + "n_counts", + "pct_dropout_by_counts", + "symbols", + "total_counts" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:34:02.974430103", + "timestamp": "2026-03-29T11:20:39.503874531", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/scanpy/harmony/main.nf b/modules/local/scanpy/harmony/main.nf index cc47b500..d438c359 100644 --- a/modules/local/scanpy/harmony/main.nf +++ b/modules/local/scanpy/harmony/main.nf @@ -15,7 +15,6 @@ process SCANPY_HARMONY { output: tuple val(meta), path("${prefix}.h5ad"), emit: h5ad path "X_${prefix}.pkl", emit: obsm - path "variance_ratio_${prefix}.yml", emit: variance_ratio path "versions.yml", emit: versions script: @@ -31,7 +30,6 @@ process SCANPY_HARMONY { """ touch ${prefix}.h5ad touch X_${prefix}.pkl - touch variance_ratio_${prefix}.yml touch versions.yml """ } diff --git a/modules/local/scanpy/harmony/templates/harmony.py b/modules/local/scanpy/harmony/templates/harmony.py index 5b44032e..adaa81dd 100644 --- a/modules/local/scanpy/harmony/templates/harmony.py +++ b/modules/local/scanpy/harmony/templates/harmony.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import yaml import argparse @@ -57,14 +60,6 @@ adata_processing.obsm["X_emb"] = adata_processing.obsm["X_emb"].round(params.decimals) adata.obsm["X_emb"] = adata_processing.obsm["X_emb"] -var_per_dim = np.var(adata.obsm["X_emb"].astype(np.float64), axis=0) -variance_ratio = (var_per_dim / var_per_dim.sum()).tolist() -if params.decimals is not None: - variance_ratio = np.round(variance_ratio, params.decimals).tolist() - -with open(f"variance_ratio_{prefix}.yml", "w") as f: - yaml.dump({"variance_ratio": variance_ratio}, f) - adata.write_h5ad(f"{prefix}.h5ad") df = pd.DataFrame(adata.obsm["X_emb"], index=adata.obs_names) diff --git a/modules/local/scanpy/harmony/tests/main.nf.test b/modules/local/scanpy/harmony/tests/main.nf.test index ae6568f7..ffc73a3b 100644 --- a/modules/local/scanpy/harmony/tests/main.nf.test +++ b/modules/local/scanpy/harmony/tests/main.nf.test @@ -29,16 +29,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { - assert snapshot( - path(process.out.variance_ratio[0]).yaml, - path(process.out.versions[0]).yaml - ).match() - }, - { assert "X_emb" in anndata(process.out.h5ad[0][1]).obsm } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert "X_emb" in adata.obsm + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -65,10 +62,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/harmony/tests/main.nf.test.snap b/modules/local/scanpy/harmony/tests/main.nf.test.snap index d4282c8a..5a847531 100644 --- a/modules/local/scanpy/harmony/tests/main.nf.test.snap +++ b/modules/local/scanpy/harmony/tests/main.nf.test.snap @@ -14,9 +14,6 @@ "X_test.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "2": [ - "variance_ratio_test.yml:md5,d41d8cd98f00b204e9800998ecf8427e" - ], - "3": [ "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ], "h5ad": [ @@ -30,9 +27,6 @@ "obsm": [ "X_test.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], - "variance_ratio": [ - "variance_ratio_test.yml:md5,d41d8cd98f00b204e9800998ecf8427e" - ], "versions": [ "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ] @@ -46,60 +40,6 @@ }, "Should run without failures": { "content": [ - { - "variance_ratio": [ - 0.2, - 0.05, - 0.05, - 0.04, - 0.04, - 0.03, - 0.03, - 0.02, - 0.02, - 0.02, - 0.02, - 0.02, - 0.02, - 0.02, - 0.02, - 0.02, - 0.02, - 0.02, - 0.02, - 0.02, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01, - 0.01 - ] - }, { "SCANPY_HARMONY": { "harmonypy": "0.2.0", @@ -107,9 +47,43 @@ "python": "3.13.12", "scanpy": "1.12" } + }, + { + "n_obs": 38234, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_emb" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-22T13:18:13.205002754", + "timestamp": "2026-03-29T11:17:47.094134151", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scanpy/hvgs/templates/hvgs.py b/modules/local/scanpy/hvgs/templates/hvgs.py index d5940605..70e43873 100644 --- a/modules/local/scanpy/hvgs/templates/hvgs.py +++ b/modules/local/scanpy/hvgs/templates/hvgs.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform from threadpoolctl import threadpool_limits diff --git a/modules/local/scanpy/hvgs/tests/main.nf.test b/modules/local/scanpy/hvgs/tests/main.nf.test index 834e0cc6..661c0efe 100644 --- a/modules/local/scanpy/hvgs/tests/main.nf.test +++ b/modules/local/scanpy/hvgs/tests/main.nf.test @@ -27,10 +27,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert "highly_variable" in adata.var.colnames + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -55,10 +58,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert "highly_variable" in adata.var.colnames + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -84,10 +90,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert "highly_variable" in adata.var.colnames + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -114,10 +123,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/hvgs/tests/main.nf.test.snap b/modules/local/scanpy/hvgs/tests/main.nf.test.snap index 75249c58..e9865ea7 100644 --- a/modules/local/scanpy/hvgs/tests/main.nf.test.snap +++ b/modules/local/scanpy/hvgs/tests/main.nf.test.snap @@ -2,79 +2,107 @@ "Should run with a specified number of HVGs": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test_hvg.h5ad:md5,f1cfc42d33cf47fb46652e2f12d06da1" + "SCANPY_HVGS": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 38234, + "n_vars": 100, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "dispersions", + "dispersions_norm", + "highly_variable", + "means" ] + }, + "layers": [ + ], - "1": [ - "test_hvg.pkl:md5,6e7304cb50e936bf78b69ad70b29495e" + "obsm": [ + ], - "2": [ - "versions.yml:md5,082c751136be043b260385c9829a571d" + "varm": [ + ], - "h5ad": [ - [ - { - "id": "test" - }, - "test_hvg.h5ad:md5,f1cfc42d33cf47fb46652e2f12d06da1" - ] + "obsp": [ + ], - "var": [ - "test_hvg.pkl:md5,6e7304cb50e936bf78b69ad70b29495e" + "varp": [ + ], - "versions": [ - "versions.yml:md5,082c751136be043b260385c9829a571d" + "uns": [ + "hvg", + "log1p" ] } ], - "timestamp": "2026-03-16T15:33:26.657516082", + "timestamp": "2026-03-29T11:18:05.314404083", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without a specified number of HVGs": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test_hvg.h5ad:md5,a8c70cd2c88e801de037f181e6830997" + "SCANPY_HVGS": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 38234, + "n_vars": 251, + "obs": { + "index": "_index", + "columns": [ + "sample" ] + }, + "var": { + "index": "_index", + "columns": [ + "dispersions", + "dispersions_norm", + "highly_variable", + "means" + ] + }, + "layers": [ + ], - "1": [ - "test_hvg.pkl:md5,82f4f37286430dbfbe76a531a53b867d" + "obsm": [ + ], - "2": [ - "versions.yml:md5,082c751136be043b260385c9829a571d" + "varm": [ + ], - "h5ad": [ - [ - { - "id": "test" - }, - "test_hvg.h5ad:md5,a8c70cd2c88e801de037f181e6830997" - ] + "obsp": [ + ], - "var": [ - "test_hvg.pkl:md5,82f4f37286430dbfbe76a531a53b867d" + "varp": [ + ], - "versions": [ - "versions.yml:md5,082c751136be043b260385c9829a571d" + "uns": [ + "hvg", + "log1p" ] } ], - "timestamp": "2026-03-16T15:33:11.035461884", + "timestamp": "2026-03-29T11:17:05.806436168", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - stub": { @@ -110,49 +138,63 @@ ] } ], - "timestamp": "2025-06-03T07:49:56.630416945", + "timestamp": "2026-03-25T15:46:02.052667216", "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.2" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } }, "Should run with a list of genes excluded from integration": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test_hvg.h5ad:md5,4d3f42a1201d720b01d15133df67727d" + "SCANPY_HVGS": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 38234, + "n_vars": 100, + "obs": { + "index": "_index", + "columns": [ + "sample" ] + }, + "var": { + "index": "_index", + "columns": [ + "dispersions", + "dispersions_norm", + "highly_variable", + "means" + ] + }, + "layers": [ + ], - "1": [ - "test_hvg.pkl:md5,e7432bf749f3ff633369d0b3199a24c4" + "obsm": [ + ], - "2": [ - "versions.yml:md5,082c751136be043b260385c9829a571d" + "varm": [ + ], - "h5ad": [ - [ - { - "id": "test" - }, - "test_hvg.h5ad:md5,4d3f42a1201d720b01d15133df67727d" - ] + "obsp": [ + ], - "var": [ - "test_hvg.pkl:md5,e7432bf749f3ff633369d0b3199a24c4" + "varp": [ + ], - "versions": [ - "versions.yml:md5,082c751136be043b260385c9829a571d" + "uns": [ + "hvg", + "log1p" ] } ], - "timestamp": "2026-03-16T15:33:45.021373498", + "timestamp": "2026-03-29T11:19:17.695541068", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/scanpy/leiden/templates/leiden.py b/modules/local/scanpy/leiden/templates/leiden.py index d285d7e3..5ec1154e 100644 --- a/modules/local/scanpy/leiden/templates/leiden.py +++ b/modules/local/scanpy/leiden/templates/leiden.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import json import base64 diff --git a/modules/local/scanpy/leiden/tests/main.nf.test b/modules/local/scanpy/leiden/tests/main.nf.test index 48072498..b3e93666 100644 --- a/modules/local/scanpy/leiden/tests/main.nf.test +++ b/modules/local/scanpy/leiden/tests/main.nf.test @@ -30,16 +30,17 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out.versions).match() }, - { - def obs = anndata(process.out.h5ad[0][1]).obs + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { assert "leiden" in obs.colnames def n_clusters = obs.get("leiden").n_unique() - assert n_clusters >= 5 && n_clusters <= 30 : "Expected 5–30 Leiden clusters, got ${n_clusters}" + assert n_clusters >= 5 && n_clusters <= 30 : "Expected 5-30 Leiden clusters, got ${n_clusters}" } - ) + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -67,10 +68,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/leiden/tests/main.nf.test.snap b/modules/local/scanpy/leiden/tests/main.nf.test.snap index 65b74eef..cdb54f1d 100644 --- a/modules/local/scanpy/leiden/tests/main.nf.test.snap +++ b/modules/local/scanpy/leiden/tests/main.nf.test.snap @@ -52,11 +52,52 @@ }, "Should run without failures": { "content": [ - [ - "versions.yml:md5,094091f84634347067c71751fa7c6b27" - ] + { + "SCANPY_LEIDEN": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "leiden", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_pca" + ], + "varm": [ + "X_pca" + ], + "obsp": [ + "connectivities", + "distances" + ], + "varp": [ + + ], + "uns": [ + "X_pca", + "leiden", + "neighbors" + ] + } ], - "timestamp": "2026-03-22T15:00:00.781565748", + "timestamp": "2026-03-29T11:17:20.376586064", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scanpy/neighbors/templates/neighbors.py b/modules/local/scanpy/neighbors/templates/neighbors.py index e1b9988e..cbf35660 100644 --- a/modules/local/scanpy/neighbors/templates/neighbors.py +++ b/modules/local/scanpy/neighbors/templates/neighbors.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import argparse import shlex diff --git a/modules/local/scanpy/neighbors/tests/main.nf.test b/modules/local/scanpy/neighbors/tests/main.nf.test index dfc16839..2aaaaccf 100644 --- a/modules/local/scanpy/neighbors/tests/main.nf.test +++ b/modules/local/scanpy/neighbors/tests/main.nf.test @@ -28,18 +28,23 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out.versions).match() }, - { - def ad = anndata(process.out.h5ad[0][1]) - assert "connectivities" in ad.obsp - assert "distances" in ad.obsp - assert "neighbors" in ad.uns + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "connectivities" in obsp + assert "distances" in obsp + assert "neighbors" in uns } - ) + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } + } + + test("Should run without failures - stub") { + options '-stub' when { @@ -59,10 +64,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/neighbors/tests/main.nf.test.snap b/modules/local/scanpy/neighbors/tests/main.nf.test.snap index 6ac4b68a..f87886a3 100644 --- a/modules/local/scanpy/neighbors/tests/main.nf.test.snap +++ b/modules/local/scanpy/neighbors/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "Should run without failures": { + "Should run without failures - stub": { "content": [ { "0": [ @@ -26,7 +26,60 @@ ] } ], - "timestamp": "2026-03-22T16:18:04.455217395", + "timestamp": "2026-03-28T16:08:57.025739289", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } + }, + "Should run without failures": { + "content": [ + { + "SCANPY_NEIGHBORS": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "leiden", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_pca" + ], + "varm": [ + "X_pca" + ], + "obsp": [ + "connectivities", + "distances" + ], + "varp": [ + + ], + "uns": [ + "X_pca", + "leiden", + "neighbors" + ] + } + ], + "timestamp": "2026-03-29T11:17:42.474824863", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scanpy/paga/templates/paga.py b/modules/local/scanpy/paga/templates/paga.py index e9475b95..d7ea8cde 100644 --- a/modules/local/scanpy/paga/templates/paga.py +++ b/modules/local/scanpy/paga/templates/paga.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import json import base64 diff --git a/modules/local/scanpy/paga/tests/main.nf.test b/modules/local/scanpy/paga/tests/main.nf.test index 13d8fa09..3c9f91da 100644 --- a/modules/local/scanpy/paga/tests/main.nf.test +++ b/modules/local/scanpy/paga/tests/main.nf.test @@ -27,10 +27,16 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "paga" in uns + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -55,10 +61,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/paga/tests/main.nf.test.snap b/modules/local/scanpy/paga/tests/main.nf.test.snap index 4b920861..4c40f84d 100644 --- a/modules/local/scanpy/paga/tests/main.nf.test.snap +++ b/modules/local/scanpy/paga/tests/main.nf.test.snap @@ -105,9 +105,55 @@ "versions": [ "versions.yml:md5,a87c0e3b4494aaca112a02c554da3084" ] + }, + { + "SCANPY_PAGA": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "leiden", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_pca" + ], + "varm": [ + "X_pca" + ], + "obsp": [ + "connectivities", + "distances" + ], + "varp": [ + + ], + "uns": [ + "X_pca", + "leiden", + "leiden_sizes", + "neighbors", + "paga" + ] } ], - "timestamp": "2026-03-22T09:51:51.950233221", + "timestamp": "2026-03-29T11:17:22.514762435", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scanpy/pca/main.nf b/modules/local/scanpy/pca/main.nf index a56f1f9f..9a65610f 100644 --- a/modules/local/scanpy/pca/main.nf +++ b/modules/local/scanpy/pca/main.nf @@ -14,7 +14,6 @@ process SCANPY_PCA { output: tuple val(meta), path("${prefix}.h5ad"), emit: h5ad path "X_${prefix}.pkl", emit: obsm - path "variance_ratio_${prefix}.yml", emit: variance_ratio path "versions.yml", emit: versions when: @@ -31,17 +30,8 @@ process SCANPY_PCA { stub: prefix = task.ext.prefix ?: "${meta.id}_pca" """ - export MPLCONFIGDIR=./tmp/mpl - export NUMBA_CACHE_DIR=./tmp/numba - touch ${prefix}.h5ad touch X_${prefix}.pkl - touch variance_ratio_${prefix}.yml - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - python: \$(python3 -c 'import platform; print(platform.python_version())') - scanpy: \$(python3 -c 'import scanpy; print(scanpy.__version__)') - END_VERSIONS + touch versions.yml """ } diff --git a/modules/local/scanpy/pca/templates/pca.py b/modules/local/scanpy/pca/templates/pca.py index 17eb44f8..3cfe4fea 100644 --- a/modules/local/scanpy/pca/templates/pca.py +++ b/modules/local/scanpy/pca/templates/pca.py @@ -1,15 +1,15 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import argparse import shlex os.environ["NUMBA_CACHE_DIR"] = "./tmp/numba" os.environ["MPLCONFIGDIR"] = "./tmp/matplotlib" -os.environ["OMP_NUM_THREADS"] = "1" -os.environ["OPENBLAS_NUM_THREADS"] = "1" -os.environ["MKL_NUM_THREADS"] = "1" import scanpy as sc import numpy as np @@ -33,18 +33,11 @@ if params.decimals is not None: adata.obsm[key_added] = np.round(adata.obsm[key_added].astype(np.float64), params.decimals) - adata.uns[key_added]["variance_ratio"] = np.round( - adata.uns[key_added]["variance_ratio"].astype(np.float64), params.decimals - ) adata.write_h5ad(f"{prefix}.h5ad") df = pd.DataFrame(adata.obsm[key_added], index=adata.obs_names) df.to_pickle(f"X_{prefix}.pkl") -variance_ratio = adata.uns[key_added]["variance_ratio"].tolist() -with open(f"variance_ratio_{prefix}.yml", "w") as f: - yaml.dump({"variance_ratio": variance_ratio}, f) - # Versions versions = { "${task.process}": { diff --git a/modules/local/scanpy/pca/tests/main.nf.test b/modules/local/scanpy/pca/tests/main.nf.test index ef89c406..5f1eec26 100644 --- a/modules/local/scanpy/pca/tests/main.nf.test +++ b/modules/local/scanpy/pca/tests/main.nf.test @@ -28,16 +28,16 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { - assert snapshot( - path(process.out.variance_ratio[0]).yaml, - path(process.out.versions[0]).yaml - ).match() - }, - { assert "X_pca" in anndata(process.out.h5ad[0][1]).obsm } - ) + def adata = anndata(process.out.h5ad[0][1]) + + assert process.success + assert "X_pca" in adata.obsm + assert "X_pca" in adata.uns + + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -63,10 +63,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/pca/tests/main.nf.test.snap b/modules/local/scanpy/pca/tests/main.nf.test.snap index 411fc037..24fa90ab 100644 --- a/modules/local/scanpy/pca/tests/main.nf.test.snap +++ b/modules/local/scanpy/pca/tests/main.nf.test.snap @@ -14,10 +14,7 @@ "X_test_pca.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "2": [ - "variance_ratio_test_pca.yml:md5,d41d8cd98f00b204e9800998ecf8427e" - ], - "3": [ - "versions.yml:md5,dc1add0c140202bbbef205a9cc48e097" + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ], "h5ad": [ [ @@ -30,85 +27,62 @@ "obsm": [ "X_test_pca.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], - "variance_ratio": [ - "variance_ratio_test_pca.yml:md5,d41d8cd98f00b204e9800998ecf8427e" - ], "versions": [ - "versions.yml:md5,dc1add0c140202bbbef205a9cc48e097" + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ] } ], - "timestamp": "2026-03-18T23:28:51.301024619", + "timestamp": "2026-04-01T15:10:58.212224761", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.2" + "nf-test": "0.9.5", + "nextflow": "25.10.4" } }, "Should run without failures": { "content": [ - { - "variance_ratio": [ - 0.724, - 0.028, - 0.02, - 0.014, - 0.008, - 0.006, - 0.004, - 0.004, - 0.003, - 0.003, - 0.003, - 0.002, - 0.002, - 0.002, - 0.002, - 0.002, - 0.002, - 0.002, - 0.002, - 0.002, - 0.002, - 0.002, - 0.002, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001, - 0.001 - ] - }, { "SCANPY_PCA": { "pandas": "2.3.3", "python": "3.13.12", "scanpy": "1.12" } + }, + { + "n_obs": 38234, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_pca" + ], + "varm": [ + "X_pca" + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + "X_pca" + ] } ], - "timestamp": "2026-03-18T23:35:10.339944767", + "timestamp": "2026-03-29T11:17:21.253081099", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scanpy/plotqc/templates/plotqc.py b/modules/local/scanpy/plotqc/templates/plotqc.py index 397b43ec..454d48d6 100644 --- a/modules/local/scanpy/plotqc/templates/plotqc.py +++ b/modules/local/scanpy/plotqc/templates/plotqc.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" os.environ["NUMBA_CACHE_DIR"] = "./tmp/numba" os.environ["MPLCONFIGDIR"] = "./tmp/matplotlib" diff --git a/modules/local/scanpy/plotqc/tests/main.nf.test b/modules/local/scanpy/plotqc/tests/main.nf.test index 8af12fc9..adf61bcd 100644 --- a/modules/local/scanpy/plotqc/tests/main.nf.test +++ b/modules/local/scanpy/plotqc/tests/main.nf.test @@ -25,10 +25,11 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() } } @@ -53,10 +54,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/plotqc/tests/main.nf.test.snap b/modules/local/scanpy/plotqc/tests/main.nf.test.snap index 1de12f12..f92c7b0f 100644 --- a/modules/local/scanpy/plotqc/tests/main.nf.test.snap +++ b/modules/local/scanpy/plotqc/tests/main.nf.test.snap @@ -69,12 +69,19 @@ "versions": [ "versions.yml:md5,0bf6e1aafa1eb89d15132965ac3c5d15" ] + }, + { + "SCANPY_PLOTQC": { + "matplotlib": "3.10.8", + "python": "3.13.12", + "scanpy": "1.12" + } } ], - "timestamp": "2026-03-16T15:14:17.873430808", + "timestamp": "2026-03-29T14:52:14.317465255", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/scanpy/rankgenesgroups/templates/rank_genes_groups.py b/modules/local/scanpy/rankgenesgroups/templates/rank_genes_groups.py index 8b98ccfc..0223adc3 100644 --- a/modules/local/scanpy/rankgenesgroups/templates/rank_genes_groups.py +++ b/modules/local/scanpy/rankgenesgroups/templates/rank_genes_groups.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import json import platform import base64 @@ -136,7 +139,7 @@ elif len(valid_groups) == 1: print(f"Skipping rank_genes_groups computation: only one group has >= 2 samples (group: {valid_groups[0]}).") else: - print(f"Skipping rank_genes_groups computation: less than 2 valid groups remaining after filtering.") + print("Skipping rank_genes_groups computation: less than 2 valid groups remaining after filtering.") # Versions diff --git a/modules/local/scanpy/rankgenesgroups/tests/main.nf.test b/modules/local/scanpy/rankgenesgroups/tests/main.nf.test index f765ef4b..c79570c5 100644 --- a/modules/local/scanpy/rankgenesgroups/tests/main.nf.test +++ b/modules/local/scanpy/rankgenesgroups/tests/main.nf.test @@ -30,10 +30,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert "rank_genes_groups" in adata.uns + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -61,10 +64,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } @@ -92,10 +93,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert "rank_genes_groups" in adata.uns + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -123,10 +127,11 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert process.out.h5ad.size() == 0 + assert snapshot( + path(process.out.versions[0]).yaml + ).match() } } diff --git a/modules/local/scanpy/rankgenesgroups/tests/main.nf.test.snap b/modules/local/scanpy/rankgenesgroups/tests/main.nf.test.snap index 682adf91..17676beb 100644 --- a/modules/local/scanpy/rankgenesgroups/tests/main.nf.test.snap +++ b/modules/local/scanpy/rankgenesgroups/tests/main.nf.test.snap @@ -44,48 +44,23 @@ ] } ], - "timestamp": "2026-01-18T21:23:45.231170376", + "timestamp": "2026-03-25T15:46:33.576251638", "meta": { - "nf-test": "0.9.2", + "nf-test": "0.9.4", "nextflow": "25.10.2" } }, "Should run with label subsetting": { "content": [ { - "0": [ - - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,a279f17d763d69028f9d84346e55dec8" - ], - "h5ad": [ - - ], - "multiqc_files": [ - - ], - "plots": [ - - ], - "uns": [ - - ], - "versions": [ - "versions.yml:md5,a279f17d763d69028f9d84346e55dec8" - ] + "SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } } ], - "timestamp": "2026-03-21T08:54:06.875259502", + "timestamp": "2026-03-28T17:42:45.977438907", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -94,49 +69,54 @@ "Should run without failures": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test_characteristic_genes.h5ad:md5,9841d511b9ad3719520f69e6eebdb9ca" + "SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "leiden", + "sample" ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + ], - "1": [ - "test_characteristic_genes.pkl:md5,a5375824a244e135c97349a6880d8e28" - ], - "2": [ - "test_characteristic_genes.png:md5,144d711a80fd70ace88db67cccd2f0bc" - ], - "3": [ - "test_characteristic_genes_mqc.json:md5,73c74aafa606395d0a010b51bfe20895" - ], - "4": [ - "versions.yml:md5,a279f17d763d69028f9d84346e55dec8" + "obsm": [ + "X_pca" ], - "h5ad": [ - [ - { - "id": "test" - }, - "test_characteristic_genes.h5ad:md5,9841d511b9ad3719520f69e6eebdb9ca" - ] + "varm": [ + "X_pca" ], - "multiqc_files": [ - "test_characteristic_genes_mqc.json:md5,73c74aafa606395d0a010b51bfe20895" + "obsp": [ + "connectivities", + "distances" ], - "plots": [ - "test_characteristic_genes.png:md5,144d711a80fd70ace88db67cccd2f0bc" + "varp": [ + ], "uns": [ - "test_characteristic_genes.pkl:md5,a5375824a244e135c97349a6880d8e28" - ], - "versions": [ - "versions.yml:md5,a279f17d763d69028f9d84346e55dec8" + "X_pca", + "leiden", + "log1p", + "neighbors", + "rank_genes_groups" ] } ], - "timestamp": "2026-03-22T09:53:53.651592336", + "timestamp": "2026-03-30T09:51:04.151403312", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -145,49 +125,58 @@ "Should run with condition subsetting": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test_characteristic_genes.h5ad:md5,557ccc34f354c9c0b8b74dedd4550688" + "SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 4386, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "leiden", + "sample", + "sample_original" ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + ], - "1": [ - "test_characteristic_genes.pkl:md5,eeebba0ce02541b826cc0b605ef30e3c" - ], - "2": [ - "test_characteristic_genes.png:md5,c49d632c6d6100f7931db5491844fdda" - ], - "3": [ - "test_characteristic_genes_mqc.json:md5,dd8d8a557bda69eb0b0e0d04ad0fc47f" - ], - "4": [ - "versions.yml:md5,a279f17d763d69028f9d84346e55dec8" + "obsm": [ + "X_pca" ], - "h5ad": [ - [ - { - "id": "test" - }, - "test_characteristic_genes.h5ad:md5,557ccc34f354c9c0b8b74dedd4550688" - ] + "varm": [ + "PCs" ], - "multiqc_files": [ - "test_characteristic_genes_mqc.json:md5,dd8d8a557bda69eb0b0e0d04ad0fc47f" + "obsp": [ + "connectivities", + "distances" ], - "plots": [ - "test_characteristic_genes.png:md5,c49d632c6d6100f7931db5491844fdda" + "varp": [ + ], "uns": [ - "test_characteristic_genes.pkl:md5,eeebba0ce02541b826cc0b605ef30e3c" - ], - "versions": [ - "versions.yml:md5,a279f17d763d69028f9d84346e55dec8" + "leiden", + "log1p", + "neighbors", + "pca", + "rank_genes_groups" ] } ], - "timestamp": "2026-03-22T10:08:54.64745021", + "timestamp": "2026-03-30T09:52:00.65325378", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scanpy/readh5/templates/readh5.py b/modules/local/scanpy/readh5/templates/readh5.py index bfb92334..d02c6806 100644 --- a/modules/local/scanpy/readh5/templates/readh5.py +++ b/modules/local/scanpy/readh5/templates/readh5.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform os.environ["MPLCONFIGDIR"] = "./tmp/mpl" diff --git a/modules/local/scanpy/readh5/tests/main.nf.test b/modules/local/scanpy/readh5/tests/main.nf.test index a844a3e3..6d0bff9b 100644 --- a/modules/local/scanpy/readh5/tests/main.nf.test +++ b/modules/local/scanpy/readh5/tests/main.nf.test @@ -25,10 +25,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -53,10 +56,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/readh5/tests/main.nf.test.snap b/modules/local/scanpy/readh5/tests/main.nf.test.snap index d1dfa942..86ce6ac0 100644 --- a/modules/local/scanpy/readh5/tests/main.nf.test.snap +++ b/modules/local/scanpy/readh5/tests/main.nf.test.snap @@ -57,12 +57,55 @@ "versions": [ "versions.yml:md5,cb1290acd28dadec5487c92ca6866c1d" ] + }, + { + "SCANPY_READH5": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 1107, + "n_vars": 507, + "obs": { + "index": "_index", + "columns": [ + + ] + }, + "var": { + "index": "_index", + "columns": [ + "feature_types", + "gene_ids", + "genome" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:14:15.685803076", + "timestamp": "2026-03-29T13:45:54.372715018", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/scanpy/sample/templates/sample.py b/modules/local/scanpy/sample/templates/sample.py index 45a6a311..dadb1059 100644 --- a/modules/local/scanpy/sample/templates/sample.py +++ b/modules/local/scanpy/sample/templates/sample.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform os.environ["MPLCONFIGDIR"] = "./tmp/mpl" diff --git a/modules/local/scanpy/sample/tests/main.nf.test b/modules/local/scanpy/sample/tests/main.nf.test index 8a4d2d7e..9482cfa3 100644 --- a/modules/local/scanpy/sample/tests/main.nf.test +++ b/modules/local/scanpy/sample/tests/main.nf.test @@ -52,10 +52,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -80,10 +83,13 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -110,10 +116,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/sample/tests/main.nf.test.snap b/modules/local/scanpy/sample/tests/main.nf.test.snap index f1e27692..317c8920 100644 --- a/modules/local/scanpy/sample/tests/main.nf.test.snap +++ b/modules/local/scanpy/sample/tests/main.nf.test.snap @@ -24,12 +24,52 @@ "versions": [ "versions.yml:md5,e107029fe0131716a546cc6a1d026522" ] + }, + { + "SCANPY_SAMPLE": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 100, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:15:01.327418477", + "timestamp": "2026-03-29T12:58:39.048199574", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run with fractional subsampling": { @@ -57,12 +97,52 @@ "versions": [ "versions.yml:md5,e107029fe0131716a546cc6a1d026522" ] + }, + { + "SCANPY_SAMPLE": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "n_obs": 6470, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T15:14:41.127806542", + "timestamp": "2026-03-29T12:58:12.748303278", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - stub": { diff --git a/modules/local/scanpy/umap/main.nf b/modules/local/scanpy/umap/main.nf index 77d786ad..e5430d23 100644 --- a/modules/local/scanpy/umap/main.nf +++ b/modules/local/scanpy/umap/main.nf @@ -13,7 +13,6 @@ process SCANPY_UMAP { output: tuple val(meta), path("${prefix}.h5ad"), emit: h5ad path "X_${prefix}.pkl", emit: obsm - path "variance_ratio_${prefix}.yml", emit: variance_ratio path "versions.yml", emit: versions when: @@ -29,7 +28,6 @@ process SCANPY_UMAP { """ touch "${prefix}.h5ad" touch "X_${prefix}.pkl" - touch "variance_ratio_${prefix}.yml" touch "versions.yml" """ } diff --git a/modules/local/scanpy/umap/templates/umap.py b/modules/local/scanpy/umap/templates/umap.py index ee3d6024..c187612b 100644 --- a/modules/local/scanpy/umap/templates/umap.py +++ b/modules/local/scanpy/umap/templates/umap.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" + import platform import argparse import shlex @@ -29,14 +32,6 @@ if params.decimals is not None: adata.obsm["X_umap"] = np.round(adata.obsm["X_umap"].astype(np.float64), params.decimals) -var_per_dim = np.var(adata.obsm["X_umap"].astype(np.float64), axis=0) -variance_ratio = (var_per_dim / var_per_dim.sum()).tolist() -if params.decimals is not None: - variance_ratio = np.round(variance_ratio, params.decimals).tolist() - -with open(f"variance_ratio_{prefix}.yml", "w") as f: - yaml.dump({"variance_ratio": variance_ratio}, f) - adata.write_h5ad(f"{prefix}.h5ad") df = pd.DataFrame(adata.obsm["X_umap"], index=adata.obs_names) df.to_pickle(f"X_{prefix}.pkl") diff --git a/modules/local/scanpy/umap/tests/main.nf.test b/modules/local/scanpy/umap/tests/main.nf.test index 1b6edbc4..29676795 100644 --- a/modules/local/scanpy/umap/tests/main.nf.test +++ b/modules/local/scanpy/umap/tests/main.nf.test @@ -27,16 +27,16 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { - assert snapshot( - path(process.out.variance_ratio[0]).yaml, - path(process.out.versions[0]).yaml - ).match() - }, - { assert "X_umap" in anndata(process.out.h5ad[0][1]).obsm } - ) + def adata = anndata(process.out.h5ad[0][1]) + + assert process.success + + assert "X_umap" in adata.obsm + + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -61,10 +61,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scanpy/umap/tests/main.nf.test.snap b/modules/local/scanpy/umap/tests/main.nf.test.snap index 9ff32e83..c1eb3782 100644 --- a/modules/local/scanpy/umap/tests/main.nf.test.snap +++ b/modules/local/scanpy/umap/tests/main.nf.test.snap @@ -14,9 +14,6 @@ "X_test.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "2": [ - "variance_ratio_test.yml:md5,d41d8cd98f00b204e9800998ecf8427e" - ], - "3": [ "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ], "h5ad": [ @@ -30,15 +27,12 @@ "obsm": [ "X_test.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], - "variance_ratio": [ - "variance_ratio_test.yml:md5,d41d8cd98f00b204e9800998ecf8427e" - ], "versions": [ "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ] } ], - "timestamp": "2026-03-22T11:03:38.032169255", + "timestamp": "2026-03-25T15:45:02.008562399", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -46,21 +40,55 @@ }, "Should run without failures": { "content": [ - { - "variance_ratio": [ - 0.81, - 0.19 - ] - }, { "SCANPY_UMAP": { "pandas": "2.3.3", "python": "3.13.12", "scanpy": "1.12" } + }, + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "leiden", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_pca", + "X_umap" + ], + "varm": [ + "X_pca" + ], + "obsp": [ + "connectivities", + "distances" + ], + "varp": [ + + ], + "uns": [ + "X_pca", + "leiden", + "neighbors", + "umap" + ] } ], - "timestamp": "2026-03-22T11:03:25.274578244", + "timestamp": "2026-03-29T11:17:48.823449269", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scimilarity/annotate/tests/main.nf.test b/modules/local/scimilarity/annotate/tests/main.nf.test index 82e0139e..fa0572b7 100644 --- a/modules/local/scimilarity/annotate/tests/main.nf.test +++ b/modules/local/scimilarity/annotate/tests/main.nf.test @@ -36,10 +36,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scimilarity/annotate/tests/main.nf.test.snap b/modules/local/scimilarity/annotate/tests/main.nf.test.snap index 5b226f6e..e5bdb129 100644 --- a/modules/local/scimilarity/annotate/tests/main.nf.test.snap +++ b/modules/local/scimilarity/annotate/tests/main.nf.test.snap @@ -32,10 +32,10 @@ ] } ], + "timestamp": "2026-01-25T17:16:36.878264104", "meta": { "nf-test": "0.9.2", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-25T17:16:36.878264104" + } } } \ No newline at end of file diff --git a/modules/local/scimilarity/embed/tests/main.nf.test b/modules/local/scimilarity/embed/tests/main.nf.test index 87c9e70a..a727de54 100644 --- a/modules/local/scimilarity/embed/tests/main.nf.test +++ b/modules/local/scimilarity/embed/tests/main.nf.test @@ -36,10 +36,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/scimilarity/embed/tests/main.nf.test.snap b/modules/local/scimilarity/embed/tests/main.nf.test.snap index e5a49987..f9166e20 100644 --- a/modules/local/scimilarity/embed/tests/main.nf.test.snap +++ b/modules/local/scimilarity/embed/tests/main.nf.test.snap @@ -32,10 +32,10 @@ ] } ], + "timestamp": "2026-01-25T17:04:22.682984013", "meta": { "nf-test": "0.9.2", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-25T17:04:22.682984013" + } } } \ No newline at end of file diff --git a/modules/local/scimilarity/pseudobulk/tests/main.nf.test b/modules/local/scimilarity/pseudobulk/tests/main.nf.test index 8819223e..c36bcada 100644 --- a/modules/local/scimilarity/pseudobulk/tests/main.nf.test +++ b/modules/local/scimilarity/pseudobulk/tests/main.nf.test @@ -30,10 +30,18 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + // one pseudobulk row per unique sample + assert "sample" in obs.colnames + assert n_obs > 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -61,10 +69,19 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + // one pseudobulk row per unique sample × leiden combination + assert "sample" in obs.colnames + assert "leiden" in obs.colnames + assert n_obs > 0 + } + assert snapshot( + process.out, + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -93,10 +110,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/scimilarity/pseudobulk/tests/main.nf.test.snap b/modules/local/scimilarity/pseudobulk/tests/main.nf.test.snap index f3186b5b..b8f9da4d 100644 --- a/modules/local/scimilarity/pseudobulk/tests/main.nf.test.snap +++ b/modules/local/scimilarity/pseudobulk/tests/main.nf.test.snap @@ -24,9 +24,52 @@ "versions": [ "versions.yml:md5,85681d93adbb062a90bb197b31eea879" ] + }, + { + "SCIMILARITY_PSEUDOBULK": { + "anndata": "0.12.10", + "python": "3.12.13", + "scimilarity": "0.4.1" + } + }, + { + "n_obs": 3, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "cells", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + "count_nonzero", + "sum" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-20T23:28:46.83306667", + "timestamp": "2026-03-29T11:18:26.581328121", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -57,9 +100,53 @@ "versions": [ "versions.yml:md5,85681d93adbb062a90bb197b31eea879" ] + }, + { + "SCIMILARITY_PSEUDOBULK": { + "anndata": "0.12.10", + "python": "3.12.13", + "scimilarity": "0.4.1" + } + }, + { + "n_obs": 43, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "cells", + "leiden", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + "count_nonzero", + "sum" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-21T08:56:36.22861983", + "timestamp": "2026-03-29T11:20:35.310554907", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scvitools/scanvi/templates/scanvi.py b/modules/local/scvitools/scanvi/templates/scanvi.py index 80a285e8..08364085 100644 --- a/modules/local/scvitools/scanvi/templates/scanvi.py +++ b/modules/local/scvitools/scanvi/templates/scanvi.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8" diff --git a/modules/local/scvitools/scanvi/tests/main.nf.test b/modules/local/scvitools/scanvi/tests/main.nf.test index 94266d43..d26593ca 100644 --- a/modules/local/scvitools/scanvi/tests/main.nf.test +++ b/modules/local/scvitools/scanvi/tests/main.nf.test @@ -45,20 +45,19 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot( + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "X_emb" in obsm + } + assert snapshot( // Hashes are not stable due to floating point inaccuracies - file(process.out.h5ad[0][1]).size(), file(process.out.h5ad[0][1]).name, - file(process.out.model[0][1]).size(), file(process.out.model[0][1]).name, - file(process.out.obsm[0]).size(), file(process.out.obsm[0]).name, - process.out.versions + path(process.out.versions[0]).yaml, + adata.yaml ).match() - }, - ) } } @@ -85,10 +84,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/scvitools/scanvi/tests/main.nf.test.snap b/modules/local/scvitools/scanvi/tests/main.nf.test.snap index a7156a3a..f1aaf8bc 100644 --- a/modules/local/scvitools/scanvi/tests/main.nf.test.snap +++ b/modules/local/scvitools/scanvi/tests/main.nf.test.snap @@ -62,17 +62,63 @@ }, "Should run without failures": { "content": [ - 28863010, "test_scanvi.h5ad", - 1380887, "model.pt", - 6118418, "X_test_scanvi.pkl", - [ - "versions.yml:md5,3d5ccecd49a7565e7f6c86996381d8d4" - ] + { + "SCVITOOLS_SCANVI": { + "scvi": "1.3.3" + } + }, + { + "n_obs": 38234, + "n_vars": 100, + "obs": { + "index": "_index", + "columns": [ + "_scvi_batch", + "_scvi_labels", + "label:scANVI", + "leiden", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "dispersions", + "dispersions_norm", + "highly_variable", + "means" + ] + }, + "layers": [ + + ], + "obsm": [ + "X_emb", + "X_pca" + ], + "varm": [ + "PCs" + ], + "obsp": [ + "connectivities", + "distances" + ], + "varp": [ + + ], + "uns": [ + "hvg", + "leiden", + "log1p", + "neighbors", + "pca" + ] + } ], - "timestamp": "2026-03-22T10:00:38.083128488", + "timestamp": "2026-03-29T11:22:21.217764975", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/scvitools/scvi/templates/scvi.py b/modules/local/scvitools/scvi/templates/scvi.py index 646c3c2f..827767ae 100644 --- a/modules/local/scvitools/scvi/templates/scvi.py +++ b/modules/local/scvitools/scvi/templates/scvi.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8" diff --git a/modules/local/scvitools/scvi/tests/main.nf.test b/modules/local/scvitools/scvi/tests/main.nf.test index f5acff81..fb61a949 100644 --- a/modules/local/scvitools/scvi/tests/main.nf.test +++ b/modules/local/scvitools/scvi/tests/main.nf.test @@ -29,17 +29,16 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot( + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + with(adata) { + assert "X_emb" in obsm + } + assert snapshot( // Hashes are not stable due to floating point inaccuracies - file(process.out.h5ad.get(0).get(1)).size(), - file(process.out.model.get(0).get(1)).size(), - file(process.out.obsm.get(0)).size(), - process.out.versions + path(process.out.versions[0]).yaml, + adata.yaml ).match() - }, - ) } } @@ -68,10 +67,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/scvitools/scvi/tests/main.nf.test.snap b/modules/local/scvitools/scvi/tests/main.nf.test.snap index c50ddffa..96d72d6c 100644 --- a/modules/local/scvitools/scvi/tests/main.nf.test.snap +++ b/modules/local/scvitools/scvi/tests/main.nf.test.snap @@ -56,17 +56,52 @@ }, "Should run without failures": { "content": [ - 18403662, - 26244445, - 6118418, - [ - "versions.yml:md5,8c1ab0d537dc26cb0c55b4fa49f7dafb" - ] + { + "SCVITOOLS_SCVI": { + "scvi": "1.3.3" + } + }, + { + "n_obs": 38234, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "_scvi_batch", + "_scvi_labels", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + "X_emb" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-16T20:35:30.494274963", + "timestamp": "2026-03-29T11:23:09.044443613", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/local/seurat/integration/tests/main.nf.test b/modules/local/seurat/integration/tests/main.nf.test index 78937e3c..32af7969 100644 --- a/modules/local/seurat/integration/tests/main.nf.test +++ b/modules/local/seurat/integration/tests/main.nf.test @@ -54,12 +54,15 @@ nextflow_process { } then { - def h5ad = process.out.h5ad[0][1] - assertAll( - { assert process.success }, - { assert snapshot(process.out.versions).match() }, - { assert "X_emb" in anndata(h5ad).obsm } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + + assert "X_emb" in adata.obsm + + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -81,10 +84,9 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + + assert snapshot(process.out).match() } } diff --git a/modules/local/seurat/integration/tests/main.nf.test.snap b/modules/local/seurat/integration/tests/main.nf.test.snap index 48b7847f..fc44d34f 100644 --- a/modules/local/seurat/integration/tests/main.nf.test.snap +++ b/modules/local/seurat/integration/tests/main.nf.test.snap @@ -26,19 +26,74 @@ ] } ], - "timestamp": "2026-01-25T17:20:38.340547924", + "timestamp": "2026-03-25T15:46:56.458125743", "meta": { - "nf-test": "0.9.2", + "nf-test": "0.9.4", "nextflow": "25.10.2" } }, "Should run without failures": { "content": [ - [ - "versions.yml:md5,c160ec9ef4b681e3c034bd0e0d165987" - ] + { + "SEURAT_INTEGRATION": { + "R": "4.5.3", + "Seurat": "5.4.0", + "anndataR": "1.0.2" + } + }, + { + "n_obs": 27350, + "n_vars": 100, + "obs": { + "index": "_index", + "columns": [ + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + "dispersions", + "dispersions_norm", + "highly_variable", + "mean_counts", + "means", + "mt", + "n_cells", + "n_cells_by_counts", + "n_counts", + "pct_dropout_by_counts", + "total_counts" + ] + }, + "layers": [ + + ], + "obsm": [ + "X_emb" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + "hvg", + "log1p" + ] + } ], - "timestamp": "2026-03-23T23:41:50.78672933", + "timestamp": "2026-03-29T11:22:37.77182437", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/modules/local/soupx/tests/main.nf.test b/modules/local/soupx/tests/main.nf.test index bd78b103..4cca951b 100644 --- a/modules/local/soupx/tests/main.nf.test +++ b/modules/local/soupx/tests/main.nf.test @@ -29,10 +29,47 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + // output written to X, so no named soupx layer + assert !("ambient_corrected_soupx" in adata.layers) + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() + } + + } + + test("Should write to a custom output layer") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = channel.of([ + [ id: 'test' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/scrnaseq/h5ad/SRR28679759_filtered_matrix.h5ad', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/scrnaseq/h5ad/SRR28679759_raw_matrix.h5ad', checkIfExists: true) + ] + ) + input[1] = 0.8 + input[2] = "X" + input[3] = "ambient_corrected_soupx" + """ + } + } + + then { + def adata = anndata(process.out.h5ad[0][1]) + assert process.success + assert "ambient_corrected_soupx" in adata.layers + assert snapshot( + path(process.out.versions[0]).yaml, + adata.yaml + ).match() } } @@ -61,10 +98,8 @@ nextflow_process { } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) + assert process.success + assert snapshot(process.out).match() } } diff --git a/modules/local/soupx/tests/main.nf.test.snap b/modules/local/soupx/tests/main.nf.test.snap index 882cb3de..952b77bb 100644 --- a/modules/local/soupx/tests/main.nf.test.snap +++ b/modules/local/soupx/tests/main.nf.test.snap @@ -35,34 +35,103 @@ "Should run without failures": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test_soupX.h5ad:md5,936b48aa0f6b63215b0d2db2492bbdb7" + "SOUPX": { + "r": "4.5.3", + "anndataR": "1.0.2", + "SoupX": "1.6.2", + "Seurat": "5.4.0" + } + }, + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + ] + }, + "layers": [ + ], - "1": [ - "versions.yml:md5,eebdf63518e672c2ceb40e1bd9c9fbdf" + "obsm": [ + ], - "h5ad": [ - [ - { - "id": "test" - }, - "test_soupX.h5ad:md5,936b48aa0f6b63215b0d2db2492bbdb7" + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } + ], + "timestamp": "2026-03-29T11:17:40.208088329", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } + }, + "Should write to a custom output layer": { + "content": [ + { + "SOUPX": { + "r": "4.5.3", + "anndataR": "1.0.2", + "SoupX": "1.6.2", + "Seurat": "5.4.0" + } + }, + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + ] + }, + "layers": [ + "ambient_corrected_soupx" ], - "versions": [ - "versions.yml:md5,eebdf63518e672c2ceb40e1bd9c9fbdf" + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + ] } ], - "timestamp": "2026-03-17T09:51:41.65597708", + "timestamp": "2026-03-29T11:21:01.296297672", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/modules/nf-core/anndata/barcodes/main.nf b/modules/nf-core/anndata/barcodes/main.nf index 35c7b48c..4893a8c9 100644 --- a/modules/nf-core/anndata/barcodes/main.nf +++ b/modules/nf-core/anndata/barcodes/main.nf @@ -12,7 +12,7 @@ process ANNDATA_BARCODES { output: tuple val(meta), path("*.h5ad"), emit: h5ad - path "versions.yml" , emit: versions + path "versions.yml" , emit: versions_anndata, topic: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/anndata/barcodes/meta.yml b/modules/nf-core/anndata/barcodes/meta.yml index d948e680..5ffc3ecd 100644 --- a/modules/nf-core/anndata/barcodes/meta.yml +++ b/modules/nf-core/anndata/barcodes/meta.yml @@ -1,6 +1,6 @@ name: anndata_barcodes -description: Module to subset AnnData object to cells with matching barcodes from - the csv file +description: Module to subset AnnData object to cells with matching barcodes + from the csv file keywords: - single-cell - barcodes @@ -14,7 +14,8 @@ tools: documentation: "https://anndata.readthedocs.io" tool_dev_url: "https://github.com/theislab/anndata" doi: "10.21105/joss.04371" - licence: ["BSD-3-clause"] + licence: + - "BSD-3-clause" identifier: biotools:anndata input: - - meta: @@ -50,13 +51,21 @@ output: pattern: "*.h5ad" ontologies: - edam: "http://edamontology.org/format_3590" # HDF5 - versions: + versions_anndata: - versions.yml: type: file description: File containing software versions pattern: "versions.yml" ontologies: - edam: "http://edamontology.org/format_3750" # YAML +topics: + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: "http://edamontology.org/format_3750" authors: - "@nictru" - "@chaochaowong" diff --git a/modules/nf-core/anndata/barcodes/tests/main.nf.test b/modules/nf-core/anndata/barcodes/tests/main.nf.test index 09dab520..2b68f8c4 100644 --- a/modules/nf-core/anndata/barcodes/tests/main.nf.test +++ b/modules/nf-core/anndata/barcodes/tests/main.nf.test @@ -15,7 +15,7 @@ nextflow_process { """ input[0] = channel.from([ [ - [ id:'test', single_end:false ], // meta map + [ id:'test' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/scrnaseq/h5ad/SRR28679759_filtered_matrix.h5ad', checkIfExists: true) ] @@ -27,7 +27,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } @@ -42,7 +42,7 @@ nextflow_process { """ input[0] = channel.from([ [ - [ id:'test', single_end:false ], // meta map + [ id:'test' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/scrnaseq/h5ad/SRR28679759_filtered_matrix.h5ad', checkIfExists: true) ] @@ -54,7 +54,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } diff --git a/modules/nf-core/anndata/barcodes/tests/main.nf.test.snap b/modules/nf-core/anndata/barcodes/tests/main.nf.test.snap index 070bed63..34c7ec56 100644 --- a/modules/nf-core/anndata/barcodes/tests/main.nf.test.snap +++ b/modules/nf-core/anndata/barcodes/tests/main.nf.test.snap @@ -2,71 +2,45 @@ "scdownstream - h5ad - csv - stub": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,a67b616625325797d4ae6f996b2cfb1d" - ], "h5ad": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ + "versions_anndata": [ "versions.yml:md5,a67b616625325797d4ae6f996b2cfb1d" ] } ], + "timestamp": "2026-03-15T19:12:06.598082087", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-11T13:32:57.324009122" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "scdownstream - h5ad - csv": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.h5ad:md5,d07d45f8d8d46411bf049f3ccff475f3" - ] - ], - "1": [ - "versions.yml:md5,c101fba36a629db79bf582b25fa301dd" - ], "h5ad": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.h5ad:md5,d07d45f8d8d46411bf049f3ccff475f3" ] ], - "versions": [ + "versions_anndata": [ "versions.yml:md5,c101fba36a629db79bf582b25fa301dd" ] } ], + "timestamp": "2026-03-15T19:11:57.14168146", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-11T13:32:49.298191972" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/cellbender/merge/cellbender-merge.diff b/modules/nf-core/cellbender/merge/cellbender-merge.diff deleted file mode 100644 index 89782904..00000000 --- a/modules/nf-core/cellbender/merge/cellbender-merge.diff +++ /dev/null @@ -1,27 +0,0 @@ -Changes in component 'nf-core/cellbender/merge' -'modules/nf-core/cellbender/merge/environment.yml' is unchanged -'modules/nf-core/cellbender/merge/meta.yml' is unchanged -Changes in 'cellbender/merge/main.nf': ---- modules/nf-core/cellbender/merge/main.nf -+++ modules/nf-core/cellbender/merge/main.nf -@@ -9,6 +9,7 @@ - - input: - tuple val(meta), path(filtered), path(unfiltered), path(cellbender_h5) -+ val(output_layer) - - output: - tuple val(meta), path("${prefix}.h5ad"), emit: h5ad -@@ -19,7 +20,6 @@ - - script: - prefix = task.ext.prefix ?: "${meta.id}" -- output_layer = task.ext.output_layer ?: "cellbender" - template 'merge.py' - - stub: - -'modules/nf-core/cellbender/merge/tests/main.nf.test.snap' is unchanged -'modules/nf-core/cellbender/merge/tests/main.nf.test' is unchanged -'modules/nf-core/cellbender/merge/templates/merge.py' is unchanged -************************************************************ diff --git a/modules/nf-core/cellbender/merge/main.nf b/modules/nf-core/cellbender/merge/main.nf index 27ea4c99..4b684552 100644 --- a/modules/nf-core/cellbender/merge/main.nf +++ b/modules/nf-core/cellbender/merge/main.nf @@ -9,17 +9,23 @@ process CELLBENDER_MERGE { input: tuple val(meta), path(filtered), path(unfiltered), path(cellbender_h5) - val(output_layer) + val(output_layer_name) output: tuple val(meta), path("${prefix}.h5ad"), emit: h5ad - path "versions.yml" , emit: versions + path "versions.yml" , emit: versions_cellbender, topic: versions when: task.ext.when == null || task.ext.when script: prefix = task.ext.prefix ?: "${meta.id}" + output_layer = output_layer_name ?: "cellbender" + + """ + echo ${output_layer} + """ + template 'merge.py' stub: diff --git a/modules/nf-core/cellbender/merge/meta.yml b/modules/nf-core/cellbender/merge/meta.yml index 4ad77d9e..3ca4f6a3 100644 --- a/modules/nf-core/cellbender/merge/meta.yml +++ b/modules/nf-core/cellbender/merge/meta.yml @@ -1,17 +1,19 @@ name: cellbender_merge -description: Module to use CellBender to remove ambient RNA from single-cell RNA-seq - data +description: Module to use CellBender to remove ambient RNA from single-cell + RNA-seq data keywords: - single-cell - scRNA-seq - ambient RNA removal tools: - cellbender: - description: CellBender is a software package for eliminating technical artifacts - from high-throughput single-cell RNA sequencing (scRNA-seq) data. + description: CellBender is a software package for eliminating technical + artifacts from high-throughput single-cell RNA sequencing (scRNA-seq) + data. documentation: https://cellbender.readthedocs.io/en/latest/ tool_dev_url: https://github.com/broadinstitute/CellBender - licence: ["BSD-3-Clause"] + licence: + - "BSD-3-Clause" identifier: biotools:CellBender input: - - meta: @@ -21,7 +23,8 @@ input: e.g. [ id:'test' ] - filtered: type: file - description: AnnData file containing filtered data (without empty droplets) + description: AnnData file containing filtered data (without empty + droplets) pattern: "*.h5ad" ontologies: [] - unfiltered: @@ -34,6 +37,9 @@ input: description: CellBender h5 file containing ambient RNA estimates pattern: "*.h5" ontologies: [] + - output_layer_name: + type: string + description: The name of the layer to store counts output: h5ad: - - meta: @@ -46,13 +52,21 @@ output: description: AnnData file containing decontaminated counts as `adata.X` pattern: "*.h5ad" ontologies: [] + versions_cellbender: + - versions.yml: + type: file + description: File containing software version + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 +topics: versions: - versions.yml: type: file description: File containing software version pattern: "versions.yml" ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - edam: http://edamontology.org/format_3750 authors: - "@nictru" maintainers: diff --git a/modules/nf-core/cellbender/merge/tests/main.nf.test b/modules/nf-core/cellbender/merge/tests/main.nf.test index f6de930b..f2b47d16 100644 --- a/modules/nf-core/cellbender/merge/tests/main.nf.test +++ b/modules/nf-core/cellbender/merge/tests/main.nf.test @@ -18,6 +18,7 @@ nextflow_process { file(params.modules_testdata_base_path + 'genomics/homo_sapiens/scrnaseq/h5ad/SRR28679759_raw_matrix.h5ad', checkIfExists: true), file("https://raw.githubusercontent.com/nf-core/test-datasets/scdownstream/intermediates/SRR28679759_cellbender.h5", checkIfExists: true) ] + input[1] = '' """ } } @@ -40,6 +41,7 @@ nextflow_process { file(params.modules_testdata_base_path + 'genomics/homo_sapiens/scrnaseq/h5ad/SRR28679759_raw_matrix.h5ad', checkIfExists: true), file("https://raw.githubusercontent.com/nf-core/test-datasets/scdownstream/intermediates/SRR28679759_cellbender.h5", checkIfExists: true) ] + input[1] = '' """ } } diff --git a/modules/nf-core/cellbender/merge/tests/main.nf.test.snap b/modules/nf-core/cellbender/merge/tests/main.nf.test.snap index 40fa0d00..8f9d1cd6 100644 --- a/modules/nf-core/cellbender/merge/tests/main.nf.test.snap +++ b/modules/nf-core/cellbender/merge/tests/main.nf.test.snap @@ -21,16 +21,16 @@ "test.h5ad:md5,d76d209cda94917cc4faf430d288480c" ] ], - "versions": [ + "versions_cellbender": [ "versions.yml:md5,52469695a4396996323548dcd4f659ec" ] } ], + "timestamp": "2026-03-13T12:59:16.360615406", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-24T10:36:28.084259232" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_cellbender_merge - stub": { "content": [ @@ -54,15 +54,15 @@ "test.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ + "versions_cellbender": [ "versions.yml:md5,b5c0e4b30e6148c29e758b0600ac3c7b" ] } ], + "timestamp": "2026-03-13T12:59:28.800015588", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-24T10:40:42.308329653" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/cellbender/removebackground/main.nf b/modules/nf-core/cellbender/removebackground/main.nf index e2d0b004..0cff86d6 100644 --- a/modules/nf-core/cellbender/removebackground/main.nf +++ b/modules/nf-core/cellbender/removebackground/main.nf @@ -22,46 +22,35 @@ process CELLBENDER_REMOVEBACKGROUND { tuple val(meta), path("${prefix}.pdf") , emit: pdf tuple val(meta), path("${prefix}.log") , emit: log tuple val(meta), path("ckpt.tar.gz") , emit: checkpoint - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('cellbender'), eval('cellbender --version'), emit: versions_cellbender, topic: versions when: - task.ext.when == null || task.ext.when - + task.ext.when == null || task.ext.when script: - prefix = task.ext.prefix ?: "${meta.id}" - args = task.ext.args ?: "" - use_gpu = task.ext.use_gpu ? "--cuda" : "" - """ - TMPDIR=. cellbender remove-background \ - ${args} \ - --cpu-threads ${task.cpus} \ - --estimator-multiple-cpu \ - ${use_gpu} \ - --input ${h5ad} \ - --output ${prefix}.h5 - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cellbender: \$(cellbender --version) - END_VERSIONS - """ + prefix = task.ext.prefix ?: "${meta.id}" + args = task.ext.args ?: "" + use_gpu = task.ext.use_gpu ? "--cuda" : "" + """ + TMPDIR=. cellbender remove-background \ + ${args} \ + --cpu-threads ${task.cpus} \ + --estimator-multiple-cpu \ + ${use_gpu} \ + --input ${h5ad} \ + --output ${prefix}.h5 + """ stub: - prefix = task.ext.prefix ?: "${meta.id}" - """ - touch "${prefix}.h5" - touch "${prefix}_filtered.h5" - touch "${prefix}_posterior.h5" - touch "${prefix}_cell_barcodes.csv" - touch "${prefix}_metrics.csv" - touch "${prefix}_report.html" - touch "${prefix}.pdf" - touch "${prefix}.log" - echo "" | gzip > ckpt.tar.gz - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cellbender: \$(cellbender --version) - END_VERSIONS - """ + prefix = task.ext.prefix ?: "${meta.id}" + """ + touch "${prefix}.h5" + touch "${prefix}_filtered.h5" + touch "${prefix}_posterior.h5" + touch "${prefix}_cell_barcodes.csv" + touch "${prefix}_metrics.csv" + touch "${prefix}_report.html" + touch "${prefix}.pdf" + touch "${prefix}.log" + echo "" | gzip > ckpt.tar.gz + """ } diff --git a/modules/nf-core/cellbender/removebackground/meta.yml b/modules/nf-core/cellbender/removebackground/meta.yml index a1f5d1e7..80348782 100644 --- a/modules/nf-core/cellbender/removebackground/meta.yml +++ b/modules/nf-core/cellbender/removebackground/meta.yml @@ -1,17 +1,19 @@ name: cellbender_removebackground -description: Module to use CellBender to estimate ambient RNA from single-cell RNA-seq - data +description: Module to use CellBender to estimate ambient RNA from single-cell + RNA-seq data keywords: - single-cell - scRNA-seq - ambient RNA removal tools: - cellbender: - description: CellBender is a software package for eliminating technical artifacts - from high-throughput single-cell RNA sequencing (scRNA-seq) data. + description: CellBender is a software package for eliminating technical + artifacts from high-throughput single-cell RNA sequencing (scRNA-seq) + data. documentation: https://cellbender.readthedocs.io/en/latest/ tool_dev_url: https://github.com/broadinstitute/CellBender - licence: ["BSD-3-Clause"] + licence: + - "BSD-3-Clause" identifier: biotools:CellBender input: - - meta: @@ -31,8 +33,8 @@ output: description: Groovy Map containing sample information - ${prefix}.h5: type: file - description: Full count matrix as an h5 file, with background RNA removed. - This file contains all the original droplet barcodes. + description: Full count matrix as an h5 file, with background RNA + removed. This file contains all the original droplet barcodes. pattern: "*.h5" ontologies: [] filtered_h5: @@ -67,7 +69,7 @@ output: but is included as a separate output for convenient use in certain downstream applications. pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 #CSV metrics: - - meta: type: map @@ -79,7 +81,7 @@ output: when using CellBender as part of a large-scale automated pipeline. pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 #CSV report: - - meta: type: map @@ -96,8 +98,8 @@ output: description: Groovy Map containing sample information - ${prefix}.pdf: type: file - description: PDF file that provides a standard graphical summary of the inference - procedure. + description: PDF file that provides a standard graphical summary of the + inference procedure. pattern: "*.pdf" ontologies: [] log: @@ -115,17 +117,31 @@ output: description: Groovy Map containing sample information - ckpt.tar.gz: type: file - description: Checkpoint file which contains the trained model and the full - posterior. + description: Checkpoint file which contains the trained model and the + full posterior. pattern: "*.ckpt" ontologies: [] + versions_cellbender: + - - ${task.process}: + type: string + description: The name of the process + - cellbender: + type: string + description: The name of the tool + - cellbender --version: + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software version - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - cellbender: + type: string + description: The name of the tool + - cellbender --version: + type: eval + description: The expression to obtain the version of the tool authors: - "@nictru" maintainers: diff --git a/modules/nf-core/cellbender/removebackground/tests/gpu.nf.test b/modules/nf-core/cellbender/removebackground/tests/gpu.nf.test index f9e158a9..398ce227 100644 --- a/modules/nf-core/cellbender/removebackground/tests/gpu.nf.test +++ b/modules/nf-core/cellbender/removebackground/tests/gpu.nf.test @@ -25,7 +25,7 @@ nextflow_process { assertAll( {assert process.success}, {assert snapshot( - process.out.versions, + process.out.findAll { key, val -> key.startsWith('versions') }, process.out.h5.collect{file(it[1]).name}, process.out.filtered_h5.collect{file(it[1]).name}, process.out.posterior_h5.collect{file(it[1]).name}, diff --git a/modules/nf-core/cellbender/removebackground/tests/gpu.nf.test.snap b/modules/nf-core/cellbender/removebackground/tests/gpu.nf.test.snap index b9990a90..081c6a90 100644 --- a/modules/nf-core/cellbender/removebackground/tests/gpu.nf.test.snap +++ b/modules/nf-core/cellbender/removebackground/tests/gpu.nf.test.snap @@ -1,9 +1,15 @@ { "test_cellbender_removebackground": { "content": [ - [ - "versions.yml:md5,53e48cca1f71828723220055334da62d" - ], + { + "versions_cellbender": [ + [ + "CELLBENDER_REMOVEBACKGROUND", + "cellbender", + "0.3.2" + ] + ] + }, [ "test.h5" ], @@ -29,11 +35,11 @@ "test.log" ] ], + "timestamp": "2026-03-13T15:28:36.521030974", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-24T11:25:08.924988231" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_cellbender_removebackground - stub": { "content": [ @@ -111,7 +117,11 @@ ] ], "9": [ - "versions.yml:md5,53e48cca1f71828723220055334da62d" + [ + "CELLBENDER_REMOVEBACKGROUND", + "cellbender", + "0.3.2" + ] ], "barcodes": [ [ @@ -185,15 +195,19 @@ "test_report.html:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,53e48cca1f71828723220055334da62d" + "versions_cellbender": [ + [ + "CELLBENDER_REMOVEBACKGROUND", + "cellbender", + "0.3.2" + ] ] } ], + "timestamp": "2026-03-12T14:54:31.232109215", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-11T10:58:34.420027935" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/cellbender/removebackground/tests/main.nf.test b/modules/nf-core/cellbender/removebackground/tests/main.nf.test index 9941c169..c1213509 100644 --- a/modules/nf-core/cellbender/removebackground/tests/main.nf.test +++ b/modules/nf-core/cellbender/removebackground/tests/main.nf.test @@ -24,7 +24,7 @@ nextflow_process { assertAll( {assert process.success}, {assert snapshot( - process.out.versions, + process.out.findAll { key, val -> key.startsWith('versions') }, process.out.h5.collect{file(it[1]).name}, process.out.filtered_h5.collect{file(it[1]).name}, process.out.posterior_h5.collect{file(it[1]).name}, diff --git a/modules/nf-core/cellbender/removebackground/tests/main.nf.test.snap b/modules/nf-core/cellbender/removebackground/tests/main.nf.test.snap index b9990a90..65d63698 100644 --- a/modules/nf-core/cellbender/removebackground/tests/main.nf.test.snap +++ b/modules/nf-core/cellbender/removebackground/tests/main.nf.test.snap @@ -1,9 +1,15 @@ { "test_cellbender_removebackground": { "content": [ - [ - "versions.yml:md5,53e48cca1f71828723220055334da62d" - ], + { + "versions_cellbender": [ + [ + "CELLBENDER_REMOVEBACKGROUND", + "cellbender", + "0.3.2" + ] + ] + }, [ "test.h5" ], @@ -29,11 +35,11 @@ "test.log" ] ], + "timestamp": "2026-03-13T15:30:56.645899744", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-24T11:25:08.924988231" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_cellbender_removebackground - stub": { "content": [ @@ -111,7 +117,11 @@ ] ], "9": [ - "versions.yml:md5,53e48cca1f71828723220055334da62d" + [ + "CELLBENDER_REMOVEBACKGROUND", + "cellbender", + "0.3.2" + ] ], "barcodes": [ [ @@ -185,15 +195,19 @@ "test_report.html:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,53e48cca1f71828723220055334da62d" + "versions_cellbender": [ + [ + "CELLBENDER_REMOVEBACKGROUND", + "cellbender", + "0.3.2" + ] ] } ], + "timestamp": "2026-03-12T14:56:46.093356987", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-11T10:58:34.420027935" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c1f4a7982b743963_1.txt b/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c1f4a7982b743963_1.txt new file mode 100644 index 00000000..76190304 --- /dev/null +++ b/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c1f4a7982b743963_1.txt @@ -0,0 +1,1552 @@ + +version: 6 +environments: +default: +channels: +- url: https://conda.anaconda.org/conda-forge/ +- url: https://conda.anaconda.org/bioconda/ +- url: https://conda.anaconda.org/bioconda/ +options: +pypi-prerelease-mode: if-necessary-or-explicit +packages: +linux-64: +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.4-hecca717_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/kaleido-core-0.2.1-h3644ca4_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.55-h421ea60_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py314h67df5f8_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/mathjax-2.7.7-ha770c72_3.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.33-pyhdfd78af_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.18.1-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.3-py314h2b28147_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.1.1-py314h8ec4b1a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.39.3-pyh58ad624_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-lts-cpu-1.34.0.deprecated-hc364b38_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.39.3-py310hffdcd12_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-compat-1.39.3-py310hbcd5346_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py314h2e6c369_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.3-h32b2ec7_101_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/regex-2026.2.28-py314h5bd0f2a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py314h2e6c369_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/tiktoken-0.12.0-py314h67fec18_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.1-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda +packages: +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda +build_number: 20 +sha256: 1dd3fffd892081df9726d7eb7e0dea6198962ba775bd88842135a4ddb4deb3c9 +md5: a9f577daf3de00bca7c3c76c0ecbd1de +depends: +- __glibc >=2.17,<3.0.a0 +- libgomp >=7.5.0 +constrains: +- openmp_impl <0.0a0 +license: BSD-3-Clause +license_family: BSD +size: 28948 +timestamp: 1770939786096 +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +sha256: a3967b937b9abf0f2a99f3173fa4630293979bd1644709d89580e7c62a544661 +md5: aaa2a381ccc56eac91d63b6c1240312f +depends: +- cpython +- python-gil +license: MIT +license_family: MIT +size: 8191 +timestamp: 1744137672556 +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +sha256: e0ea1ba78fbb64f17062601edda82097fcf815012cf52bb704150a2668110d48 +md5: 2934f256a8acfe48f6ebb4fce6cde29c +depends: +- python >=3.9 +- typing-extensions >=4.0.0 +license: MIT +license_family: MIT +size: 18074 +timestamp: 1733247158254 +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +sha256: 1b6124230bb4e571b1b9401537ecff575b7b109cc3a21ee019f65e083b8399ab +md5: c6b0543676ecb1fb2d7643941fe375f2 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 64927 +timestamp: 1773935801332 +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda +noarch: generic +sha256: c31ab719d256bc6f89926131e88ecd0f0c5d003fe8481852c6424f4ec6c7eb29 +md5: a2ac7763a9ac75055b68f325d3255265 +depends: +- python >=3.14 +license: BSD-3-Clause AND MIT AND EPL-2.0 +size: 7514 +timestamp: 1767044983590 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda +sha256: 3ad3500bff54a781c29f16ce1b288b36606e2189d0b0ef2f67036554f47f12b0 +md5: 8910d2c46f7e7b519129f486e0fe927a +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +constrains: +- libbrotlicommon 1.2.0 hb03c661_1 +license: MIT +license_family: MIT +size: 367376 +timestamp: 1764017265553 +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda +sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 +md5: d2ffd7602c02f2b316fd921d39876885 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: bzip2-1.0.6 +license_family: BSD +size: 260182 +timestamp: 1771350215188 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda +sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc +md5: 4492fd26db29495f0ba23f146cd5638d +depends: +- __unix +license: ISC +size: 147413 +timestamp: 1772006283803 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda +sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 +md5: 765c4d97e877cdbbb88ff33152b86125 +depends: +- python >=3.10 +license: ISC +size: 151445 +timestamp: 1772001170301 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda +sha256: d86dfd428b2e3c364fa90e07437c8405d635aa4ef54b25ab51d9c712be4112a5 +md5: 49ee13eb9b8f44d63879c69b8a40a74b +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 58510 +timestamp: 1773660086450 +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda +sha256: 38cfe1ee75b21a8361c8824f5544c3866f303af1762693a178266d7f198e8715 +md5: ea8a6c3256897cc31263de9f455e25d9 +depends: +- python >=3.10 +- __unix +- python +license: BSD-3-Clause +license_family: BSD +size: 97676 +timestamp: 1764518652276 +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +sha256: 8021c76eeadbdd5784b881b165242db9449783e12ce26d6234060026fd6a8680 +md5: b866ff7007b934d564961066c8195983 +depends: +- humanfriendly >=9.1 +- python >=3.9 +license: MIT +license_family: MIT +size: 43758 +timestamp: 1733928076798 +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +sha256: 59c9e29800b483b390467f90e82b0da3a4fbf0612efe1c90813fca232780e160 +md5: 071cf7b0ce333c81718b054066c15102 +depends: +- networkx >=2.0 +- numpy +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 39326 +timestamp: 1735759976140 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda +noarch: generic +sha256: 91b06300879df746214f7363d6c27c2489c80732e46a369eb2afc234bcafb44c +md5: 3bb89e4f795e5414addaa531d6b1500a +depends: +- python >=3.14,<3.15.0a0 +- python_abi * *_cp314 +license: Python-2.0 +size: 50078 +timestamp: 1770674447292 +- conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.4-hecca717_0.conda +sha256: 0cc345e4dead417996ce9a1f088b28d858f03d113d43c1963d29194366dcce27 +md5: a0535741a4934b3e386051065c58761a +depends: +- __glibc >=2.17,<3.0.a0 +- libexpat 2.7.4 hecca717_0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 145274 +timestamp: 1771259434699 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b +md5: 0c96522c6bdaed4b1566d11387caaf45 +license: BSD-3-Clause +license_family: BSD +size: 397370 +timestamp: 1566932522327 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c +md5: 34893075a5c9e55cdafac56607368fc6 +license: OFL-1.1 +license_family: Other +size: 96530 +timestamp: 1620479909603 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139 +md5: 4d59c254e01d9cde7957100457e2d5fb +license: OFL-1.1 +license_family: Other +size: 700814 +timestamp: 1620479612257 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14 +md5: 49023d73832ef61042f6a237cb2687e7 +license: LicenseRef-Ubuntu-Font-Licence-Version-1.0 +license_family: Other +size: 1620504 +timestamp: 1727511233259 +- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda +sha256: aa4a44dba97151221100a637c7f4bde619567afade9c0265f8e1c8eed8d7bd8c +md5: 867127763fbe935bab59815b6e0b7b5c +depends: +- __glibc >=2.17,<3.0.a0 +- libexpat >=2.7.4,<3.0a0 +- libfreetype >=2.14.1 +- libfreetype6 >=2.14.1 +- libgcc >=14 +- libuuid >=2.41.3,<3.0a0 +- libzlib >=1.3.1,<2.0a0 +license: MIT +license_family: MIT +size: 270705 +timestamp: 1771382710863 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333 +md5: a7970cd949a077b7cb9696379d338681 +depends: +- font-ttf-ubuntu +- font-ttf-inconsolata +- font-ttf-dejavu-sans-mono +- font-ttf-source-code-pro +license: BSD-3-Clause +license_family: BSD +size: 4059 +timestamp: 1762351264405 +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +sha256: 84c64443368f84b600bfecc529a1194a3b14c3656ee2e832d15a20e0329b6da3 +md5: 164fc43f0b53b6e3a7bc7dce5e4f1dc9 +depends: +- python >=3.10 +- hyperframe >=6.1,<7 +- hpack >=4.1,<5 +- python +license: MIT +license_family: MIT +size: 95967 +timestamp: 1756364871835 +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba +md5: 0a802cb9888dd14eeefc611f05c40b6e +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 30731 +timestamp: 1737618390337 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +sha256: fa2071da7fab758c669e78227e6094f6b3608228740808a6de5d6bce83d9e52d +md5: 7fe569c10905402ed47024fc481bb371 +depends: +- __unix +- python >=3.9 +license: MIT +license_family: MIT +size: 73563 +timestamp: 1733928021866 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +sha256: 6c4343b376d0b12a4c75ab992640970d36c933cad1fd924f6a1181fa91710e80 +md5: daddf757c3ecd6067b9af1df1f25d89e +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 67994 +timestamp: 1766267728652 +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +sha256: 77af6f5fe8b62ca07d09ac60127a30d9069fdc3c68d6b256754d0ffb1f7779f8 +md5: 8e6923fc12f1fe8f8c4e5c9f343256ac +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 17397 +timestamp: 1737618427549 +- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda +sha256: fbf86c4a59c2ed05bbffb2ba25c7ed94f6185ec30ecb691615d42342baa1a16a +md5: c80d8a3b84358cb967fa81e7075fbc8a +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: MIT +license_family: MIT +size: 12723451 +timestamp: 1773822285671 +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda +sha256: ae89d0299ada2a3162c2614a9d26557a92aa6a77120ce142f8e0109bbf0342b0 +md5: 53abe63df7e10a6ba605dc5f9f961d36 +depends: +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 50721 +timestamp: 1760286526795 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda +sha256: 82ab2a0d91ca1e7e63ab6a4939356667ef683905dea631bc2121aa534d347b16 +md5: 080594bf4493e6bae2607e65390c520a +depends: +- python >=3.10 +- zipp >=3.20 +- python +license: Apache-2.0 +license_family: APACHE +size: 34387 +timestamp: 1773931568510 +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +sha256: fc9ca7348a4f25fed2079f2153ecdcf5f9cf2a0bc36c4172420ca09e1849df7b +md5: 04558c96691bed63104678757beb4f8d +depends: +- markupsafe >=2.0 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 120685 +timestamp: 1764517220861 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +sha256: db973a37d75db8e19b5f44bbbdaead0c68dde745407f281e2a7fe4db74ec51d7 +md5: ada41c863af263cc4c5fcbaff7c3e4dc +depends: +- attrs >=22.2.0 +- jsonschema-specifications >=2023.3.6 +- python >=3.10 +- referencing >=0.28.4 +- rpds-py >=0.25.0 +- python +license: MIT +license_family: MIT +size: 82356 +timestamp: 1767839954256 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +sha256: 0a4f3b132f0faca10c89fdf3b60e15abb62ded6fa80aebfc007d05965192aa04 +md5: 439cd0f567d697b20a8f45cb70a1005a +depends: +- python >=3.10 +- referencing >=0.31.0 +- python +license: MIT +license_family: MIT +size: 19236 +timestamp: 1757335715225 +- conda: https://conda.anaconda.org/conda-forge/linux-64/kaleido-core-0.2.1-h3644ca4_0.tar.bz2 +sha256: 7f243680ca03eba7457b7a48f93a9440ba8181a8eac20a3eb5ef165ab6c96664 +md5: b3723b235b0758abaae8c82ce4d80146 +depends: +- __glibc >=2.17,<3.0.a0 +- expat >=2.2.10,<3.0.0a0 +- fontconfig +- fonts-conda-forge +- libgcc-ng >=9.3.0 +- mathjax 2.7.* +- nspr >=4.29,<5.0a0 +- nss >=3.62,<4.0a0 +- sqlite >=3.34.0,<4.0a0 +license: MIT +license_family: MIT +size: 62099926 +timestamp: 1615199463039 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda +sha256: 836ec4b895352110335b9fdcfa83a8dcdbe6c5fb7c06c4929130600caea91c0a +md5: 6f2e2c8f58160147c4d1c6f4c14cbac4 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.2,<4.0a0 +- libtiff >=4.7.1,<4.8.0a0 +license: MIT +license_family: MIT +size: 249959 +timestamp: 1768184673131 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda +sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c +md5: 18335a698559cdbcd86150a48bf54ba6 +depends: +- __glibc >=2.17,<3.0.a0 +- zstd >=1.5.7,<1.6.0a0 +constrains: +- binutils_impl_linux-64 2.45.1 +license: GPL-3.0-only +license_family: GPL +size: 728002 +timestamp: 1774197446916 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda +sha256: f84cb54782f7e9cea95e810ea8fef186e0652d0fa73d3009914fa2c1262594e1 +md5: a752488c68f2e7c456bcbd8f16eec275 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: Apache-2.0 +license_family: Apache +size: 261513 +timestamp: 1773113328888 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda +build_number: 5 +sha256: 18c72545080b86739352482ba14ba2c4815e19e26a7417ca21a95b76ec8da24c +md5: c160954f7418d7b6e87eaf05a8913fa9 +depends: +- libopenblas >=0.3.30,<0.3.31.0a0 +- libopenblas >=0.3.30,<1.0a0 +constrains: +- mkl <2026 +- liblapack 3.11.0 5*_openblas +- libcblas 3.11.0 5*_openblas +- blas 2.305 openblas +- liblapacke 3.11.0 5*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18213 +timestamp: 1765818813880 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda +build_number: 5 +sha256: 0cbdcc67901e02dc17f1d19e1f9170610bd828100dc207de4d5b6b8ad1ae7ad8 +md5: 6636a2b6f1a87572df2970d3ebc87cc0 +depends: +- libblas 3.11.0 5_h4a7cf45_openblas +constrains: +- liblapacke 3.11.0 5*_openblas +- blas 2.305 openblas +- liblapack 3.11.0 5*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18194 +timestamp: 1765818837135 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda +sha256: aa8e8c4be9a2e81610ddf574e05b64ee131fab5e0e3693210c9d6d2fba32c680 +md5: 6c77a605a7a689d17d4819c0f8ac9a00 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 73490 +timestamp: 1761979956660 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda +sha256: d78f1d3bea8c031d2f032b760f36676d87929b18146351c4464c66b0869df3f5 +md5: e7f7ce06ec24cfcfb9e36d28cf82ba57 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- expat 2.7.4.* +license: MIT +license_family: MIT +size: 76798 +timestamp: 1771259418166 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda +sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6 +md5: a360c33a5abe61c07959e449fa1453eb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 58592 +timestamp: 1769456073053 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda +sha256: 38f014a7129e644636e46064ecd6b1945e729c2140e21d75bb476af39e692db2 +md5: e289f3d17880e44b633ba911d57a321b +depends: +- libfreetype6 >=2.14.3 +license: GPL-2.0-only OR FTL +size: 8049 +timestamp: 1774298163029 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda +sha256: 16f020f96da79db1863fcdd8f2b8f4f7d52f177dd4c58601e38e9182e91adf1d +md5: fb16b4b69e3f1dcfe79d80db8fd0c55d +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libpng >=1.6.55,<1.7.0a0 +- libzlib >=1.3.2,<2.0a0 +constrains: +- freetype >=2.14.3 +license: GPL-2.0-only OR FTL +size: 384575 +timestamp: 1774298162622 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda +sha256: faf7d2017b4d718951e3a59d081eb09759152f93038479b768e3d612688f83f5 +md5: 0aa00f03f9e39fb9876085dee11a85d4 +depends: +- __glibc >=2.17,<3.0.a0 +- _openmp_mutex >=4.5 +constrains: +- libgcc-ng ==15.2.0=*_18 +- libgomp 15.2.0 he0feb66_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 1041788 +timestamp: 1771378212382 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda +sha256: e318a711400f536c81123e753d4c797a821021fb38970cebfb3f454126016893 +md5: d5e96b1ed75ca01906b3d2469b4ce493 +depends: +- libgcc 15.2.0 he0feb66_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27526 +timestamp: 1771378224552 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda +sha256: d2c9fad338fd85e4487424865da8e74006ab2e2475bd788f624d7a39b2a72aee +md5: 9063115da5bc35fdc3e1002e69b9ef6e +depends: +- libgfortran5 15.2.0 h68bc16d_18 +constrains: +- libgfortran-ng ==15.2.0=*_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27523 +timestamp: 1771378269450 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda +sha256: 539b57cf50ec85509a94ba9949b7e30717839e4d694bc94f30d41c9d34de2d12 +md5: 646855f357199a12f02a87382d429b75 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=15.2.0 +constrains: +- libgfortran 15.2.0 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 2482475 +timestamp: 1771378241063 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda +sha256: 21337ab58e5e0649d869ab168d4e609b033509de22521de1bfed0c031bfc5110 +md5: 239c5e9546c38a1e884d69effcf4c882 +depends: +- __glibc >=2.17,<3.0.a0 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 603262 +timestamp: 1771378117851 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda +sha256: cc9aba923eea0af8e30e0f94f2ad7156e2984d80d1e8e7fe6be5a1f257f0eb32 +md5: 8397539e3a0bbd1695584fb4f927485a +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- jpeg <0.0.0a +license: IJG AND BSD-3-Clause AND Zlib +size: 633710 +timestamp: 1762094827865 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda +build_number: 5 +sha256: c723b6599fcd4c6c75dee728359ef418307280fa3e2ee376e14e85e5bbdda053 +md5: b38076eb5c8e40d0106beda6f95d7609 +depends: +- libblas 3.11.0 5_h4a7cf45_openblas +constrains: +- blas 2.305 openblas +- liblapacke 3.11.0 5*_openblas +- libcblas 3.11.0 5*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18200 +timestamp: 1765818857876 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda +sha256: 755c55ebab181d678c12e49cced893598f2bab22d582fbbf4d8b83c18be207eb +md5: c7c83eecbb72d88b940c249af56c8b17 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- xz 5.8.2.* +license: 0BSD +size: 113207 +timestamp: 1768752626120 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda +sha256: fe171ed5cf5959993d43ff72de7596e8ac2853e9021dec0344e583734f1e0843 +md5: 2c21e66f50753a083cbe6b80f38268fa +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: BSD-2-Clause +license_family: BSD +size: 92400 +timestamp: 1769482286018 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda +sha256: 199d79c237afb0d4780ccd2fbf829cea80743df60df4705202558675e07dd2c5 +md5: be43915efc66345cccb3c310b6ed0374 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libgfortran +- libgfortran5 >=14.3.0 +constrains: +- openblas >=0.3.30,<0.3.31.0a0 +license: BSD-3-Clause +license_family: BSD +size: 5927939 +timestamp: 1763114673331 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.55-h421ea60_0.conda +sha256: 36ade759122cdf0f16e2a2562a19746d96cf9c863ffaa812f2f5071ebbe9c03c +md5: 5f13ffc7d30ffec87864e678df9957b4 +depends: +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- libzlib >=1.3.1,<2.0a0 +license: zlib-acknowledgement +size: 317669 +timestamp: 1770691470744 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda +sha256: d716847b7deca293d2e49ed1c8ab9e4b9e04b9d780aea49a97c26925b28a7993 +md5: fd893f6a3002a635b5e50ceb9dd2c0f4 +depends: +- __glibc >=2.17,<3.0.a0 +- icu >=78.2,<79.0a0 +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +license: blessing +size: 951405 +timestamp: 1772818874251 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda +sha256: 78668020064fdaa27e9ab65cd2997e2c837b564ab26ce3bf0e58a2ce1a525c6e +md5: 1b08cd684f34175e4514474793d44bcb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc 15.2.0 he0feb66_18 +constrains: +- libstdcxx-ng ==15.2.0=*_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 5852330 +timestamp: 1771378262446 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda +sha256: e5f8c38625aa6d567809733ae04bb71c161a42e44a9fa8227abe61fa5c60ebe0 +md5: cd5a90476766d53e901500df9215e927 +depends: +- __glibc >=2.17,<3.0.a0 +- lerc >=4.0.0,<5.0a0 +- libdeflate >=1.25,<1.26.0a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.0,<4.0a0 +- liblzma >=5.8.1,<6.0a0 +- libstdcxx >=14 +- libwebp-base >=1.6.0,<2.0a0 +- libzlib >=1.3.1,<2.0a0 +- zstd >=1.5.7,<1.6.0a0 +license: HPND +size: 435273 +timestamp: 1762022005702 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda +sha256: 1a7539cfa7df00714e8943e18de0b06cceef6778e420a5ee3a2a145773758aee +md5: db409b7c1720428638e7c0d509d3e1b5 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: BSD-3-Clause +license_family: BSD +size: 40311 +timestamp: 1766271528534 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda +sha256: 3aed21ab28eddffdaf7f804f49be7a7d701e8f0e46c856d801270b470820a37b +md5: aea31d2e5b1091feca96fcfe945c3cf9 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- libwebp 1.6.0 +license: BSD-3-Clause +license_family: BSD +size: 429011 +timestamp: 1752159441324 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda +sha256: 666c0c431b23c6cec6e492840b176dde533d48b7e6fb8883f5071223433776aa +md5: 92ed62436b625154323d40d5f2f11dd7 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- pthread-stubs +- xorg-libxau >=1.0.11,<2.0a0 +- xorg-libxdmcp +license: MIT +license_family: MIT +size: 395888 +timestamp: 1727278577118 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda +sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9 +md5: d87ff7921124eccd67248aa483c23fec +depends: +- __glibc >=2.17,<3.0.a0 +constrains: +- zlib 1.3.2 *_2 +license: Zlib +license_family: Other +size: 63629 +timestamp: 1774072609062 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +sha256: 20e0892592a3e7c683e3d66df704a9425d731486a97c34fc56af4da1106b2b6b +md5: ba0a9221ce1063f31692c07370d062f3 +depends: +- importlib-metadata >=4.4 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 85893 +timestamp: 1770694658918 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda +sha256: 7b1da4b5c40385791dbc3cc85ceea9fad5da680a27d5d3cb8bfaa185e304a89e +md5: 5b5203189eb668f042ac2b0826244964 +depends: +- mdurl >=0.1,<1 +- python >=3.10 +license: MIT +license_family: MIT +size: 64736 +timestamp: 1754951288511 +- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py314h67df5f8_1.conda +sha256: c279be85b59a62d5c52f5dd9a4cd43ebd08933809a8416c22c3131595607d4cf +md5: 9a17c4307d23318476d7fbf0fedc0cde +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +constrains: +- jinja2 >=3.0.0 +license: BSD-3-Clause +license_family: BSD +size: 27424 +timestamp: 1772445227915 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mathjax-2.7.7-ha770c72_3.tar.bz2 +sha256: 02fef69bde69db264a12f21386612262f545b6e3e68d8f1ccec19f3eaae58edf +md5: 86e69bd82c2a2c6fd29f5ab7e02b3691 +license: Apache-2.0 +license_family: Apache +size: 22281629 +timestamp: 1662784498331 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +sha256: 78c1bbe1723449c52b7a9df1af2ee5f005209f67e40b6e1d3c7619127c43b1c7 +md5: 592132998493b3ff25fd7479396e8351 +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 14465 +timestamp: 1733255681319 +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.33-pyhdfd78af_0.conda +sha256: f005760b13093362fc9c997d603dd487de32ab2e821a3cbce52a42bcb8136517 +md5: 698a8a27c2b9d8a542c70cb47099a75e +depends: +- click +- coloredlogs +- humanize +- importlib-metadata +- jinja2 >=3.0.0 +- jsonschema +- markdown +- natsort +- numpy +- packaging +- pillow >=10.2.0 +- plotly >=5.18 +- polars-lts-cpu +- pyaml-env +- pydantic >=2.7.1 +- python >=3.8,!=3.14.1 +- python-dotenv +- python-kaleido 0.2.1 +- pyyaml >=4 +- requests +- rich >=10 +- rich-click +- spectra >=0.0.10 +- tiktoken +- tqdm +- typeguard +license: GPL-3.0-or-later +license_family: GPL3 +size: 4198799 +timestamp: 1765300743879 +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.18.1-pyhcf101f3_1.conda +sha256: 541fd4390a0687228b8578247f1536a821d9261389a65585af9d1a6f2a14e1e0 +md5: 30bec5e8f4c3969e2b1bd407c5e52afb +depends: +- python >=3.10 +- python +license: MIT +size: 280459 +timestamp: 1774380620329 +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +sha256: aeb1548eb72e4f198e72f19d242fb695b35add2ac7b2c00e0d83687052867680 +md5: e941e85e273121222580723010bd4fa2 +depends: +- python >=3.9 +- python +license: MIT +license_family: MIT +size: 39262 +timestamp: 1770905275632 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda +sha256: 3fde293232fa3fca98635e1167de6b7c7fda83caf24b9d6c91ec9eefb4f4d586 +md5: 47e340acb35de30501a76c7c799c41d7 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +license: X11 AND BSD-3-Clause +size: 891641 +timestamp: 1738195959188 +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +sha256: f6a82172afc50e54741f6f84527ef10424326611503c64e359e25a19a8e4c1c6 +md5: a2c1eeadae7a309daed9d62c96012a2b +depends: +- python >=3.11 +- python +constrains: +- numpy >=1.25 +- scipy >=1.11.2 +- matplotlib-base >=3.8 +- pandas >=2.0 +license: BSD-3-Clause +license_family: BSD +size: 1587439 +timestamp: 1765215107045 +- conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda +sha256: e3664264bd936c357523b55c71ed5a30263c6ba278d726a75b1eb112e6fb0b64 +md5: e235d5566c9cc8970eb2798dd4ecf62f +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: MPL-2.0 +license_family: MOZILLA +size: 228588 +timestamp: 1762348634537 +- conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda +sha256: 44dd98ffeac859d84a6dcba79a2096193a42fc10b29b28a5115687a680dd6aea +md5: 567fbeed956c200c1db5782a424e58ee +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libsqlite >=3.51.0,<4.0a0 +- libstdcxx >=14 +- libzlib >=1.3.1,<2.0a0 +- nspr >=4.38,<5.0a0 +license: MPL-2.0 +license_family: MOZILLA +size: 2057773 +timestamp: 1763485556350 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.3-py314h2b28147_0.conda +sha256: f2ba8cb0d86a6461a6bcf0d315c80c7076083f72c6733c9290086640723f79ec +md5: 36f5b7eb328bdc204954a2225cf908e2 +depends: +- python +- libstdcxx >=14 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.14.* *_cp314 +- libcblas >=3.9.0,<4.0a0 +- liblapack >=3.9.0,<4.0a0 +- libblas >=3.9.0,<4.0a0 +constrains: +- numpy-base <0a0 +license: BSD-3-Clause +license_family: BSD +size: 8927860 +timestamp: 1773839233468 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda +sha256: 3900f9f2dbbf4129cf3ad6acf4e4b6f7101390b53843591c53b00f034343bc4d +md5: 11b3379b191f63139e29c0d19dee24cd +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libpng >=1.6.50,<1.7.0a0 +- libstdcxx >=14 +- libtiff >=4.7.1,<4.8.0a0 +- libzlib >=1.3.1,<2.0a0 +license: BSD-2-Clause +license_family: BSD +size: 355400 +timestamp: 1758489294972 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda +sha256: 44c877f8af015332a5d12f5ff0fb20ca32f896526a7d0cdb30c769df1144fb5c +md5: f61eb8cd60ff9057122a3d338b99c00f +depends: +- __glibc >=2.17,<3.0.a0 +- ca-certificates +- libgcc >=14 +license: Apache-2.0 +license_family: Apache +size: 3164551 +timestamp: 1769555830639 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda +sha256: c1fc0f953048f743385d31c468b4a678b3ad20caffdeaa94bed85ba63049fd58 +md5: b76541e68fea4d511b1ac46a28dcd2c6 +depends: +- python >=3.8 +- python +license: Apache-2.0 +license_family: APACHE +size: 72010 +timestamp: 1769093650580 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.1.1-py314h8ec4b1a_0.conda +sha256: 9e6ec8f3213e8b7d64b0ad45f84c51a2c9eba4398efda31e196c9a56186133ee +md5: 79678378ae235e24b3aa83cee1b38207 +depends: +- python +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- libwebp-base >=1.6.0,<2.0a0 +- zlib-ng >=2.3.3,<2.4.0a0 +- python_abi 3.14.* *_cp314 +- tk >=8.6.13,<8.7.0a0 +- libjpeg-turbo >=3.1.2,<4.0a0 +- libxcb >=1.17.0,<2.0a0 +- openjpeg >=2.5.4,<3.0a0 +- lcms2 >=2.18,<3.0a0 +- libtiff >=4.7.1,<4.8.0a0 +- libfreetype >=2.14.1 +- libfreetype6 >=2.14.1 +license: HPND +size: 1073026 +timestamp: 1770794002408 +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +sha256: c418d325359fc7a0074cea7f081ef1bce26e114d2da8a0154c5d27ecc87a08e7 +md5: 3e9427ee186846052e81fadde8ebe96a +depends: +- narwhals >=1.15.1 +- packaging +- python >=3.10 +constrains: +- ipywidgets >=7.6 +license: MIT +license_family: MIT +size: 5251872 +timestamp: 1772628857717 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.39.3-pyh58ad624_1.conda +sha256: d332c2d5002fc440ae37ed9679ffc21b552f18d20232390005d1dd3bce0888d3 +md5: d5a4e013a30dd8dfde9ab39f45aaf9c1 +depends: +- polars-runtime-32 ==1.39.3 +- python >=3.10 +- python +constrains: +- numpy >=1.16.0 +- pyarrow >=7.0.0 +- fastexcel >=0.9 +- openpyxl >=3.0.0 +- xlsx2csv >=0.8.0 +- connectorx >=0.3.2 +- deltalake >=1.0.0 +- pyiceberg >=0.7.1 +- altair >=5.4.0 +- great_tables >=0.8.0 +- polars-runtime-32 ==1.39.3 +- polars-runtime-64 ==1.39.3 +- polars-runtime-compat ==1.39.3 +license: MIT +license_family: MIT +size: 533495 +timestamp: 1774207987966 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-lts-cpu-1.34.0.deprecated-hc364b38_0.conda +sha256: e466fb31f67ba9bde18deafeb34263ca5eb25807f39ead0e9d753a8e82c4c4f4 +md5: ef0340e75068ac8ff96462749b5c98e7 +depends: +- polars >=1.34.0 +- polars-runtime-compat >=1.34.0 +license: MIT +license_family: MIT +size: 3902 +timestamp: 1760206808444 +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.39.3-py310hffdcd12_1.conda +noarch: python +sha256: 9744f8086bb0832998f5b01076f57ddc9efbe460e493b14303c3567dc4f401e7 +md5: f9327f9f2cfc4215f55b613e64afd3ba +depends: +- python +- libstdcxx >=14 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 37570276 +timestamp: 1774207987966 +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-compat-1.39.3-py310hbcd5346_1.conda +noarch: python +sha256: bf0b932713f0f27924f42159c98426e0073bb6145ed796eaa4cec79ca05363c7 +md5: 4b9b312453eebd6fbdbbe2a88fa1b5c4 +depends: +- python +- libgcc >=14 +- libstdcxx >=14 +- __glibc >=2.17,<3.0.a0 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 37224264 +timestamp: 1774207985377 +- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda +sha256: 4ce2e1ee31a6217998f78c31ce7dc0a3e0557d9238b51d49dd20c52d467a126d +md5: f2c23a77b25efcad57d377b34bd84941 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-2.0-or-later AND LGPL-2.0-or-later +license_family: GPL +size: 593603 +timestamp: 1769710381284 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda +sha256: 9c88f8c64590e9567c6c80823f0328e58d3b1efb0e1c539c0315ceca764e0973 +md5: b3c17d95b5a10c6e64a21fa17573e70e +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +license: MIT +license_family: MIT +size: 8252 +timestamp: 1726802366959 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +sha256: 58994e0d2ea8584cb399546e6f6896d771995e6121d1a7b6a2c9948388358932 +md5: e17be1016bcc3516827b836cd3e4d9dc +depends: +- python >=3.9 +- pyyaml >=5.0,<=7.0 +license: MIT +license_family: MIT +size: 14645 +timestamp: 1736766960536 +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda +sha256: 868569d9505b7fe246c880c11e2c44924d7613a8cdcc1f6ef85d5375e892f13d +md5: c3946ed24acdb28db1b5d63321dbca7d +depends: +- typing-inspection >=0.4.2 +- typing_extensions >=4.14.1 +- python >=3.10 +- typing-extensions >=4.6.1 +- annotated-types >=0.6.0 +- pydantic-core ==2.41.5 +- python +license: MIT +license_family: MIT +size: 340482 +timestamp: 1764434463101 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py314h2e6c369_1.conda +sha256: 7e0ae379796e28a429f8e48f2fe22a0f232979d65ec455e91f8dac689247d39f +md5: 432b0716a1dfac69b86aa38fdd59b7e6 +depends: +- python +- typing-extensions >=4.6.0,!=4.7.0 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 1943088 +timestamp: 1762988995556 +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda +sha256: 5577623b9f6685ece2697c6eb7511b4c9ac5fb607c9babc2646c811b428fd46a +md5: 6b6ece66ebcae2d5f326c77ef2c5a066 +depends: +- python >=3.9 +license: BSD-2-Clause +license_family: BSD +size: 889287 +timestamp: 1750615908735 +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8 +md5: 461219d1a5bd61342293efa2c0c90eac +depends: +- __unix +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 21085 +timestamp: 1733217331982 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.3-h32b2ec7_101_cp314.conda +build_number: 101 +sha256: cb0628c5f1732f889f53a877484da98f5a0e0f47326622671396fb4f2b0cd6bd +md5: c014ad06e60441661737121d3eae8a60 +depends: +- __glibc >=2.17,<3.0.a0 +- bzip2 >=1.0.8,<2.0a0 +- ld_impl_linux-64 >=2.36.1 +- libexpat >=2.7.3,<3.0a0 +- libffi >=3.5.2,<3.6.0a0 +- libgcc >=14 +- liblzma >=5.8.2,<6.0a0 +- libmpdec >=4.0.0,<5.0a0 +- libsqlite >=3.51.2,<4.0a0 +- libuuid >=2.41.3,<3.0a0 +- libzlib >=1.3.1,<2.0a0 +- ncurses >=6.5,<7.0a0 +- openssl >=3.5.5,<4.0a0 +- python_abi 3.14.* *_cp314 +- readline >=8.3,<9.0a0 +- tk >=8.6.13,<8.7.0a0 +- tzdata +- zstd >=1.5.7,<1.6.0a0 +license: Python-2.0 +size: 36702440 +timestamp: 1770675584356 +python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +sha256: 74e417a768f59f02a242c25e7db0aa796627b5bc8c818863b57786072aeb85e5 +md5: 130584ad9f3a513cdd71b1fdc1244e9c +depends: +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 27848 +timestamp: 1772388605021 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda +sha256: 233aebd94c704ac112afefbb29cf4170b7bc606e22958906f2672081bc50638a +md5: 235765e4ea0d0301c75965985163b5a1 +depends: +- cpython 3.14.3.* +- python_abi * *_cp314 +license: Python-2.0 +size: 50062 +timestamp: 1770674497152 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +sha256: e17bf63a30aec33432f1ead86e15e9febde9fc40a7f869c0e766be8d2db44170 +md5: 310259a5b03ff02289d7705f39e2b1d2 +depends: +- kaleido-core 0.2.1.* +- python >=3.5 +license: MIT +license_family: MIT +size: 18320 +timestamp: 1615204747600 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +build_number: 8 +sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 +md5: 0539938c55b6b1a59b560e843ad864a4 +constrains: +- python 3.14.* *_cp314 +license: BSD-3-Clause +license_family: BSD +size: 6989 +timestamp: 1752805904792 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda +sha256: b318fb070c7a1f89980ef124b80a0b5ccf3928143708a85e0053cde0169c699d +md5: 2035f68f96be30dc60a5dfd7452c7941 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +- yaml >=0.2.5,<0.3.0a0 +license: MIT +license_family: MIT +size: 202391 +timestamp: 1770223462836 +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda +sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002 +md5: d7d95fc8287ea7bf33e0e7116d2b95ec +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-3.0-only +license_family: GPL +size: 345073 +timestamp: 1765813471974 +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +sha256: 0577eedfb347ff94d0f2fa6c052c502989b028216996b45c7f21236f25864414 +md5: 870293df500ca7e18bedefa5838a22ab +depends: +- attrs >=22.2.0 +- python >=3.10 +- rpds-py >=0.7.0 +- typing_extensions >=4.4.0 +- python +license: MIT +license_family: MIT +size: 51788 +timestamp: 1760379115194 +- conda: https://conda.anaconda.org/conda-forge/linux-64/regex-2026.2.28-py314h5bd0f2a_0.conda +sha256: e085e336f1446f5263a3ec9747df8c719b6996753901181add50dc4fdd8bb2e8 +md5: 3c8b6a8c4d0ff5a264e9831eac4941f4 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +license: Apache-2.0 AND CNRI-Python +license_family: PSF +size: 411924 +timestamp: 1772255161535 +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda +sha256: 7813c38b79ae549504b2c57b3f33394cea4f2ad083f0994d2045c2e24cb538c5 +md5: c65df89a0b2e321045a9e01d1337b182 +depends: +- python >=3.10 +- certifi >=2017.4.17 +- charset-normalizer >=2,<4 +- idna >=2.5,<4 +- urllib3 >=1.21.1,<3 +- python +constrains: +- chardet >=3.0.2,<6 +license: Apache-2.0 +license_family: APACHE +size: 63602 +timestamp: 1766926974520 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda +sha256: b06ce84d6a10c266811a7d3adbfa1c11f13393b91cc6f8a5b468277d90be9590 +md5: 7a6289c50631d620652f5045a63eb573 +depends: +- markdown-it-py >=2.2.0 +- pygments >=2.13.0,<3.0.0 +- python >=3.10 +- typing_extensions >=4.0.0,<5.0.0 +- python +license: MIT +license_family: MIT +size: 208472 +timestamp: 1771572730357 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +sha256: aa3fcb167321bae51998de2e94d199109c9024f25a5a063cb1c28d8f1af33436 +md5: 0c20a8ebcddb24a45da89d5e917e6cb9 +depends: +- python >=3.10 +- rich >=12 +- click >=8 +- typing-extensions >=4 +- __unix +- python +license: MIT +license_family: MIT +size: 64356 +timestamp: 1769850479089 +- conda: https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py314h2e6c369_0.conda +sha256: e53b0cbf3b324eaa03ca1fe1a688fdf4ab42cea9c25270b0a7307d8aaaa4f446 +md5: c1c368b5437b0d1a68f372ccf01cb133 +depends: +- python +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 376121 +timestamp: 1764543122774 +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +sha256: 7c65782d2511738e62c70462e89d65da4fa54d5a7e47c46667bcd27a59f81876 +md5: 472239e4eb7b5a84bb96b3ed7e3a596a +depends: +- colormath >=3.0.0 +- python >=3.9 +license: MIT +license_family: MIT +size: 22284 +timestamp: 1735770589188 +- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda +sha256: c9af81e7830d9c4b67a7f48e512d060df2676b29cac59e3b31f09dbfcee29c58 +md5: 7d9d7efe9541d4bb71b5934e8ee348ea +depends: +- __glibc >=2.17,<3.0.a0 +- icu >=78.2,<79.0a0 +- libgcc >=14 +- libsqlite 3.52.0 hf4e2dac_0 +- libzlib >=1.3.1,<2.0a0 +- ncurses >=6.5,<7.0a0 +- readline >=8.3,<9.0a0 +license: blessing +size: 203641 +timestamp: 1772818888368 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tiktoken-0.12.0-py314h67fec18_3.conda +sha256: 7e395d67fd249d901beb1ae269057763c0d8c3ee5f7a348694bdb16d158a37d9 +md5: d705f9d8a1185a2b01cced191177a028 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +- regex >=2022.1.18 +- requests >=2.26.0 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 939648 +timestamp: 1764028306357 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda +sha256: cafeec44494f842ffeca27e9c8b0c27ed714f93ac77ddadc6aaf726b5554ebac +md5: cffd3bdd58090148f4cfcd831f4b26ab +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +constrains: +- xorg-libx11 >=1.8.12,<2.0a0 +license: TCL +license_family: BSD +size: 3301196 +timestamp: 1769460227866 +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +sha256: 9ef8e47cf00e4d6dcc114eb32a1504cc18206300572ef14d76634ba29dfe1eb6 +md5: e5ce43272193b38c2e9037446c1d9206 +depends: +- python >=3.10 +- __unix +- python +license: MPL-2.0 and MIT +size: 94132 +timestamp: 1770153424136 +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.1-pyhd8ed1ab_0.conda +sha256: 39d8ae33c43cdb8f771373e149b0b4fae5a08960ac58dcca95b2f1642bb17448 +md5: 260af1b0a94f719de76b4e14094e9a3b +depends: +- importlib-metadata >=3.6 +- python >=3.10 +- typing-extensions >=4.10.0 +- typing_extensions >=4.14.0 +constrains: +- pytest >=7 +license: MIT +license_family: MIT +size: 36838 +timestamp: 1771532971545 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c +md5: edd329d7d3a4ab45dcf905899a7a6115 +depends: +- typing_extensions ==4.15.0 pyhcf101f3_0 +license: PSF-2.0 +license_family: PSF +size: 91383 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda +sha256: 70db27de58a97aeb7ba7448366c9853f91b21137492e0b4430251a1870aa8ff4 +md5: a0a4a3035667fc34f29bfbd5c190baa6 +depends: +- python >=3.10 +- typing_extensions >=4.12.0 +license: MIT +license_family: MIT +size: 18923 +timestamp: 1764158430324 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 +md5: 0caa1af407ecff61170c9437a808404d +depends: +- python >=3.10 +- python +license: PSF-2.0 +license_family: PSF +size: 51692 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c +md5: ad659d0a2b3e47e38d829aa8cad2d610 +license: LicenseRef-Public-Domain +size: 119135 +timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda +sha256: af641ca7ab0c64525a96fd9ad3081b0f5bcf5d1cbb091afb3f6ed5a9eee6111a +md5: 9272daa869e03efe68833e3dc7a02130 +depends: +- backports.zstd >=1.0.0 +- brotli-python >=1.2.0 +- h2 >=4,<5 +- pysocks >=1.5.6,<2.0,!=1.5.7 +- python >=3.10 +license: MIT +license_family: MIT +size: 103172 +timestamp: 1767817860341 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda +sha256: 6bc6ab7a90a5d8ac94c7e300cc10beb0500eeba4b99822768ca2f2ef356f731b +md5: b2895afaf55bf96a8c8282a2e47a5de0 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 15321 +timestamp: 1762976464266 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda +sha256: 25d255fb2eef929d21ff660a0c687d38a6d2ccfbcbf0cc6aa738b12af6e9d142 +md5: 1dafce8548e38671bea82e3f5c6ce22f +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 20591 +timestamp: 1762976546182 +- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda +sha256: 6d9ea2f731e284e9316d95fa61869fe7bbba33df7929f82693c121022810f4ad +md5: a77f85f77be52ff59391544bfe73390a +depends: +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +license: MIT +license_family: MIT +size: 85189 +timestamp: 1753484064210 +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda +sha256: b4533f7d9efc976511a73ef7d4a2473406d7f4c750884be8e8620b0ce70f4dae +md5: 30cd29cb87d819caead4d55184c1d115 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 24194 +timestamp: 1764460141901 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda +sha256: ea4e50c465d70236408cb0bfe0115609fd14db1adcd8bd30d8918e0291f8a75f +md5: 2aadb0d17215603a82a2a6b0afd9a4cb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: Zlib +license_family: Other +size: 122618 +timestamp: 1770167931827 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda +sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7 +md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829 +depends: +- __glibc >=2.17,<3.0.a0 +- libzlib >=1.3.1,<2.0a0 +license: BSD-3-Clause +license_family: BSD +size: 601375 +timestamp: 1764777111296 diff --git a/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-40bf3b435e89dc22_1.txt b/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-40bf3b435e89dc22_1.txt new file mode 100644 index 00000000..a58231a0 --- /dev/null +++ b/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-40bf3b435e89dc22_1.txt @@ -0,0 +1,1502 @@ + +version: 6 +environments: +default: +channels: +- url: https://conda.anaconda.org/conda-forge/ +- url: https://conda.anaconda.org/bioconda/ +- url: https://conda.anaconda.org/bioconda/ +options: +pypi-prerelease-mode: if-necessary-or-explicit +packages: +linux-aarch64: +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.7.4-hfae3067_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.17.1-hba86a56_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/kaleido-core-0.2.1-he5a581e_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.18-h9d5b58d_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-5_haddc8a3_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-5_hd72aa62_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.2-he30d5cf_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-5_h88aeb00_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.30-pthreads_h9d3fd7e_4.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.55-h1abf092_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.3-py314hb76de3f_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/mathjax-2.7.7-h8af1aa0_3.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.33-pyhdfd78af_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.18.1-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nspr-4.38-h3ad9384_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nss-3.118-h544fa81_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.3-py314haac167e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.4-h5da879a_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-12.1.1-py314hac3e5ec_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.39.3-pyh58ad624_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-lts-cpu-1.34.0.deprecated-hc364b38_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-32-1.39.3-py310hff09b76_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-compat-1.39.3-py310hf00a4a2_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pydantic-core-2.41.5-py314h451b6cc_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.3-hb06a95a_101_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/regex-2026.2.28-py314h51f160d_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rpds-py-0.30.0-py314h02b7a91_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/sqlite-3.52.0-hf1c7be2_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tiktoken-0.12.0-py314h6a36e60_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.1-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-ng-2.3.3-ha7cb516_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda +packages: +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda +build_number: 20 +sha256: a2527b1d81792a0ccd2c05850960df119c2b6d8f5fdec97f2db7d25dc23b1068 +md5: 468fd3bb9e1f671d36c2cbc677e56f1d +depends: +- libgomp >=7.5.0 +constrains: +- openmp_impl <0.0a0 +license: BSD-3-Clause +license_family: BSD +size: 28926 +timestamp: 1770939656741 +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +sha256: a3967b937b9abf0f2a99f3173fa4630293979bd1644709d89580e7c62a544661 +md5: aaa2a381ccc56eac91d63b6c1240312f +depends: +- cpython +- python-gil +license: MIT +license_family: MIT +size: 8191 +timestamp: 1744137672556 +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +sha256: e0ea1ba78fbb64f17062601edda82097fcf815012cf52bb704150a2668110d48 +md5: 2934f256a8acfe48f6ebb4fce6cde29c +depends: +- python >=3.9 +- typing-extensions >=4.0.0 +license: MIT +license_family: MIT +size: 18074 +timestamp: 1733247158254 +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +sha256: 1b6124230bb4e571b1b9401537ecff575b7b109cc3a21ee019f65e083b8399ab +md5: c6b0543676ecb1fb2d7643941fe375f2 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 64927 +timestamp: 1773935801332 +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda +noarch: generic +sha256: c31ab719d256bc6f89926131e88ecd0f0c5d003fe8481852c6424f4ec6c7eb29 +md5: a2ac7763a9ac75055b68f325d3255265 +depends: +- python >=3.14 +license: BSD-3-Clause AND MIT AND EPL-2.0 +size: 7514 +timestamp: 1767044983590 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda +sha256: 5a5b0cdcd7ed89c6a8fb830924967f6314a2b71944bc1ebc2c105781ba97aa75 +md5: a1b5c571a0923a205d663d8678df4792 +depends: +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python >=3.14,<3.15.0a0 *_cp314 +- python_abi 3.14.* *_cp314 +constrains: +- libbrotlicommon 1.2.0 he30d5cf_1 +license: MIT +license_family: MIT +size: 373193 +timestamp: 1764017486851 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda +sha256: b3495077889dde6bb370938e7db82be545c73e8589696ad0843a32221520ad4c +md5: 840d8fc0d7b3209be93080bc20e07f2d +depends: +- libgcc >=14 +license: bzip2-1.0.6 +license_family: BSD +size: 192412 +timestamp: 1771350241232 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda +sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc +md5: 4492fd26db29495f0ba23f146cd5638d +depends: +- __unix +license: ISC +size: 147413 +timestamp: 1772006283803 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda +sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 +md5: 765c4d97e877cdbbb88ff33152b86125 +depends: +- python >=3.10 +license: ISC +size: 151445 +timestamp: 1772001170301 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda +sha256: d86dfd428b2e3c364fa90e07437c8405d635aa4ef54b25ab51d9c712be4112a5 +md5: 49ee13eb9b8f44d63879c69b8a40a74b +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 58510 +timestamp: 1773660086450 +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda +sha256: 38cfe1ee75b21a8361c8824f5544c3866f303af1762693a178266d7f198e8715 +md5: ea8a6c3256897cc31263de9f455e25d9 +depends: +- python >=3.10 +- __unix +- python +license: BSD-3-Clause +license_family: BSD +size: 97676 +timestamp: 1764518652276 +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +sha256: 8021c76eeadbdd5784b881b165242db9449783e12ce26d6234060026fd6a8680 +md5: b866ff7007b934d564961066c8195983 +depends: +- humanfriendly >=9.1 +- python >=3.9 +license: MIT +license_family: MIT +size: 43758 +timestamp: 1733928076798 +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +sha256: 59c9e29800b483b390467f90e82b0da3a4fbf0612efe1c90813fca232780e160 +md5: 071cf7b0ce333c81718b054066c15102 +depends: +- networkx >=2.0 +- numpy +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 39326 +timestamp: 1735759976140 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda +noarch: generic +sha256: 91b06300879df746214f7363d6c27c2489c80732e46a369eb2afc234bcafb44c +md5: 3bb89e4f795e5414addaa531d6b1500a +depends: +- python >=3.14,<3.15.0a0 +- python_abi * *_cp314 +license: Python-2.0 +size: 50078 +timestamp: 1770674447292 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.7.4-hfae3067_0.conda +sha256: 5f087bef054c681edcaae84a8c2230585b938691e371ff92957a30707b7fcdf7 +md5: b304307db639831ad7caabd2eac6fca6 +depends: +- libexpat 2.7.4 hfae3067_0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 137701 +timestamp: 1771259543650 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b +md5: 0c96522c6bdaed4b1566d11387caaf45 +license: BSD-3-Clause +license_family: BSD +size: 397370 +timestamp: 1566932522327 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c +md5: 34893075a5c9e55cdafac56607368fc6 +license: OFL-1.1 +license_family: Other +size: 96530 +timestamp: 1620479909603 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139 +md5: 4d59c254e01d9cde7957100457e2d5fb +license: OFL-1.1 +license_family: Other +size: 700814 +timestamp: 1620479612257 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14 +md5: 49023d73832ef61042f6a237cb2687e7 +license: LicenseRef-Ubuntu-Font-Licence-Version-1.0 +license_family: Other +size: 1620504 +timestamp: 1727511233259 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.17.1-hba86a56_0.conda +sha256: 835aff8615dd8d8fff377679710ce81b8a2c47b6404e21a92fb349fda193a15c +md5: 0fed1ff55f4938a65907f3ecf62609db +depends: +- libexpat >=2.7.4,<3.0a0 +- libfreetype >=2.14.1 +- libfreetype6 >=2.14.1 +- libgcc >=14 +- libuuid >=2.41.3,<3.0a0 +- libzlib >=1.3.1,<2.0a0 +license: MIT +license_family: MIT +size: 279044 +timestamp: 1771382728182 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333 +md5: a7970cd949a077b7cb9696379d338681 +depends: +- font-ttf-ubuntu +- font-ttf-inconsolata +- font-ttf-dejavu-sans-mono +- font-ttf-source-code-pro +license: BSD-3-Clause +license_family: BSD +size: 4059 +timestamp: 1762351264405 +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +sha256: 84c64443368f84b600bfecc529a1194a3b14c3656ee2e832d15a20e0329b6da3 +md5: 164fc43f0b53b6e3a7bc7dce5e4f1dc9 +depends: +- python >=3.10 +- hyperframe >=6.1,<7 +- hpack >=4.1,<5 +- python +license: MIT +license_family: MIT +size: 95967 +timestamp: 1756364871835 +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba +md5: 0a802cb9888dd14eeefc611f05c40b6e +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 30731 +timestamp: 1737618390337 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +sha256: fa2071da7fab758c669e78227e6094f6b3608228740808a6de5d6bce83d9e52d +md5: 7fe569c10905402ed47024fc481bb371 +depends: +- __unix +- python >=3.9 +license: MIT +license_family: MIT +size: 73563 +timestamp: 1733928021866 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +sha256: 6c4343b376d0b12a4c75ab992640970d36c933cad1fd924f6a1181fa91710e80 +md5: daddf757c3ecd6067b9af1df1f25d89e +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 67994 +timestamp: 1766267728652 +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +sha256: 77af6f5fe8b62ca07d09ac60127a30d9069fdc3c68d6b256754d0ffb1f7779f8 +md5: 8e6923fc12f1fe8f8c4e5c9f343256ac +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 17397 +timestamp: 1737618427549 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_0.conda +sha256: 49ba6aed2c6b482bb0ba41078057555d29764299bc947b990708617712ef6406 +md5: 546da38c2fa9efacf203e2ad3f987c59 +depends: +- libgcc >=14 +- libstdcxx >=14 +license: MIT +license_family: MIT +size: 12837286 +timestamp: 1773822650615 +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda +sha256: ae89d0299ada2a3162c2614a9d26557a92aa6a77120ce142f8e0109bbf0342b0 +md5: 53abe63df7e10a6ba605dc5f9f961d36 +depends: +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 50721 +timestamp: 1760286526795 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda +sha256: 82ab2a0d91ca1e7e63ab6a4939356667ef683905dea631bc2121aa534d347b16 +md5: 080594bf4493e6bae2607e65390c520a +depends: +- python >=3.10 +- zipp >=3.20 +- python +license: Apache-2.0 +license_family: APACHE +size: 34387 +timestamp: 1773931568510 +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +sha256: fc9ca7348a4f25fed2079f2153ecdcf5f9cf2a0bc36c4172420ca09e1849df7b +md5: 04558c96691bed63104678757beb4f8d +depends: +- markupsafe >=2.0 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 120685 +timestamp: 1764517220861 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +sha256: db973a37d75db8e19b5f44bbbdaead0c68dde745407f281e2a7fe4db74ec51d7 +md5: ada41c863af263cc4c5fcbaff7c3e4dc +depends: +- attrs >=22.2.0 +- jsonschema-specifications >=2023.3.6 +- python >=3.10 +- referencing >=0.28.4 +- rpds-py >=0.25.0 +- python +license: MIT +license_family: MIT +size: 82356 +timestamp: 1767839954256 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +sha256: 0a4f3b132f0faca10c89fdf3b60e15abb62ded6fa80aebfc007d05965192aa04 +md5: 439cd0f567d697b20a8f45cb70a1005a +depends: +- python >=3.10 +- referencing >=0.31.0 +- python +license: MIT +license_family: MIT +size: 19236 +timestamp: 1757335715225 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/kaleido-core-0.2.1-he5a581e_0.tar.bz2 +sha256: d3c7f4797566e6f983d16c2a87063a18e4b2d819a66230190a21584d70042755 +md5: 4f0d284f5d11e04277b552eb1c172c7f +depends: +- __glibc >=2.17,<3.0.a0 +- expat >=2.2.10,<3.0.0a0 +- fontconfig +- fonts-conda-forge +- libgcc-ng >=9.3.0 +- mathjax 2.7.* +- nspr >=4.29,<5.0a0 +- nss >=3.62,<4.0a0 +- sqlite >=3.34.0,<4.0a0 +license: MIT +license_family: MIT +size: 65750397 +timestamp: 1615199465742 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.18-h9d5b58d_0.conda +sha256: 379ef5e91a587137391a6149755d0e929f1a007d2dcb211318ac670a46c8596f +md5: bb960f01525b5e001608afef9d47b79c +depends: +- libgcc >=14 +- libjpeg-turbo >=3.1.2,<4.0a0 +- libtiff >=4.7.1,<4.8.0a0 +license: MIT +license_family: MIT +size: 293039 +timestamp: 1768184778398 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda +sha256: 7abd913d81a9bf00abb699e8987966baa2065f5132e37e815f92d90fc6bba530 +md5: a21644fc4a83da26452a718dc9468d5f +depends: +- zstd >=1.5.7,<1.6.0a0 +constrains: +- binutils_impl_linux-aarch64 2.45.1 +license: GPL-3.0-only +license_family: GPL +size: 875596 +timestamp: 1774197520746 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda +sha256: 8957fd460c1c132c8031f65fd5f56ec3807fd71b7cab2c5e2b0937b13404ab36 +md5: d13423b06447113a90b5b1366d4da171 +depends: +- libgcc >=14 +- libstdcxx >=14 +license: Apache-2.0 +license_family: Apache +size: 240444 +timestamp: 1773114901155 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-5_haddc8a3_openblas.conda +build_number: 5 +sha256: 700f3c03d0fba8e687a345404a45fbabe781c1cf92242382f62cef2948745ec4 +md5: 5afcea37a46f76ec1322943b3c4dfdc0 +depends: +- libopenblas >=0.3.30,<0.3.31.0a0 +- libopenblas >=0.3.30,<1.0a0 +constrains: +- mkl <2026 +- libcblas 3.11.0 5*_openblas +- liblapack 3.11.0 5*_openblas +- liblapacke 3.11.0 5*_openblas +- blas 2.305 openblas +license: BSD-3-Clause +license_family: BSD +size: 18369 +timestamp: 1765818610617 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-5_hd72aa62_openblas.conda +build_number: 5 +sha256: 3fad5c9de161dccb4e42c8b1ae8eccb33f4ed56bccbcced9cbb0956ae7869e61 +md5: 0b2f1143ae2d0aa4c991959d0daaf256 +depends: +- libblas 3.11.0 5_haddc8a3_openblas +constrains: +- liblapack 3.11.0 5*_openblas +- liblapacke 3.11.0 5*_openblas +- blas 2.305 openblas +license: BSD-3-Clause +license_family: BSD +size: 18371 +timestamp: 1765818618899 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda +sha256: 48814b73bd462da6eed2e697e30c060ae16af21e9fbed30d64feaf0aad9da392 +md5: a9138815598fe6b91a1d6782ca657b0c +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 71117 +timestamp: 1761979776756 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda +sha256: 995ce3ad96d0f4b5ed6296b051a0d7b6377718f325bc0e792fbb96b0e369dad7 +md5: 57f3b3da02a50a1be2a6fe847515417d +depends: +- libgcc >=14 +constrains: +- expat 2.7.4.* +license: MIT +license_family: MIT +size: 76564 +timestamp: 1771259530958 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda +sha256: 3df4c539449aabc3443bbe8c492c01d401eea894603087fca2917aa4e1c2dea9 +md5: 2f364feefb6a7c00423e80dcb12db62a +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 55952 +timestamp: 1769456078358 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda +sha256: 752e4f66283d7deb4c6fd47d88df644d8daa2aaa825a54f3bf350a625190192a +md5: a229e22d4d8814a07702b0919d8e6701 +depends: +- libfreetype6 >=2.14.3 +license: GPL-2.0-only OR FTL +size: 8125 +timestamp: 1774301094057 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda +sha256: 8e6b27fe4eec4c2fa7b7769a21973734c8dba1de80086fb0213e58375ac09f4c +md5: b99ed99e42dafb27889483b3098cace7 +depends: +- libgcc >=14 +- libpng >=1.6.55,<1.7.0a0 +- libzlib >=1.3.2,<2.0a0 +constrains: +- freetype >=2.14.3 +license: GPL-2.0-only OR FTL +size: 422941 +timestamp: 1774301093473 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda +sha256: 43df385bedc1cab11993c4369e1f3b04b4ca5d0ea16cba6a0e7f18dbc129fcc9 +md5: 552567ea2b61e3a3035759b2fdb3f9a6 +depends: +- _openmp_mutex >=4.5 +constrains: +- libgcc-ng ==15.2.0=*_18 +- libgomp 15.2.0 h8acb6b2_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 622900 +timestamp: 1771378128706 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda +sha256: 83bb0415f59634dccfa8335d4163d1f6db00a27b36666736f9842b650b92cf2f +md5: 4feebd0fbf61075a1a9c2e9b3936c257 +depends: +- libgcc 15.2.0 h8acb6b2_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27568 +timestamp: 1771378136019 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_18.conda +sha256: 7dcd7dff2505d56fd5272a6e712ec912f50a46bf07dc6873a7e853694304e6e4 +md5: 41f261f5e4e2e8cbd236c2f1f15dae1b +depends: +- libgfortran5 15.2.0 h1b7bec0_18 +constrains: +- libgfortran-ng ==15.2.0=*_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27587 +timestamp: 1771378169244 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_18.conda +sha256: 85347670dfb4a8d4c13cd7cae54138dcf2b1606b6bede42eef5507bf5f9660c6 +md5: 574d88ce3348331e962cfa5ed451b247 +depends: +- libgcc >=15.2.0 +constrains: +- libgfortran 15.2.0 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 1486341 +timestamp: 1771378148102 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda +sha256: fc716f11a6a8525e27a5d332ef6a689210b0d2a4dd1133edc0f530659aa9faa6 +md5: 4faa39bf919939602e594253bd673958 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 588060 +timestamp: 1771378040807 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.2-he30d5cf_0.conda +sha256: 84064c7c53a64291a585d7215fe95ec42df74203a5bf7615d33d49a3b0f08bb6 +md5: 5109d7f837a3dfdf5c60f60e311b041f +depends: +- libgcc >=14 +constrains: +- jpeg <0.0.0a +license: IJG AND BSD-3-Clause AND Zlib +size: 691818 +timestamp: 1762094728337 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-5_h88aeb00_openblas.conda +build_number: 5 +sha256: 692222d186d3ffbc99eaf04b5b20181fd26aee1edec1106435a0a755c57cce86 +md5: 88d1e4133d1182522b403e9ba7435f04 +depends: +- libblas 3.11.0 5_haddc8a3_openblas +constrains: +- liblapacke 3.11.0 5*_openblas +- blas 2.305 openblas +- libcblas 3.11.0 5*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18392 +timestamp: 1765818627104 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda +sha256: 843c46e20519651a3e357a8928352b16c5b94f4cd3d5481acc48be2e93e8f6a3 +md5: 96944e3c92386a12755b94619bae0b35 +depends: +- libgcc >=14 +constrains: +- xz 5.8.2.* +license: 0BSD +size: 125916 +timestamp: 1768754941722 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda +sha256: 57c0dd12d506e84541c4e877898bd2a59cca141df493d34036f18b2751e0a453 +md5: 7b9813e885482e3ccb1fa212b86d7fd0 +depends: +- libgcc >=14 +license: BSD-2-Clause +license_family: BSD +size: 114056 +timestamp: 1769482343003 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.30-pthreads_h9d3fd7e_4.conda +sha256: 794a7270ea049ec931537874cd8d2de0ef4b3cef71c055cfd8b4be6d2f4228b0 +md5: 11d7d57b7bdd01da745bbf2b67020b2e +depends: +- libgcc >=14 +- libgfortran +- libgfortran5 >=14.3.0 +constrains: +- openblas >=0.3.30,<0.3.31.0a0 +license: BSD-3-Clause +license_family: BSD +size: 4959359 +timestamp: 1763114173544 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.55-h1abf092_0.conda +sha256: c7378c6b79de4d571d00ad1caf0a4c19d43c9c94077a761abb6ead44d891f907 +md5: be4088903b94ea297975689b3c3aeb27 +depends: +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +license: zlib-acknowledgement +size: 340156 +timestamp: 1770691477245 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda +sha256: 1ddaf91b44fae83856276f4cb7ce544ffe41d4b55c1e346b504c6b45f19098d6 +md5: 77891484f18eca74b8ad83694da9815e +depends: +- icu >=78.2,<79.0a0 +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +license: blessing +size: 952296 +timestamp: 1772818881550 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda +sha256: 31fdb9ffafad106a213192d8319b9f810e05abca9c5436b60e507afb35a6bc40 +md5: f56573d05e3b735cb03efeb64a15f388 +depends: +- libgcc 15.2.0 h8acb6b2_18 +constrains: +- libstdcxx-ng ==15.2.0=*_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 5541411 +timestamp: 1771378162499 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda +sha256: 7ff79470db39e803e21b8185bc8f19c460666d5557b1378d1b1e857d929c6b39 +md5: 8c6fd84f9c87ac00636007c6131e457d +depends: +- lerc >=4.0.0,<5.0a0 +- libdeflate >=1.25,<1.26.0a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.0,<4.0a0 +- liblzma >=5.8.1,<6.0a0 +- libstdcxx >=14 +- libwebp-base >=1.6.0,<2.0a0 +- libzlib >=1.3.1,<2.0a0 +- zstd >=1.5.7,<1.6.0a0 +license: HPND +size: 488407 +timestamp: 1762022048105 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda +sha256: c37a8e89b700646f3252608f8368e7eb8e2a44886b92776e57ad7601fc402a11 +md5: cf2861212053d05f27ec49c3784ff8bb +depends: +- libgcc >=14 +license: BSD-3-Clause +license_family: BSD +size: 43453 +timestamp: 1766271546875 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda +sha256: b03700a1f741554e8e5712f9b06dd67e76f5301292958cd3cb1ac8c6fdd9ed25 +md5: 24e92d0942c799db387f5c9d7b81f1af +depends: +- libgcc >=14 +constrains: +- libwebp 1.6.0 +license: BSD-3-Clause +license_family: BSD +size: 359496 +timestamp: 1752160685488 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda +sha256: 461cab3d5650ac6db73a367de5c8eca50363966e862dcf60181d693236b1ae7b +md5: cd14ee5cca2464a425b1dbfc24d90db2 +depends: +- libgcc >=13 +- pthread-stubs +- xorg-libxau >=1.0.11,<2.0a0 +- xorg-libxdmcp +license: MIT +license_family: MIT +size: 397493 +timestamp: 1727280745441 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda +sha256: eb111e32e5a7313a5bf799c7fb2419051fa2fe7eff74769fac8d5a448b309f7f +md5: 502006882cf5461adced436e410046d1 +constrains: +- zlib 1.3.2 *_2 +license: Zlib +license_family: Other +size: 69833 +timestamp: 1774072605429 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +sha256: 20e0892592a3e7c683e3d66df704a9425d731486a97c34fc56af4da1106b2b6b +md5: ba0a9221ce1063f31692c07370d062f3 +depends: +- importlib-metadata >=4.4 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 85893 +timestamp: 1770694658918 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda +sha256: 7b1da4b5c40385791dbc3cc85ceea9fad5da680a27d5d3cb8bfaa185e304a89e +md5: 5b5203189eb668f042ac2b0826244964 +depends: +- mdurl >=0.1,<1 +- python >=3.10 +license: MIT +license_family: MIT +size: 64736 +timestamp: 1754951288511 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.3-py314hb76de3f_1.conda +sha256: 383c188496d13a55658c06e61e7d4cdff2c9f9d5a0648769fca8250bece7e0ef +md5: e5de3c36dd548b35ff2a8aa49208dcb3 +depends: +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +constrains: +- jinja2 >=3.0.0 +license: BSD-3-Clause +license_family: BSD +size: 27913 +timestamp: 1772446407659 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/mathjax-2.7.7-h8af1aa0_3.tar.bz2 +sha256: 8fd4c79d6eda3d4cba73783114305a53a154ada4d1e334d4e02cb3521429599b +md5: 7b08314a6867a9d5648a1c3265e9eb8e +license: Apache-2.0 +license_family: Apache +size: 22257008 +timestamp: 1662784555011 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +sha256: 78c1bbe1723449c52b7a9df1af2ee5f005209f67e40b6e1d3c7619127c43b1c7 +md5: 592132998493b3ff25fd7479396e8351 +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 14465 +timestamp: 1733255681319 +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.33-pyhdfd78af_0.conda +sha256: f005760b13093362fc9c997d603dd487de32ab2e821a3cbce52a42bcb8136517 +md5: 698a8a27c2b9d8a542c70cb47099a75e +depends: +- click +- coloredlogs +- humanize +- importlib-metadata +- jinja2 >=3.0.0 +- jsonschema +- markdown +- natsort +- numpy +- packaging +- pillow >=10.2.0 +- plotly >=5.18 +- polars-lts-cpu +- pyaml-env +- pydantic >=2.7.1 +- python >=3.8,!=3.14.1 +- python-dotenv +- python-kaleido 0.2.1 +- pyyaml >=4 +- requests +- rich >=10 +- rich-click +- spectra >=0.0.10 +- tiktoken +- tqdm +- typeguard +license: GPL-3.0-or-later +license_family: GPL3 +size: 4198799 +timestamp: 1765300743879 +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.18.1-pyhcf101f3_1.conda +sha256: 541fd4390a0687228b8578247f1536a821d9261389a65585af9d1a6f2a14e1e0 +md5: 30bec5e8f4c3969e2b1bd407c5e52afb +depends: +- python >=3.10 +- python +license: MIT +size: 280459 +timestamp: 1774380620329 +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +sha256: aeb1548eb72e4f198e72f19d242fb695b35add2ac7b2c00e0d83687052867680 +md5: e941e85e273121222580723010bd4fa2 +depends: +- python >=3.9 +- python +license: MIT +license_family: MIT +size: 39262 +timestamp: 1770905275632 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda +sha256: 91cfb655a68b0353b2833521dc919188db3d8a7f4c64bea2c6a7557b24747468 +md5: 182afabe009dc78d8b73100255ee6868 +depends: +- libgcc >=13 +license: X11 AND BSD-3-Clause +size: 926034 +timestamp: 1738196018799 +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +sha256: f6a82172afc50e54741f6f84527ef10424326611503c64e359e25a19a8e4c1c6 +md5: a2c1eeadae7a309daed9d62c96012a2b +depends: +- python >=3.11 +- python +constrains: +- numpy >=1.25 +- scipy >=1.11.2 +- matplotlib-base >=3.8 +- pandas >=2.0 +license: BSD-3-Clause +license_family: BSD +size: 1587439 +timestamp: 1765215107045 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nspr-4.38-h3ad9384_0.conda +sha256: 78a06e89285fef242e272998b292c1e621e3ee3dd4fba62ec014e503c7ec118f +md5: 6dd4f07147774bf720075a210f8026b9 +depends: +- libgcc >=14 +- libstdcxx >=14 +license: MPL-2.0 +license_family: MOZILLA +size: 235140 +timestamp: 1762350120355 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nss-3.118-h544fa81_0.conda +sha256: 48942696889367ffd448f8dccfc080fb7e130b9938a4a3b6b20ef8e6af856463 +md5: 4540f9570d12db2150f42ba036154552 +depends: +- libgcc >=14 +- libsqlite >=3.51.0,<4.0a0 +- libstdcxx >=14 +- libzlib >=1.3.1,<2.0a0 +- nspr >=4.38,<5.0a0 +license: MPL-2.0 +license_family: MOZILLA +size: 2061869 +timestamp: 1763490303490 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.3-py314haac167e_0.conda +sha256: a6d42fd88afc57c3b0a57b21a12eff7492dfc419bb61ee3f74e9ba6261dabc88 +md5: 25d896c331481145720a21e5145fad65 +depends: +- python +- libgcc >=14 +- python 3.14.* *_cp314 +- libstdcxx >=14 +- libcblas >=3.9.0,<4.0a0 +- liblapack >=3.9.0,<4.0a0 +- python_abi 3.14.* *_cp314 +- libblas >=3.9.0,<4.0a0 +constrains: +- numpy-base <0a0 +license: BSD-3-Clause +license_family: BSD +size: 8008045 +timestamp: 1773839355275 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.4-h5da879a_0.conda +sha256: bd1bc8bdde5e6c5cbac42d462b939694e40b59be6d0698f668515908640c77b8 +md5: cea962410e327262346d48d01f05936c +depends: +- libgcc >=14 +- libpng >=1.6.50,<1.7.0a0 +- libstdcxx >=14 +- libtiff >=4.7.1,<4.8.0a0 +- libzlib >=1.3.1,<2.0a0 +license: BSD-2-Clause +license_family: BSD +size: 392636 +timestamp: 1758489353577 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda +sha256: 7f8048c0e75b2620254218d72b4ae7f14136f1981c5eb555ef61645a9344505f +md5: 25f5885f11e8b1f075bccf4a2da91c60 +depends: +- ca-certificates +- libgcc >=14 +license: Apache-2.0 +license_family: Apache +size: 3692030 +timestamp: 1769557678657 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda +sha256: c1fc0f953048f743385d31c468b4a678b3ad20caffdeaa94bed85ba63049fd58 +md5: b76541e68fea4d511b1ac46a28dcd2c6 +depends: +- python >=3.8 +- python +license: Apache-2.0 +license_family: APACHE +size: 72010 +timestamp: 1769093650580 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-12.1.1-py314hac3e5ec_0.conda +sha256: 1ca2d1616baad9bccb7ebc425ef2dcd6cebe742fbe91edf226fb606ad371ca0f +md5: d3c959c7efe560b2d7da459d69121fe9 +depends: +- python +- python 3.14.* *_cp314 +- libgcc >=14 +- zlib-ng >=2.3.3,<2.4.0a0 +- libwebp-base >=1.6.0,<2.0a0 +- tk >=8.6.13,<8.7.0a0 +- libfreetype >=2.14.1 +- libfreetype6 >=2.14.1 +- libtiff >=4.7.1,<4.8.0a0 +- lcms2 >=2.18,<3.0a0 +- python_abi 3.14.* *_cp314 +- openjpeg >=2.5.4,<3.0a0 +- libjpeg-turbo >=3.1.2,<4.0a0 +- libxcb >=1.17.0,<2.0a0 +license: HPND +size: 1051828 +timestamp: 1770794010335 +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +sha256: c418d325359fc7a0074cea7f081ef1bce26e114d2da8a0154c5d27ecc87a08e7 +md5: 3e9427ee186846052e81fadde8ebe96a +depends: +- narwhals >=1.15.1 +- packaging +- python >=3.10 +constrains: +- ipywidgets >=7.6 +license: MIT +license_family: MIT +size: 5251872 +timestamp: 1772628857717 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.39.3-pyh58ad624_1.conda +sha256: d332c2d5002fc440ae37ed9679ffc21b552f18d20232390005d1dd3bce0888d3 +md5: d5a4e013a30dd8dfde9ab39f45aaf9c1 +depends: +- polars-runtime-32 ==1.39.3 +- python >=3.10 +- python +constrains: +- numpy >=1.16.0 +- pyarrow >=7.0.0 +- fastexcel >=0.9 +- openpyxl >=3.0.0 +- xlsx2csv >=0.8.0 +- connectorx >=0.3.2 +- deltalake >=1.0.0 +- pyiceberg >=0.7.1 +- altair >=5.4.0 +- great_tables >=0.8.0 +- polars-runtime-32 ==1.39.3 +- polars-runtime-64 ==1.39.3 +- polars-runtime-compat ==1.39.3 +license: MIT +license_family: MIT +size: 533495 +timestamp: 1774207987966 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-lts-cpu-1.34.0.deprecated-hc364b38_0.conda +sha256: e466fb31f67ba9bde18deafeb34263ca5eb25807f39ead0e9d753a8e82c4c4f4 +md5: ef0340e75068ac8ff96462749b5c98e7 +depends: +- polars >=1.34.0 +- polars-runtime-compat >=1.34.0 +license: MIT +license_family: MIT +size: 3902 +timestamp: 1760206808444 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-32-1.39.3-py310hff09b76_1.conda +noarch: python +sha256: c070be507c5a90df397a47ae0299660be437d5546d68f1bc0fa4402c9f07d59e +md5: 3c1a7c6b4ba8b9fb773ace9723f8a5db +depends: +- python +- libgcc >=14 +- libstdcxx >=14 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 34785466 +timestamp: 1774207998285 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-compat-1.39.3-py310hf00a4a2_1.conda +noarch: python +sha256: 683315f1a49e47ce72bf9462419733b40b588b2b3106552d95fd4cd994e174de +md5: dd3464e2132dc3a783e76e5078870c76 +depends: +- python +- libgcc >=14 +- libstdcxx >=14 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 34652491 +timestamp: 1774207996879 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda +sha256: e9cbcbc94e151ada3d6dc365380aaaf591f65012c16d9a2abaea4b9b90adc402 +md5: ab7288cc39545556d1bc5e71ab2df9a9 +depends: +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-2.0-or-later AND LGPL-2.0-or-later +license_family: GPL +size: 636733 +timestamp: 1769712412683 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda +sha256: 977dfb0cb3935d748521dd80262fe7169ab82920afd38ed14b7fee2ea5ec01ba +md5: bb5a90c93e3bac3d5690acf76b4a6386 +depends: +- libgcc >=13 +license: MIT +license_family: MIT +size: 8342 +timestamp: 1726803319942 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +sha256: 58994e0d2ea8584cb399546e6f6896d771995e6121d1a7b6a2c9948388358932 +md5: e17be1016bcc3516827b836cd3e4d9dc +depends: +- python >=3.9 +- pyyaml >=5.0,<=7.0 +license: MIT +license_family: MIT +size: 14645 +timestamp: 1736766960536 +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda +sha256: 868569d9505b7fe246c880c11e2c44924d7613a8cdcc1f6ef85d5375e892f13d +md5: c3946ed24acdb28db1b5d63321dbca7d +depends: +- typing-inspection >=0.4.2 +- typing_extensions >=4.14.1 +- python >=3.10 +- typing-extensions >=4.6.1 +- annotated-types >=0.6.0 +- pydantic-core ==2.41.5 +- python +license: MIT +license_family: MIT +size: 340482 +timestamp: 1764434463101 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pydantic-core-2.41.5-py314h451b6cc_1.conda +sha256: f8acb2d03ebe80fed0032b9a989fc9acfb6735e3cd3f8c704b72728cb31868f6 +md5: 28f5027a1e04d67aa13fac1c5ba79693 +depends: +- python +- typing-extensions >=4.6.0,!=4.7.0 +- libgcc >=14 +- python 3.14.* *_cp314 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 1828339 +timestamp: 1762989038561 +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda +sha256: 5577623b9f6685ece2697c6eb7511b4c9ac5fb607c9babc2646c811b428fd46a +md5: 6b6ece66ebcae2d5f326c77ef2c5a066 +depends: +- python >=3.9 +license: BSD-2-Clause +license_family: BSD +size: 889287 +timestamp: 1750615908735 +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8 +md5: 461219d1a5bd61342293efa2c0c90eac +depends: +- __unix +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 21085 +timestamp: 1733217331982 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.3-hb06a95a_101_cp314.conda +build_number: 101 +sha256: 87e9dff5646aba87cecfbc08789634c855871a7325169299d749040b0923a356 +md5: 205011b36899ff0edf41b3db0eda5a44 +depends: +- bzip2 >=1.0.8,<2.0a0 +- ld_impl_linux-aarch64 >=2.36.1 +- libexpat >=2.7.3,<3.0a0 +- libffi >=3.5.2,<3.6.0a0 +- libgcc >=14 +- liblzma >=5.8.2,<6.0a0 +- libmpdec >=4.0.0,<5.0a0 +- libsqlite >=3.51.2,<4.0a0 +- libuuid >=2.41.3,<3.0a0 +- libzlib >=1.3.1,<2.0a0 +- ncurses >=6.5,<7.0a0 +- openssl >=3.5.5,<4.0a0 +- python_abi 3.14.* *_cp314 +- readline >=8.3,<9.0a0 +- tk >=8.6.13,<8.7.0a0 +- tzdata +- zstd >=1.5.7,<1.6.0a0 +license: Python-2.0 +size: 37305578 +timestamp: 1770674395875 +python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +sha256: 74e417a768f59f02a242c25e7db0aa796627b5bc8c818863b57786072aeb85e5 +md5: 130584ad9f3a513cdd71b1fdc1244e9c +depends: +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 27848 +timestamp: 1772388605021 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda +sha256: 233aebd94c704ac112afefbb29cf4170b7bc606e22958906f2672081bc50638a +md5: 235765e4ea0d0301c75965985163b5a1 +depends: +- cpython 3.14.3.* +- python_abi * *_cp314 +license: Python-2.0 +size: 50062 +timestamp: 1770674497152 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +sha256: e17bf63a30aec33432f1ead86e15e9febde9fc40a7f869c0e766be8d2db44170 +md5: 310259a5b03ff02289d7705f39e2b1d2 +depends: +- kaleido-core 0.2.1.* +- python >=3.5 +license: MIT +license_family: MIT +size: 18320 +timestamp: 1615204747600 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +build_number: 8 +sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 +md5: 0539938c55b6b1a59b560e843ad864a4 +constrains: +- python 3.14.* *_cp314 +license: BSD-3-Clause +license_family: BSD +size: 6989 +timestamp: 1752805904792 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda +sha256: 496b5e65dfdd0aaaaa5de0dcaaf3bceea00fcb4398acf152f89e567c82ec1046 +md5: 9ae2c92975118058bd720e9ba2bb7c58 +depends: +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python >=3.14,<3.15.0a0 *_cp314 +- python_abi 3.14.* *_cp314 +- yaml >=0.2.5,<0.3.0a0 +license: MIT +license_family: MIT +size: 195678 +timestamp: 1770223441816 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda +sha256: fe695f9d215e9a2e3dd0ca7f56435ab4df24f5504b83865e3d295df36e88d216 +md5: 3d49cad61f829f4f0e0611547a9cda12 +depends: +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-3.0-only +license_family: GPL +size: 357597 +timestamp: 1765815673644 +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +sha256: 0577eedfb347ff94d0f2fa6c052c502989b028216996b45c7f21236f25864414 +md5: 870293df500ca7e18bedefa5838a22ab +depends: +- attrs >=22.2.0 +- python >=3.10 +- rpds-py >=0.7.0 +- typing_extensions >=4.4.0 +- python +license: MIT +license_family: MIT +size: 51788 +timestamp: 1760379115194 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/regex-2026.2.28-py314h51f160d_0.conda +sha256: 2080ecea825e1ef91a2422cc0bc63e85db9e38908ed17657fb8f41de7a6eee71 +md5: 818aa2c9f6b3c808da5e7be22a9a424c +depends: +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python >=3.14,<3.15.0a0 *_cp314 +- python_abi 3.14.* *_cp314 +license: Apache-2.0 AND CNRI-Python +license_family: PSF +size: 408097 +timestamp: 1772255205521 +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda +sha256: 7813c38b79ae549504b2c57b3f33394cea4f2ad083f0994d2045c2e24cb538c5 +md5: c65df89a0b2e321045a9e01d1337b182 +depends: +- python >=3.10 +- certifi >=2017.4.17 +- charset-normalizer >=2,<4 +- idna >=2.5,<4 +- urllib3 >=1.21.1,<3 +- python +constrains: +- chardet >=3.0.2,<6 +license: Apache-2.0 +license_family: APACHE +size: 63602 +timestamp: 1766926974520 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda +sha256: b06ce84d6a10c266811a7d3adbfa1c11f13393b91cc6f8a5b468277d90be9590 +md5: 7a6289c50631d620652f5045a63eb573 +depends: +- markdown-it-py >=2.2.0 +- pygments >=2.13.0,<3.0.0 +- python >=3.10 +- typing_extensions >=4.0.0,<5.0.0 +- python +license: MIT +license_family: MIT +size: 208472 +timestamp: 1771572730357 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +sha256: aa3fcb167321bae51998de2e94d199109c9024f25a5a063cb1c28d8f1af33436 +md5: 0c20a8ebcddb24a45da89d5e917e6cb9 +depends: +- python >=3.10 +- rich >=12 +- click >=8 +- typing-extensions >=4 +- __unix +- python +license: MIT +license_family: MIT +size: 64356 +timestamp: 1769850479089 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rpds-py-0.30.0-py314h02b7a91_0.conda +sha256: a587240f16eac7c6a80f9585cef679cd1cb9a287b8dfcdd36dcef1f7e7db15dc +md5: e7f6ed9e60043bb5cbcc527764897f0d +depends: +- python +- libgcc >=14 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 376332 +timestamp: 1764543345455 +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +sha256: 7c65782d2511738e62c70462e89d65da4fa54d5a7e47c46667bcd27a59f81876 +md5: 472239e4eb7b5a84bb96b3ed7e3a596a +depends: +- colormath >=3.0.0 +- python >=3.9 +license: MIT +license_family: MIT +size: 22284 +timestamp: 1735770589188 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/sqlite-3.52.0-hf1c7be2_0.conda +sha256: 4f8523f5341f0d9e1547085206c6c1f71f9fc7c277443ca363a8cf98add8fc01 +md5: d9634079df93a65ee045b3c75f35cae1 +depends: +- icu >=78.2,<79.0a0 +- libgcc >=14 +- libsqlite 3.52.0 h10b116e_0 +- libzlib >=1.3.1,<2.0a0 +- ncurses >=6.5,<7.0a0 +- readline >=8.3,<9.0a0 +license: blessing +size: 209416 +timestamp: 1772818891689 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tiktoken-0.12.0-py314h6a36e60_3.conda +sha256: c1da41c79262b27efa168407cfecc47b20270e5fc071a8307f95a2c85fb94170 +md5: 55bf7b559202236157b14323b40f19e6 +depends: +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +- regex >=2022.1.18 +- requests >=2.26.0 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 914402 +timestamp: 1764030357702 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda +sha256: e25c314b52764219f842b41aea2c98a059f06437392268f09b03561e4f6e5309 +md5: 7fc6affb9b01e567d2ef1d05b84aa6ed +depends: +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +constrains: +- xorg-libx11 >=1.8.12,<2.0a0 +license: TCL +license_family: BSD +size: 3368666 +timestamp: 1769464148928 +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +sha256: 9ef8e47cf00e4d6dcc114eb32a1504cc18206300572ef14d76634ba29dfe1eb6 +md5: e5ce43272193b38c2e9037446c1d9206 +depends: +- python >=3.10 +- __unix +- python +license: MPL-2.0 and MIT +size: 94132 +timestamp: 1770153424136 +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.1-pyhd8ed1ab_0.conda +sha256: 39d8ae33c43cdb8f771373e149b0b4fae5a08960ac58dcca95b2f1642bb17448 +md5: 260af1b0a94f719de76b4e14094e9a3b +depends: +- importlib-metadata >=3.6 +- python >=3.10 +- typing-extensions >=4.10.0 +- typing_extensions >=4.14.0 +constrains: +- pytest >=7 +license: MIT +license_family: MIT +size: 36838 +timestamp: 1771532971545 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c +md5: edd329d7d3a4ab45dcf905899a7a6115 +depends: +- typing_extensions ==4.15.0 pyhcf101f3_0 +license: PSF-2.0 +license_family: PSF +size: 91383 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda +sha256: 70db27de58a97aeb7ba7448366c9853f91b21137492e0b4430251a1870aa8ff4 +md5: a0a4a3035667fc34f29bfbd5c190baa6 +depends: +- python >=3.10 +- typing_extensions >=4.12.0 +license: MIT +license_family: MIT +size: 18923 +timestamp: 1764158430324 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 +md5: 0caa1af407ecff61170c9437a808404d +depends: +- python >=3.10 +- python +license: PSF-2.0 +license_family: PSF +size: 51692 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c +md5: ad659d0a2b3e47e38d829aa8cad2d610 +license: LicenseRef-Public-Domain +size: 119135 +timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda +sha256: af641ca7ab0c64525a96fd9ad3081b0f5bcf5d1cbb091afb3f6ed5a9eee6111a +md5: 9272daa869e03efe68833e3dc7a02130 +depends: +- backports.zstd >=1.0.0 +- brotli-python >=1.2.0 +- h2 >=4,<5 +- pysocks >=1.5.6,<2.0,!=1.5.7 +- python >=3.10 +license: MIT +license_family: MIT +size: 103172 +timestamp: 1767817860341 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda +sha256: e9f6e931feeb2f40e1fdbafe41d3b665f1ab6cb39c5880a1fcf9f79a3f3c84a5 +md5: 1c246e1105000c3660558459e2fd6d43 +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 16317 +timestamp: 1762977521691 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda +sha256: 128d72f36bcc8d2b4cdbec07507542e437c7d67f677b7d77b71ed9eeac7d6df1 +md5: bff06dcde4a707339d66d45d96ceb2e2 +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 21039 +timestamp: 1762979038025 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda +sha256: 66265e943f32ce02396ad214e27cb35f5b0490b3bd4f064446390f9d67fa5d88 +md5: 032d8030e4a24fe1f72c74423a46fb88 +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 88088 +timestamp: 1753484092643 +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda +sha256: b4533f7d9efc976511a73ef7d4a2473406d7f4c750884be8e8620b0ce70f4dae +md5: 30cd29cb87d819caead4d55184c1d115 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 24194 +timestamp: 1764460141901 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-ng-2.3.3-ha7cb516_1.conda +sha256: 638a3a41a4fbfed52d3c60c8ef5a3693b3f12a5b1a3f58fa29f5698d0a0702e2 +md5: f731af71c723065d91b4c01bb822641b +depends: +- libgcc >=14 +- libstdcxx >=14 +license: Zlib +license_family: Other +size: 121046 +timestamp: 1770167944449 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda +sha256: 569990cf12e46f9df540275146da567d9c618c1e9c7a0bc9d9cfefadaed20b75 +md5: c3655f82dcea2aa179b291e7099c1fcc +depends: +- libzlib >=1.3.1,<2.0a0 +license: BSD-3-Clause +license_family: BSD +size: 614429 +timestamp: 1764777145593 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 3b0e975b..5376aea1 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,25 +1,21 @@ process MULTIQC { + tag "${meta.id}" label 'process_single' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/34/34e733a9ae16a27e80fe00f863ea1479c96416017f24a907996126283e7ecd4d/data' : - 'community.wave.seqera.io/library/multiqc:1.33--ee7739d47738383b' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/34/34e733a9ae16a27e80fe00f863ea1479c96416017f24a907996126283e7ecd4d/data' + : 'community.wave.seqera.io/library/multiqc:1.33--ee7739d47738383b'}" input: - path multiqc_files, stageAs: "?/*" - path(multiqc_config) - path(extra_multiqc_config) - path(multiqc_logo) - path(replace_names) - path(sample_names) + tuple val(meta), path(multiqc_files, stageAs: "?/*"), path(multiqc_config, stageAs: "?/*"), path(multiqc_logo), path(replace_names), path(sample_names) output: - path "*.html" , emit: report - path "*_data" , emit: data - path "*_plots" , optional:true, emit: plots - tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), emit: versions + tuple val(meta), path("*.html"), emit: report + tuple val(meta), path("*_data"), emit: data + tuple val(meta), path("*_plots"), emit: plots, optional: true // MultiQC should not push its versions to the `versions` topic. Its input depends on the versions topic to be resolved thus outputting to the topic will let the pipeline hang forever + tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), emit: versions when: task.ext.when == null || task.ext.when @@ -27,8 +23,7 @@ process MULTIQC { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ? "--filename ${task.ext.prefix}.html" : '' - def config = multiqc_config ? "--config ${multiqc_config}" : '' - def extra_config = extra_multiqc_config ? "--config ${extra_multiqc_config}" : '' + def config = multiqc_config ? multiqc_config instanceof List ? "--config ${multiqc_config.join(' --config ')}" : "--config ${multiqc_config}" : "" def logo = multiqc_logo ? "--cl-config 'custom_logo: \"${multiqc_logo}\"'" : '' def replace = replace_names ? "--replace-names ${replace_names}" : '' def samples = sample_names ? "--sample-names ${sample_names}" : '' @@ -38,7 +33,6 @@ process MULTIQC { ${args} \\ ${config} \\ ${prefix} \\ - ${extra_config} \\ ${logo} \\ ${replace} \\ ${samples} \\ @@ -50,6 +44,7 @@ process MULTIQC { mkdir multiqc_data touch multiqc_data/.stub mkdir multiqc_plots + touch multiqc_plots/.stub touch multiqc_report.html """ } diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index f790cab0..57cf43ca 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,6 +1,6 @@ name: multiqc -description: Aggregate results from bioinformatics analyses across many samples into - a single report +description: Aggregate results from bioinformatics analyses across many samples + into a single report keywords: - QC - bioinformatics tools @@ -12,67 +12,81 @@ tools: It's a general use tool, perfect for summarising the output from numerous bioinformatics tools. homepage: https://multiqc.info/ documentation: https://multiqc.info/docs/ - licence: ["GPL-3.0-or-later"] + licence: + - "GPL-3.0-or-later" identifier: biotools:multiqc input: - - multiqc_files: - type: file - description: | - List of reports / files recognised by MultiQC, for example the html and zip output of FastQC - ontologies: [] - - multiqc_config: - type: file - description: Optional config yml for MultiQC - pattern: "*.{yml,yaml}" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML - - extra_multiqc_config: - type: file - description: Second optional config yml for MultiQC. Will override common sections - in multiqc_config. - pattern: "*.{yml,yaml}" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML - - multiqc_logo: - type: file - description: Optional logo file for MultiQC - pattern: "*.{png}" - ontologies: [] - - replace_names: - type: file - description: | - Optional two-column sample renaming file. First column a set of - patterns, second column a set of corresponding replacements. Passed via - MultiQC's `--replace-names` option. - pattern: "*.{tsv}" - ontologies: - - edam: http://edamontology.org/format_3475 # TSV - - sample_names: - type: file - description: | - Optional TSV file with headers, passed to the MultiQC --sample_names - argument. - pattern: "*.{tsv}" - ontologies: - - edam: http://edamontology.org/format_3475 # TSV -output: - report: - - "*.html": + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - multiqc_files: type: file - description: MultiQC report file - pattern: ".html" + description: | + List of reports / files recognised by MultiQC, for example the html and zip output of FastQC ontologies: [] - data: - - "*_data": - type: directory - description: MultiQC data dir - pattern: "multiqc_data" - plots: - - "*_plots": + - multiqc_config: type: file - description: Plots created by MultiQC - pattern: "*_data" + description: Optional config yml for MultiQC + pattern: "*.{yml,yaml}" + ontologies: + - edam: http://edamontology.org/format_3750 + - multiqc_logo: + type: file + description: Optional logo file for MultiQC + pattern: "*.{png}" ontologies: [] + - replace_names: + type: file + description: | + Optional two-column sample renaming file. First column a set of + patterns, second column a set of corresponding replacements. Passed via + MultiQC's `--replace-names` option. + pattern: "*.{tsv}" + ontologies: + - edam: http://edamontology.org/format_3475 + - sample_names: + type: file + description: | + Optional TSV file with headers, passed to the MultiQC --sample_names + argument. + pattern: "*.{tsv}" + ontologies: + - edam: http://edamontology.org/format_3475 +output: + report: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*.html": + type: file + description: MultiQC report file + pattern: ".html" + ontologies: [] + data: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*_data": + type: directory + description: MultiQC data dir + pattern: "multiqc_data" + plots: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*_plots": + type: file + description: Plots created by MultiQC + pattern: "*_plots" + ontologies: [] versions: - - ${task.process}: type: string @@ -95,25 +109,25 @@ maintainers: - "@jfy133" containers: conda: - linux_amd64: - lock_file: https://wave.seqera.io/v1alpha1/builds/bd-d58f60e4deb769bf_1/condalock - linux_arm64: - lock_file: https://wave.seqera.io/v1alpha1/builds/bd-193776baee4194db_1/condalock + linux/amd64: + lock_file: modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c1f4a7982b743963_1.txt + linux/arm64: + lock_file: modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-40bf3b435e89dc22_1.txt docker: - linux_amd64: - build_id: bd-d58f60e4deb769bf_1 - name: community.wave.seqera.io/library/multiqc:1.32--d58f60e4deb769bf - scanId: sc-d76ac07493e940b4_6 - linux_arm64: - build_id: bd-193776baee4194db_1 - name: community.wave.seqera.io/library/multiqc:1.32--193776baee4194db - scanId: sc-86caded0bff8246e_3 + linux/amd64: + name: community.wave.seqera.io/library/multiqc:1.33--c1f4a7982b743963 + build_id: bd-c1f4a7982b743963_1 + scan_id: sc-b7b7f470b2a16699_1 + linux/arm64: + name: community.wave.seqera.io/library/multiqc:1.33--40bf3b435e89dc22 + build_id: bd-40bf3b435e89dc22_1 + scan_id: sc-0e2108a0e7368d2f_1 singularity: - linux_amd64: - build_id: bd-e649ffa094d1ef4a_1 - name: oras://community.wave.seqera.io/library/multiqc:1.32--e649ffa094d1ef4a - https: https://community.wave.seqera.io/v2/library/multiqc/blobs/sha256:8c6c120d559d7ee04c7442b61ad7cf5a9e8970be5feefb37d68eeaa60c1034eb - linux_arm64: - build_id: bd-aee0064f5570ef22_1 - name: oras://community.wave.seqera.io/library/multiqc:1.32--aee0064f5570ef22 - https: https://community.wave.seqera.io/v2/library/multiqc/blobs/sha256:f02c59ebf6e9a00aa954ee8188a4ecc5c743e18f40b9215a242f67606a00f9cf + linux/amd64: + name: oras://community.wave.seqera.io/library/multiqc:1.33--9b3473b1c4bb0493 + build_id: bd-9b3473b1c4bb0493_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c4/c4e6d9f669e1a99b53c7dc5cdd6b8e7fd6654032c755bb783cc9849e8203f4d1/data + linux/arm64: + name: oras://community.wave.seqera.io/library/multiqc:1.33--e1ef2065eb21b530 + build_id: bd-e1ef2065eb21b530_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/2a/2acce766e3efb280fa43acdbe85305ea6496ddadbcaa2d806ac4985dfe4686ce/data diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index 06a6cda4..4cbdb95d 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -15,25 +15,41 @@ nextflow_process { when { process { """ - input[0] = channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = [] - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) """ } } then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, - { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.findAll { key, val -> key.startsWith("versions")}).match() } - ) + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() } - } test("sarscov2 single-end [fastqc] - custom prefix") { @@ -42,24 +58,41 @@ nextflow_process { when { process { """ - input[0] = channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = [] - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) """ } } then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/custom_prefix.html" }, - { assert process.out.data[0] ==~ ".*/custom_prefix_data" } - ) + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() } - } test("sarscov2 single-end [fastqc] [config]") { @@ -67,23 +100,85 @@ nextflow_process { when { process { """ - input[0] = channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true), + [], + [], + [] + ]) """ } } then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, - { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.findAll { key, val -> key.startsWith("versions")}).match() } - ) + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() + } + } + + test("sarscov2 single-end [fastqc] [multiple configs]") { + + when { + process { + """ + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [ + file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true), + file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true) + ], + [], + [], + [] + ]) + """ + } + } + + then { + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() } } @@ -94,25 +189,23 @@ nextflow_process { when { process { """ - input[0] = channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = [] - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out.report.collect { file(it).getName() } + - process.out.data.collect { file(it).getName() } + - process.out.plots.collect { file(it).getName() } + - process.out.findAll { key, val -> key.startsWith("versions")} ).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } - } } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index d72d35b7..3bfc524f 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -1,7 +1,176 @@ { + "sarscov2 single-end [fastqc] [multiple configs]": { + "content": [ + { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "multiqc_report.html", + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } + ], + "timestamp": "2026-03-17T16:15:42.577775492", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, "sarscov2 single-end [fastqc]": { "content": [ { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_software_versions.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "multiqc_report.html", "versions": [ [ "MULTIQC", @@ -11,38 +180,230 @@ ] } ], + "timestamp": "2026-03-17T16:21:17.072841555", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-09T10:10:43.020315838" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 single-end [fastqc] - stub": { "content": [ - [ - "multiqc_report.html", - "multiqc_data", - "multiqc_plots", - { - "versions": [ + { + "data": [ + [ + { + "id": "FASTQC" + }, + [ + ".stub:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "plots": [ + [ + { + "id": "FASTQC" + }, [ - "MULTIQC", - "multiqc", - "1.33" + ".stub:md5,d41d8cd98f00b204e9800998ecf8427e" ] ] - } - ] + ], + "report": [ + [ + { + "id": "FASTQC" + }, + "multiqc_report.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } ], + "timestamp": "2026-02-26T15:14:39.789193051", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-09T10:11:14.131950776" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 single-end [fastqc] [config]": { "content": [ { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "multiqc_report.html", + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } + ], + "timestamp": "2026-03-17T16:15:30.372239611", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, + "sarscov2 single-end [fastqc] - custom prefix": { + "content": [ + { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_software_versions.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "custom_prefix.html", "versions": [ [ "MULTIQC", @@ -52,10 +413,10 @@ ] } ], + "timestamp": "2026-03-17T16:15:18.189023981", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-09T10:11:07.15692209" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/tests/nextflow.config b/modules/nf-core/multiqc/tests/nextflow.config index c537a6a3..374dfef2 100644 --- a/modules/nf-core/multiqc/tests/nextflow.config +++ b/modules/nf-core/multiqc/tests/nextflow.config @@ -1,5 +1,6 @@ process { withName: 'MULTIQC' { ext.prefix = null + ext.args = '-p' } } diff --git a/modules/nf-core/scvitools/scar/templates/scar.py b/modules/nf-core/scvitools/scar/templates/scar.py index 3418ce56..0ad95cc8 100644 --- a/modules/nf-core/scvitools/scar/templates/scar.py +++ b/modules/nf-core/scvitools/scar/templates/scar.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility +import os +os.environ["KMP_AFFINITY"] = "disabled" + import anndata as ad import scvi import yaml diff --git a/modules/nf-core/scvitools/solo/templates/solo.py b/modules/nf-core/scvitools/solo/templates/solo.py index 810869b5..b1da9388 100644 --- a/modules/nf-core/scvitools/solo/templates/solo.py +++ b/modules/nf-core/scvitools/solo/templates/solo.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 +# Disable OpenMP CPU topology detection for MacOS compatibility import os +os.environ["KMP_AFFINITY"] = "disabled" os.environ["MPLCONFIGDIR"] = "./tmp" diff --git a/modules/nf-core/untar/main.nf b/modules/nf-core/untar/main.nf index e712ebe6..b9c324da 100644 --- a/modules/nf-core/untar/main.nf +++ b/modules/nf-core/untar/main.nf @@ -12,7 +12,7 @@ process UNTAR { output: tuple val(meta), path("${prefix}"), emit: untar - path "versions.yml", emit: versions + tuple val("${task.process}"), val('untar'), eval('tar --version 2>&1 | head -1 | sed "s/tar (GNU tar) //; s/ Copyright.*//"'), emit: versions_untar, topic: versions when: task.ext.when == null || task.ext.when @@ -43,10 +43,6 @@ process UNTAR { ${args2} fi - cat <<-END_VERSIONS > versions.yml - "${task.process}": - untar: \$(echo \$(tar --version 2>&1) | sed 's/^.*(GNU tar) //; s/ Copyright.*\$//') - END_VERSIONS """ stub: @@ -75,10 +71,5 @@ process UNTAR { fi done fi - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - untar: \$(echo \$(tar --version 2>&1) | sed 's/^.*(GNU tar) //; s/ Copyright.*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/untar/meta.yml b/modules/nf-core/untar/meta.yml index 1603e382..571d8078 100644 --- a/modules/nf-core/untar/meta.yml +++ b/modules/nf-core/untar/meta.yml @@ -38,13 +38,29 @@ output: Groovy Map containing sample information e.g. [ id:'test', single_end:false ] pattern: "*/" + versions_untar: + - - ${task.process}: + type: string + description: The name of the process + - untar: + type: string + description: The name of the tool + - tar --version 2>&1 | head -1 | sed "s/tar (GNU tar) //; s/ Copyright.*//": + type: eval + description: The expression to obtain the version of the tool + +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - untar: + type: string + description: The name of the tool + - tar --version 2>&1 | head -1 | sed "s/tar (GNU tar) //; s/ Copyright.*//": + type: eval + description: The expression to obtain the version of the tool + authors: - "@joseespinosa" - "@drpatelh" diff --git a/modules/nf-core/untar/tests/main.nf.test b/modules/nf-core/untar/tests/main.nf.test index c957517a..fde8db16 100644 --- a/modules/nf-core/untar/tests/main.nf.test +++ b/modules/nf-core/untar/tests/main.nf.test @@ -20,7 +20,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() }, + { assert snapshot( + process.out.untar, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() }, ) } } @@ -38,7 +41,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() }, + { assert snapshot( + process.out.untar, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() }, ) } } @@ -58,7 +64,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() }, + { assert snapshot( + process.out.untar, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() }, ) } } @@ -78,7 +87,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() }, + { assert snapshot( + process.out.untar, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() }, ) } } diff --git a/modules/nf-core/untar/tests/main.nf.test.snap b/modules/nf-core/untar/tests/main.nf.test.snap index ceb91b79..51a414dd 100644 --- a/modules/nf-core/untar/tests/main.nf.test.snap +++ b/modules/nf-core/untar/tests/main.nf.test.snap @@ -1,158 +1,118 @@ { "test_untar_onlyfiles": { "content": [ - { - "0": [ + [ + [ + [ + + ], [ - [ - - ], - [ - "hello.txt:md5,e59ff97941044f85df5297e1c302d260" - ] + "hello.txt:md5,e59ff97941044f85df5297e1c302d260" ] - ], - "1": [ - "versions.yml:md5,6063247258c56fd271d076bb04dd7536" - ], - "untar": [ + ] + ], + { + "versions_untar": [ [ - [ - - ], - [ - "hello.txt:md5,e59ff97941044f85df5297e1c302d260" - ] + "UNTAR", + "untar", + "1.34" ] - ], - "versions": [ - "versions.yml:md5,6063247258c56fd271d076bb04dd7536" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.3" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2024-07-10T12:04:28.231047" + "timestamp": "2026-01-28T17:49:32.000491" }, "test_untar_onlyfiles - stub": { "content": [ - { - "0": [ + [ + [ + [ + + ], [ - [ - - ], - [ - "hello.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + "hello.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] - ], - "1": [ - "versions.yml:md5,6063247258c56fd271d076bb04dd7536" - ], - "untar": [ + ] + ], + { + "versions_untar": [ [ - [ - - ], - [ - "hello.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + "UNTAR", + "untar", + "1.34" ] - ], - "versions": [ - "versions.yml:md5,6063247258c56fd271d076bb04dd7536" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.3" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2024-07-10T12:04:45.773103" + "timestamp": "2026-01-28T17:49:58.812479" }, "test_untar - stub": { "content": [ - { - "0": [ + [ + [ + [ + + ], [ - [ - - ], - [ - "hash.k2d:md5,d41d8cd98f00b204e9800998ecf8427e", - "opts.k2d:md5,d41d8cd98f00b204e9800998ecf8427e", - "taxo.k2d:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + "hash.k2d:md5,d41d8cd98f00b204e9800998ecf8427e", + "opts.k2d:md5,d41d8cd98f00b204e9800998ecf8427e", + "taxo.k2d:md5,d41d8cd98f00b204e9800998ecf8427e" ] - ], - "1": [ - "versions.yml:md5,6063247258c56fd271d076bb04dd7536" - ], - "untar": [ + ] + ], + { + "versions_untar": [ [ - [ - - ], - [ - "hash.k2d:md5,d41d8cd98f00b204e9800998ecf8427e", - "opts.k2d:md5,d41d8cd98f00b204e9800998ecf8427e", - "taxo.k2d:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + "UNTAR", + "untar", + "1.34" ] - ], - "versions": [ - "versions.yml:md5,6063247258c56fd271d076bb04dd7536" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.3" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2024-07-10T12:04:36.777441" + "timestamp": "2026-01-28T17:49:48.119456" }, "test_untar": { "content": [ - { - "0": [ + [ + [ + [ + + ], [ - [ - - ], - [ - "hash.k2d:md5,8b8598468f54a7087c203ad0190555d9", - "opts.k2d:md5,a033d00cf6759407010b21700938f543", - "taxo.k2d:md5,094d5891cdccf2f1468088855c214b2c" - ] + "hash.k2d:md5,8b8598468f54a7087c203ad0190555d9", + "opts.k2d:md5,a033d00cf6759407010b21700938f543", + "taxo.k2d:md5,094d5891cdccf2f1468088855c214b2c" ] - ], - "1": [ - "versions.yml:md5,6063247258c56fd271d076bb04dd7536" - ], - "untar": [ + ] + ], + { + "versions_untar": [ [ - [ - - ], - [ - "hash.k2d:md5,8b8598468f54a7087c203ad0190555d9", - "opts.k2d:md5,a033d00cf6759407010b21700938f543", - "taxo.k2d:md5,094d5891cdccf2f1468088855c214b2c" - ] + "UNTAR", + "untar", + "1.34" ] - ], - "versions": [ - "versions.yml:md5,6063247258c56fd271d076bb04dd7536" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.3" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2024-07-10T12:04:19.377674" + "timestamp": "2026-01-28T17:49:17.252494" } } \ No newline at end of file diff --git a/nf-test.config b/nf-test.config index 9680c4b6..2eaa14f0 100644 --- a/nf-test.config +++ b/nf-test.config @@ -20,7 +20,7 @@ config { // load the necessary plugins plugins { load "nft-utils@0.0.3" - load "nft-anndata@0.3.5" + load "nft-anndata@0.4.1" load "nft-csv@0.1.0" } } diff --git a/subworkflows/local/ambient_correction/main.nf b/subworkflows/local/ambient_correction/main.nf index ea191413..ef879b05 100644 --- a/subworkflows/local/ambient_correction/main.nf +++ b/subworkflows/local/ambient_correction/main.nf @@ -69,7 +69,6 @@ workflow AMBIENT_CORRECTION { CELLBENDER_REMOVEBACKGROUND ( ch_multi.input .map { meta, _filtered, unfiltered -> [meta, unfiltered] }) - ch_versions = ch_versions.mix(CELLBENDER_REMOVEBACKGROUND.out.versions) CELLBENDER_MERGE ( ch_multi.input @@ -86,7 +85,6 @@ workflow AMBIENT_CORRECTION { ch_multi.output_layer ) ch_h5ad = ch_h5ad.mix(CELLBENDER_MERGE.out.h5ad) - ch_versions = ch_versions.mix(CELLBENDER_MERGE.out.versions) } else if (method == 'soupx') { SOUPX ( diff --git a/subworkflows/local/ambient_correction/tests/main.nf.test b/subworkflows/local/ambient_correction/tests/main.nf.test index 977a38f8..3a3df23d 100644 --- a/subworkflows/local/ambient_correction/tests/main.nf.test +++ b/subworkflows/local/ambient_correction/tests/main.nf.test @@ -28,10 +28,12 @@ nextflow_workflow { } then { - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() } - ) + assert workflow.success + assert workflow.out.h5ad.size() == 1 + assert snapshot( + workflow.out.versions, + workflow.out.h5ad.size() + ).match() } } @@ -83,10 +85,12 @@ nextflow_workflow { } then { - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() } - ) + assert workflow.success + assert workflow.out.h5ad.size() == 1 + assert snapshot( + workflow.out.versions, + workflow.out.h5ad.size() + ).match() } } @@ -112,12 +116,15 @@ nextflow_workflow { } then { - def h5ad = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() }, - { assert "ambient_corrected_decontx" in anndata(h5ad).layers } - ) + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + + assert "ambient_corrected_decontx" in adata.layers + + assert snapshot( + workflow.out.versions, + adata.yaml + ).match() } } @@ -143,12 +150,15 @@ nextflow_workflow { } then { - def h5ad = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() }, - { assert "ambient_corrected_decontx" in anndata(h5ad).layers } - ) + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + + assert "ambient_corrected_decontx" in adata.layers + + assert snapshot( + workflow.out.versions, + adata.yaml + ).match() } } @@ -174,12 +184,15 @@ nextflow_workflow { } then { - def h5ad = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() }, - { assert "ambient_corrected_soupx" in anndata(h5ad).layers } - ) + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + + assert "ambient_corrected_soupx" in adata.layers + + assert snapshot( + workflow.out.versions, + adata.yaml + ).match() } } @@ -206,12 +219,15 @@ nextflow_workflow { } then { - def h5ad = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() }, - { assert "ambient_corrected_scar" in anndata(h5ad).layers } - ) + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + + assert "ambient_corrected_scar" in adata.layers + + assert snapshot( + workflow.out.versions, + adata.yaml + ).match() } } @@ -237,12 +253,15 @@ nextflow_workflow { } then { - def h5ad = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() }, - { assert "ambient_corrected_cellbender" in anndata(h5ad).layers } - ) + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + + assert "ambient_corrected_cellbender" in adata.layers + + assert snapshot( + workflow.out.versions, + adata.yaml + ).match() } } @@ -268,12 +287,14 @@ nextflow_workflow { } then { - def h5ad = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() }, - { assert anndata(h5ad).obs.rownames.size() > 0 } - ) + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + // output written to X, so no named decontx layer + assert !("ambient_corrected_decontx" in adata.layers) + assert snapshot( + workflow.out.versions, + adata.yaml + ).match() } } @@ -299,12 +320,14 @@ nextflow_workflow { } then { - def h5ad = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() }, - { assert anndata(h5ad).obs.rownames.size() > 0 } - ) + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + // output written to X, so no named soupx layer + assert !("ambient_corrected_soupx" in adata.layers) + assert snapshot( + workflow.out.versions, + adata.yaml + ).match() } } @@ -331,12 +354,14 @@ nextflow_workflow { } then { - def h5ad = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() }, - { assert anndata(h5ad).obs.rownames.size() > 0 } - ) + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + // output written to X, so no named scar layer + assert !("ambient_corrected_scar" in adata.layers) + assert snapshot( + workflow.out.versions, + adata.yaml + ).match() } } @@ -362,12 +387,14 @@ nextflow_workflow { } then { - def h5ad = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out.versions).match() }, - { assert anndata(h5ad).obs.rownames.size() > 0 } - ) + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + // output written to X, so no named cellbender layer + assert !("ambient_corrected_cellbender" in adata.layers) + assert snapshot( + workflow.out.versions, + adata.yaml + ).match() } } diff --git a/subworkflows/local/ambient_correction/tests/main.nf.test.snap b/subworkflows/local/ambient_correction/tests/main.nf.test.snap index 16a305cb..9e8efbcc 100644 --- a/subworkflows/local/ambient_correction/tests/main.nf.test.snap +++ b/subworkflows/local/ambient_correction/tests/main.nf.test.snap @@ -3,9 +3,10 @@ "content": [ [ - ] + ], + 1 ], - "timestamp": "2026-03-23T22:53:42.301253063", + "timestamp": "2026-03-25T15:46:16.218237575", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -15,34 +16,135 @@ "content": [ [ "versions.yml:md5,f9ea95abb10a7769d50d14fcaa5734ee" - ] + ], + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T23:01:44.949156977", + "timestamp": "2026-03-29T11:28:03.511988284", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" } }, - "Should run with 'cellbender' ambient correction to 'X'": { + "Should run with 'decontx' ambient correction and no batch column": { "content": [ [ - "versions.yml:md5,1d70371b0f0ca5e50f7ba70335f8946f", - "versions.yml:md5,e6e98e83cbc9a2924c66e901445bbc4f" - ] + "versions.yml:md5,f9ea95abb10a7769d50d14fcaa5734ee" + ], + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + "ambient_corrected_decontx" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T23:06:59.552055248", + "timestamp": "2026-03-29T11:21:35.00820843", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" } }, - "Should run with 'decontx' ambient correction and no batch column": { + "Should run with 'cellbender' ambient correction to 'X'": { "content": [ [ - "versions.yml:md5,f9ea95abb10a7769d50d14fcaa5734ee" - ] + + ], + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T22:55:48.212429509", + "timestamp": "2026-03-30T08:50:28.315741473", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -52,9 +154,43 @@ "content": [ [ "versions.yml:md5,f9ea95abb10a7769d50d14fcaa5734ee" - ] + ], + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + "ambient_corrected_decontx" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T22:54:53.07199224", + "timestamp": "2026-03-29T11:18:56.290966056", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -64,33 +200,104 @@ "content": [ [ "versions.yml:md5,0266faf0b40a7b86ec9f2b1948f8c7aa" - ] + ], + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T23:02:27.711519463", + "timestamp": "2026-03-29T11:28:48.515147711", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" } }, - "Should run with 'scar' ambient correction": { + "Should not do anything if ambient correction is disabled in meta": { "content": [ [ - "versions.yml:md5,2717cb5f250a65aec0a76a456f7028ba" - ] + + ], + 1 ], - "timestamp": "2026-03-23T22:57:58.607959901", + "timestamp": "2026-03-25T15:46:46.64367644", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" } }, - "Should not do anything if ambient correction is disabled in meta": { + "Should run with 'scar' ambient correction": { "content": [ [ - - ] + "versions.yml:md5,2717cb5f250a65aec0a76a456f7028ba" + ], + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "_scvi_batch", + "_scvi_labels", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + "ambient_corrected_scar" + ], + "obsm": [ + + ], + "varm": [ + "ambient_profile" + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T22:54:01.532131592", + "timestamp": "2026-03-29T11:24:02.851605031", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -99,11 +306,44 @@ "Should run with 'cellbender' ambient correction": { "content": [ [ - "versions.yml:md5,1d70371b0f0ca5e50f7ba70335f8946f", - "versions.yml:md5,e6e98e83cbc9a2924c66e901445bbc4f" - ] + + ], + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + "ambient_corrected_cellbender" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T23:00:54.238589778", + "timestamp": "2026-03-30T08:42:11.218749814", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -113,9 +353,43 @@ "content": [ [ "versions.yml:md5,0266faf0b40a7b86ec9f2b1948f8c7aa" - ] + ], + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + "ambient_corrected_soupx" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T22:56:39.961201724", + "timestamp": "2026-03-29T11:22:41.092799679", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -125,9 +399,45 @@ "content": [ [ "versions.yml:md5,2717cb5f250a65aec0a76a456f7028ba" - ] + ], + { + "n_obs": 7373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "_scvi_batch", + "_scvi_labels", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + "ambient_profile" + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-23T23:03:37.590823873", + "timestamp": "2026-03-29T11:29:53.928496596", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/subworkflows/local/celltype_assignment/tests/main.nf.test b/subworkflows/local/celltype_assignment/tests/main.nf.test index faa362f5..50a0bb48 100644 --- a/subworkflows/local/celltype_assignment/tests/main.nf.test +++ b/subworkflows/local/celltype_assignment/tests/main.nf.test @@ -30,6 +30,7 @@ nextflow_workflow { then { assert workflow.success + assert workflow.out.obs.size() >= 1 assert snapshot( workflow.out.versions, workflow.out.obs.size() diff --git a/subworkflows/local/celltype_assignment/tests/main.nf.test.snap b/subworkflows/local/celltype_assignment/tests/main.nf.test.snap index c38ded62..1766ea61 100644 --- a/subworkflows/local/celltype_assignment/tests/main.nf.test.snap +++ b/subworkflows/local/celltype_assignment/tests/main.nf.test.snap @@ -9,10 +9,10 @@ ], 2 ], - "timestamp": "2026-03-17T21:51:53.626655883", + "timestamp": "2026-03-25T15:50:21.38171952", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - stub": { @@ -60,10 +60,10 @@ ] } ], - "timestamp": "2025-07-17T10:31:35.176849323", + "timestamp": "2026-03-25T15:50:38.187327089", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/subworkflows/local/cluster/tests/main.nf.test b/subworkflows/local/cluster/tests/main.nf.test index 62a8fd4e..ed090f72 100644 --- a/subworkflows/local/cluster/tests/main.nf.test +++ b/subworkflows/local/cluster/tests/main.nf.test @@ -64,20 +64,20 @@ nextflow_workflow { then { assert workflow.success - assert snapshot(workflow.out.versions).match() workflow.out.h5ad_neighbors.each { meta, h5ad -> - def ad = anndata(h5ad) - assert ad.obsm.any { it.endsWith("_umap") } - assert "connectivities" in ad.obsp - assert "distances" in ad.obsp + def adata = anndata(h5ad) + with(adata) { + assert obsm.any { it.endsWith("_umap") } + assert "connectivities" in obsp + assert "distances" in obsp + } } workflow.out.h5ad_clustering.each { meta, h5ad -> - def obs = anndata(h5ad).obs + def adata = anndata(h5ad) def key = meta.id + "_leiden" - assert key in obs.colnames : "Expected ${key} in obs, found: ${obs.colnames}" - def n = obs.get(key).n_unique() - assert n >= 2 && n <= 50 : "Expected 2–50 clusters for ${key}, got ${n}" + assert key in adata.obs.colnames } + assert snapshot(workflow.out.versions).match() } } @@ -139,20 +139,20 @@ nextflow_workflow { then { assert workflow.success - assert snapshot(workflow.out.versions).match() workflow.out.h5ad_neighbors.each { meta, h5ad -> - def ad = anndata(h5ad) - assert ad.obsm.any { it.endsWith("_umap") } - assert "connectivities" in ad.obsp - assert "distances" in ad.obsp + def adata = anndata(h5ad) + with(adata) { + assert obsm.any { it.endsWith("_umap") } + assert "connectivities" in obsp + assert "distances" in obsp + } } workflow.out.h5ad_clustering.each { meta, h5ad -> - def obs = anndata(h5ad).obs + def adata = anndata(h5ad) def key = meta.id + "_leiden" - assert key in obs.colnames : "Expected ${key} in obs, found: ${obs.colnames}" - def n = obs.get(key).n_unique() - assert n >= 2 && n <= 50 : "Expected 2–50 clusters for ${key}, got ${n}" + assert key in adata.obs.colnames } + assert snapshot(workflow.out.versions).match() } } @@ -214,20 +214,20 @@ nextflow_workflow { then { assert workflow.success - assert snapshot(workflow.out.versions).match() workflow.out.h5ad_neighbors.each { meta, h5ad -> - def ad = anndata(h5ad) - assert ad.obsm.any { it.endsWith("_umap") } - assert "connectivities" in ad.obsp - assert "distances" in ad.obsp + def adata = anndata(h5ad) + with(adata) { + assert obsm.any { it.endsWith("_umap") } + assert "connectivities" in obsp + assert "distances" in obsp + } } workflow.out.h5ad_clustering.each { meta, h5ad -> - def obs = anndata(h5ad).obs + def adata = anndata(h5ad) def key = meta.id + "_leiden" - assert key in obs.colnames - def n = obs.get(key).n_unique() - assert n >= 2 && n <= 50 : "Expected 2–50 clusters for ${key}, got ${n}" + assert key in adata.obs.colnames } + assert snapshot(workflow.out.versions).match() } } diff --git a/subworkflows/local/combine/main.nf b/subworkflows/local/combine/main.nf index a0e22835..bd46eb85 100644 --- a/subworkflows/local/combine/main.nf +++ b/subworkflows/local/combine/main.nf @@ -27,7 +27,8 @@ workflow COMBINE { ADATA_MERGE( ch_h5ad .map { _meta, h5ad -> [[id: "merged"], h5ad] } - .groupTuple(), + .groupTuple() + .map { meta, h5ads -> [meta, h5ads.sort { a, b -> a.name <=> b.name }] }, ch_base, ) ch_var = ch_var.mix(ADATA_MERGE.out.intersect_genes) diff --git a/subworkflows/local/combine/tests/main.nf.test b/subworkflows/local/combine/tests/main.nf.test index 3a134ed1..fcaa7275 100644 --- a/subworkflows/local/combine/tests/main.nf.test +++ b/subworkflows/local/combine/tests/main.nf.test @@ -21,7 +21,7 @@ nextflow_workflow { [[id: 'test1'], file(params.pipelines_testdata_base_path + '/anndata-variations/batch_correct_name.h5ad', checkIfExists: true)], [[id: 'test2'], file(params.pipelines_testdata_base_path + '/anndata-variations/batch_correct_name.h5ad', checkIfExists: true)] ) - input[1] = channel.empty() + input[1] = channel.value([[], []]) input[2] = false input[3] = 0 input[4] = 'scvi' @@ -54,7 +54,7 @@ nextflow_workflow { [[id: 'test1'], file(params.pipelines_testdata_base_path + '/anndata-variations/batch_correct_name.h5ad', checkIfExists: true)], [[id: 'test2'], file(params.pipelines_testdata_base_path + '/anndata-variations/batch_correct_name.h5ad', checkIfExists: true)] ) - input[1] = channel.empty() + input[1] = channel.value([[], []]) input[2] = false input[3] = 0 input[4] = 'scvi' @@ -69,8 +69,13 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.h5ad[0][1]) assert workflow.success - assert snapshot(workflow.out).match() + assert "batch" in adata.obs.colnames + assert snapshot( + workflow.out.versions.collect { path(it).yaml }, + adata.yaml + ).match() } } diff --git a/subworkflows/local/combine/tests/main.nf.test.snap b/subworkflows/local/combine/tests/main.nf.test.snap index bc108952..1a2b6ceb 100644 --- a/subworkflows/local/combine/tests/main.nf.test.snap +++ b/subworkflows/local/combine/tests/main.nf.test.snap @@ -3,106 +3,161 @@ "content": [ { "0": [ - + [ + { + "id": "merged" + }, + "merged_outer.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ], "1": [ - + [ + { + "id": "merged" + }, + "merged_inner.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ], "2": [ - + [ + { + "id": "scvi", + "integration": "scvi" + }, + "scvi.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ], "3": [ - + "gene_intersection.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "4": [ ], "5": [ - + "X_scvi.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "6": [ - + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ], "h5ad": [ - + [ + { + "id": "merged" + }, + "merged_outer.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ], "h5ad_inner": [ - + [ + { + "id": "merged" + }, + "merged_inner.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ], "integrations": [ - + [ + { + "id": "scvi", + "integration": "scvi" + }, + "scvi.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ], "obs": [ ], "obsm": [ - + "X_scvi.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "var": [ - + "gene_intersection.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "versions": [ - + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ] } ], + "timestamp": "2026-03-29T13:32:53.623653313", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2026-01-16T22:32:56.838829264" + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } }, "Should run without failures - without base": { "content": [ + [ + { + "COMBINE:INTEGRATE:SCVITOOLS_SCVI": { + "scvi": "1.3.3" + } + }, + { + "COMBINE:INTEGRATE:SCANPY_HVGS": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "COMBINE:ADATA_MERGE": { + "anndata": "0.12.10", + "python": "3.13.12", + "scanpy": "1.12", + "scipy": "1.17.1" + } + }, + { + "COMBINE:INTEGRATE:SCANPY_FILTER": { + "python": "3.13.12", + "scanpy": "1.12" + } + } + ], { - "0": [ - - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - - ], - "5": [ - - ], - "6": [ - - ], - "h5ad": [ - - ], - "h5ad_inner": [ - + "n_obs": 25880, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + "counts" ], - "integrations": [ + "obsm": [ ], - "obs": [ + "varm": [ ], - "obsm": [ + "obsp": [ ], - "var": [ + "varp": [ ], - "versions": [ + "uns": [ ] } ], + "timestamp": "2026-03-29T14:31:17.652923187", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2026-01-16T22:33:05.898148109" + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } } } \ No newline at end of file diff --git a/subworkflows/local/differential_expression/tests/main.nf.test b/subworkflows/local/differential_expression/tests/main.nf.test index 290955ee..4ca191e9 100644 --- a/subworkflows/local/differential_expression/tests/main.nf.test +++ b/subworkflows/local/differential_expression/tests/main.nf.test @@ -25,7 +25,12 @@ nextflow_workflow { then { assert workflow.success - assert snapshot(workflow.out).match() + assert workflow.out.uns.size() >= 1 + assert workflow.out.multiqc_files.size() >= 1 + assert workflow.out.uns.any { file(it).name.endsWith("_characteristic_genes.pkl") } + assert snapshot( + workflow.out.versions.collect { path(it).yaml } + ).match() } } @@ -48,7 +53,12 @@ nextflow_workflow { then { assert workflow.success - assert snapshot(workflow.out).match() + assert workflow.out.uns.size() >= 1 + assert workflow.out.multiqc_files.size() >= 1 + assert workflow.out.uns.any { file(it).name.endsWith("_characteristic_genes.pkl") } + assert snapshot( + workflow.out.versions.collect { path(it).yaml } + ).match() } } diff --git a/subworkflows/local/differential_expression/tests/main.nf.test.snap b/subworkflows/local/differential_expression/tests/main.nf.test.snap index c2cda462..11574c49 100644 --- a/subworkflows/local/differential_expression/tests/main.nf.test.snap +++ b/subworkflows/local/differential_expression/tests/main.nf.test.snap @@ -1,118 +1,122 @@ { "Should run differential expression with leiden clustering": { "content": [ - { - "0": [ - "condition:leiden:0_characteristic_genes.pkl:md5,d6be6f9447ed67f6bb5d5df1acf22b86", - "condition:leiden:10_characteristic_genes.pkl:md5,7fd29daa10b8008e16f5c9639a402587", - "condition:leiden:11_characteristic_genes.pkl:md5,9e96aaf44b8d0f0c26a5bda59f63b096", - "condition:leiden:1_characteristic_genes.pkl:md5,f2d38b8ddd01bfd820945fc25fb15f06", - "condition:leiden:2_characteristic_genes.pkl:md5,184a05f08b741d4a0b6e0ee17a9609ec", - "condition:leiden:3_characteristic_genes.pkl:md5,b1bcd5c5d3332c121b01d24cb46a2334", - "condition:leiden:4_characteristic_genes.pkl:md5,15bc73779b616c2276eeedc94bd448b6", - "condition:leiden:5_characteristic_genes.pkl:md5,f314433d06e822b6bcdcccfe1635d32c", - "condition:leiden:6_characteristic_genes.pkl:md5,96e0edc86bf4df08008ff1af3cc10522", - "condition:leiden:7_characteristic_genes.pkl:md5,91ae9da4509aaddb59fb79505f6d37af", - "condition:leiden:8_characteristic_genes.pkl:md5,fae74f6935930804cd95b1e62b393f44", - "condition:leiden:9_characteristic_genes.pkl:md5,635e5ca72000437e64a458a4fc89dc4b", - "leiden:condition:Disease_characteristic_genes.pkl:md5,029b3b97860e8ba00b2b7701c0ef4836", - "leiden:condition:Healthy_characteristic_genes.pkl:md5,f638b9a63be41a80c24367c329ad9c92", - "leiden:condition:Treated_characteristic_genes.pkl:md5,5761aff9c5fff490dee108a0127a8af4", - "leiden_characteristic_genes.pkl:md5,e387d9c66878055c92c3d4de44cec54a" - ], - "1": [ - "condition:leiden:0_characteristic_genes_mqc.json:md5,0d9173af58f05a6a017b7bf62a8ab6a8", - "condition:leiden:10_characteristic_genes_mqc.json:md5,1c42e764ba8a629df84a9f6a7b7cb889", - "condition:leiden:11_characteristic_genes_mqc.json:md5,0778f0f0cd0bd3edf2317a7b557ce952", - "condition:leiden:1_characteristic_genes_mqc.json:md5,a3b5df45edbd4dcc5fb3cf73864f4e76", - "condition:leiden:2_characteristic_genes_mqc.json:md5,1656d5018a65811325f95449b34f302b", - "condition:leiden:3_characteristic_genes_mqc.json:md5,1ce90ec438f14d33bebd26db002544cb", - "condition:leiden:4_characteristic_genes_mqc.json:md5,375733d6a0a018ad6ef0776d5039fb64", - "condition:leiden:5_characteristic_genes_mqc.json:md5,17df859608e296b50492d4fbcaff66f2", - "condition:leiden:6_characteristic_genes_mqc.json:md5,21ec62fdde2bb968127d4f8b5acabaa7", - "condition:leiden:7_characteristic_genes_mqc.json:md5,d1fa8613daecf0aafb769d14c9be39d7", - "condition:leiden:8_characteristic_genes_mqc.json:md5,2602bc68c47188fda2742ad9f222cf4e", - "condition:leiden:9_characteristic_genes_mqc.json:md5,c968bea56d8763520f0d68de394ccb79", - "leiden:condition:Disease_characteristic_genes_mqc.json:md5,46ee7c6e656b2419d618650d7c67d0b0", - "leiden:condition:Healthy_characteristic_genes_mqc.json:md5,cc6e0fe227a84f1036f893945604dcc2", - "leiden:condition:Treated_characteristic_genes_mqc.json:md5,a7a78be0d9f0655ae8a5cae77daf0a74", - "leiden_characteristic_genes_mqc.json:md5,875d02a88fd8f4f0c0462f4da112d1ed" - ], - "2": [ - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934" - ], - "multiqc_files": [ - "condition:leiden:0_characteristic_genes_mqc.json:md5,0d9173af58f05a6a017b7bf62a8ab6a8", - "condition:leiden:10_characteristic_genes_mqc.json:md5,1c42e764ba8a629df84a9f6a7b7cb889", - "condition:leiden:11_characteristic_genes_mqc.json:md5,0778f0f0cd0bd3edf2317a7b557ce952", - "condition:leiden:1_characteristic_genes_mqc.json:md5,a3b5df45edbd4dcc5fb3cf73864f4e76", - "condition:leiden:2_characteristic_genes_mqc.json:md5,1656d5018a65811325f95449b34f302b", - "condition:leiden:3_characteristic_genes_mqc.json:md5,1ce90ec438f14d33bebd26db002544cb", - "condition:leiden:4_characteristic_genes_mqc.json:md5,375733d6a0a018ad6ef0776d5039fb64", - "condition:leiden:5_characteristic_genes_mqc.json:md5,17df859608e296b50492d4fbcaff66f2", - "condition:leiden:6_characteristic_genes_mqc.json:md5,21ec62fdde2bb968127d4f8b5acabaa7", - "condition:leiden:7_characteristic_genes_mqc.json:md5,d1fa8613daecf0aafb769d14c9be39d7", - "condition:leiden:8_characteristic_genes_mqc.json:md5,2602bc68c47188fda2742ad9f222cf4e", - "condition:leiden:9_characteristic_genes_mqc.json:md5,c968bea56d8763520f0d68de394ccb79", - "leiden:condition:Disease_characteristic_genes_mqc.json:md5,46ee7c6e656b2419d618650d7c67d0b0", - "leiden:condition:Healthy_characteristic_genes_mqc.json:md5,cc6e0fe227a84f1036f893945604dcc2", - "leiden:condition:Treated_characteristic_genes_mqc.json:md5,a7a78be0d9f0655ae8a5cae77daf0a74", - "leiden_characteristic_genes_mqc.json:md5,875d02a88fd8f4f0c0462f4da112d1ed" - ], - "uns": [ - "condition:leiden:0_characteristic_genes.pkl:md5,d6be6f9447ed67f6bb5d5df1acf22b86", - "condition:leiden:10_characteristic_genes.pkl:md5,7fd29daa10b8008e16f5c9639a402587", - "condition:leiden:11_characteristic_genes.pkl:md5,9e96aaf44b8d0f0c26a5bda59f63b096", - "condition:leiden:1_characteristic_genes.pkl:md5,f2d38b8ddd01bfd820945fc25fb15f06", - "condition:leiden:2_characteristic_genes.pkl:md5,184a05f08b741d4a0b6e0ee17a9609ec", - "condition:leiden:3_characteristic_genes.pkl:md5,b1bcd5c5d3332c121b01d24cb46a2334", - "condition:leiden:4_characteristic_genes.pkl:md5,15bc73779b616c2276eeedc94bd448b6", - "condition:leiden:5_characteristic_genes.pkl:md5,f314433d06e822b6bcdcccfe1635d32c", - "condition:leiden:6_characteristic_genes.pkl:md5,96e0edc86bf4df08008ff1af3cc10522", - "condition:leiden:7_characteristic_genes.pkl:md5,91ae9da4509aaddb59fb79505f6d37af", - "condition:leiden:8_characteristic_genes.pkl:md5,fae74f6935930804cd95b1e62b393f44", - "condition:leiden:9_characteristic_genes.pkl:md5,635e5ca72000437e64a458a4fc89dc4b", - "leiden:condition:Disease_characteristic_genes.pkl:md5,029b3b97860e8ba00b2b7701c0ef4836", - "leiden:condition:Healthy_characteristic_genes.pkl:md5,f638b9a63be41a80c24367c329ad9c92", - "leiden:condition:Treated_characteristic_genes.pkl:md5,5761aff9c5fff490dee108a0127a8af4", - "leiden_characteristic_genes.pkl:md5,e387d9c66878055c92c3d4de44cec54a" - ], - "versions": [ - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934" - ] - } + [ + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + } + ] ], - "timestamp": "2026-03-22T10:30:59.698386674", + "timestamp": "2026-03-29T13:30:15.199583154", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -120,82 +124,80 @@ }, "Should run differential expression with label column": { "content": [ - { - "0": [ - "condition:label:B_cell_characteristic_genes.pkl:md5,2f99d61c2954906ec104799264fed6d0", - "condition:label:Cd4_t_characteristic_genes.pkl:md5,a38d1c237a97f99759d821f73bba5719", - "condition:label:Cd8_t_characteristic_genes.pkl:md5,776d565572bb6a1eddfd5567a69c0dc6", - "condition:label:Monocyte_characteristic_genes.pkl:md5,0e709c29bc3a61ba316048e2c8d61da8", - "condition:label:Nk_cell_characteristic_genes.pkl:md5,e91f318cec5509beb1641bf17e272523", - "condition:label:T_cell_characteristic_genes.pkl:md5,fca6d6c9ccd508cdcb5c718a2a4c25dd", - "label:condition:Disease_characteristic_genes.pkl:md5,dda81972668c2b9a164bb925930a9489", - "label:condition:Healthy_characteristic_genes.pkl:md5,f8b17a3fc7c93037a74b83f5d2a30622", - "label:condition:Treated_characteristic_genes.pkl:md5,b477570c5ae47b5239891344904d946d", - "label_characteristic_genes.pkl:md5,859c3b54b1b39be82f92048a60dab7c4" - ], - "1": [ - "condition:label:B_cell_characteristic_genes_mqc.json:md5,820db31f71bd14483b91ecf5e7656de4", - "condition:label:Cd4_t_characteristic_genes_mqc.json:md5,2af14cf72e88e19a5d9ce15dd7025727", - "condition:label:Cd8_t_characteristic_genes_mqc.json:md5,52203e4f1b841cb16e2b8ed719de1492", - "condition:label:Monocyte_characteristic_genes_mqc.json:md5,a88fa9d3780b4184d291d924a4830b9e", - "condition:label:Nk_cell_characteristic_genes_mqc.json:md5,51feda33f6932ea1429ff87f153e2aa0", - "condition:label:T_cell_characteristic_genes_mqc.json:md5,99f02e1eca31c65a84b9dbf57d05bd7a", - "label:condition:Disease_characteristic_genes_mqc.json:md5,5474c0aa0b23b308e0bbfa09cf67dc7d", - "label:condition:Healthy_characteristic_genes_mqc.json:md5,4e73669edf2a51df4e85f9e308e69b69", - "label:condition:Treated_characteristic_genes_mqc.json:md5,845060dadf420e9c9ee032989690c9e7", - "label_characteristic_genes_mqc.json:md5,dfa0f0eb363917eb443b7dbbde95a20f" - ], - "2": [ - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934" - ], - "multiqc_files": [ - "condition:label:B_cell_characteristic_genes_mqc.json:md5,820db31f71bd14483b91ecf5e7656de4", - "condition:label:Cd4_t_characteristic_genes_mqc.json:md5,2af14cf72e88e19a5d9ce15dd7025727", - "condition:label:Cd8_t_characteristic_genes_mqc.json:md5,52203e4f1b841cb16e2b8ed719de1492", - "condition:label:Monocyte_characteristic_genes_mqc.json:md5,a88fa9d3780b4184d291d924a4830b9e", - "condition:label:Nk_cell_characteristic_genes_mqc.json:md5,51feda33f6932ea1429ff87f153e2aa0", - "condition:label:T_cell_characteristic_genes_mqc.json:md5,99f02e1eca31c65a84b9dbf57d05bd7a", - "label:condition:Disease_characteristic_genes_mqc.json:md5,5474c0aa0b23b308e0bbfa09cf67dc7d", - "label:condition:Healthy_characteristic_genes_mqc.json:md5,4e73669edf2a51df4e85f9e308e69b69", - "label:condition:Treated_characteristic_genes_mqc.json:md5,845060dadf420e9c9ee032989690c9e7", - "label_characteristic_genes_mqc.json:md5,dfa0f0eb363917eb443b7dbbde95a20f" - ], - "uns": [ - "condition:label:B_cell_characteristic_genes.pkl:md5,2f99d61c2954906ec104799264fed6d0", - "condition:label:Cd4_t_characteristic_genes.pkl:md5,a38d1c237a97f99759d821f73bba5719", - "condition:label:Cd8_t_characteristic_genes.pkl:md5,776d565572bb6a1eddfd5567a69c0dc6", - "condition:label:Monocyte_characteristic_genes.pkl:md5,0e709c29bc3a61ba316048e2c8d61da8", - "condition:label:Nk_cell_characteristic_genes.pkl:md5,e91f318cec5509beb1641bf17e272523", - "condition:label:T_cell_characteristic_genes.pkl:md5,fca6d6c9ccd508cdcb5c718a2a4c25dd", - "label:condition:Disease_characteristic_genes.pkl:md5,dda81972668c2b9a164bb925930a9489", - "label:condition:Healthy_characteristic_genes.pkl:md5,f8b17a3fc7c93037a74b83f5d2a30622", - "label:condition:Treated_characteristic_genes.pkl:md5,b477570c5ae47b5239891344904d946d", - "label_characteristic_genes.pkl:md5,859c3b54b1b39be82f92048a60dab7c4" - ], - "versions": [ - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934", - "versions.yml:md5,c4e56a7a79e312d6f945d4913899b934" - ] - } + [ + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + } + ] ], - "timestamp": "2026-03-17T22:20:42.142007254", + "timestamp": "2026-03-29T13:31:13.926825588", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/subworkflows/local/doublet_detection/tests/main.nf.test b/subworkflows/local/doublet_detection/tests/main.nf.test index 26fb4f2b..fc745f68 100644 --- a/subworkflows/local/doublet_detection/tests/main.nf.test +++ b/subworkflows/local/doublet_detection/tests/main.nf.test @@ -28,10 +28,8 @@ nextflow_workflow { } then { - assertAll( - { assert workflow.success }, - { assert workflow.trace.tasks().size() == 0 } - ) + assert workflow.success + assert workflow.trace.tasks().size() == 0 } } @@ -58,14 +56,15 @@ nextflow_workflow { } then { - assertAll( - { assert workflow.success }, - { assert anndata(workflow.out.h5ad[0][1]).n_obs > 5960 }, - { assert anndata(workflow.out.h5ad[0][1]).n_obs < 5985 }, - { assert snapshot( - workflow.out.versions, - ).match() } - ) + def adata = anndata(workflow.out.h5ad[0][1]) + + assert workflow.success + assert adata.n_obs > 5960 + assert adata.n_obs < 5985 + assert snapshot( + workflow.out.versions.collect { path(it).yaml }, + adata.yaml + ).match() } } @@ -93,10 +92,8 @@ nextflow_workflow { } then { - assertAll( - { assert workflow.success }, - { assert snapshot(workflow.out).match() } - ) + assert workflow.success + assert snapshot(workflow.out).match() } } diff --git a/subworkflows/local/doublet_detection/tests/main.nf.test.snap b/subworkflows/local/doublet_detection/tests/main.nf.test.snap index 0930bd3b..d7339e7b 100644 --- a/subworkflows/local/doublet_detection/tests/main.nf.test.snap +++ b/subworkflows/local/doublet_detection/tests/main.nf.test.snap @@ -2,14 +2,61 @@ "Should run with all methods except doubletdetection": { "content": [ [ - "versions.yml:md5,09080fed8361c8fcf41d5527c339deed", - "versions.yml:md5,413d1a693de9ab89500219638de87ee2" - ] + { + "DOUBLET_DETECTION:DOUBLET_REMOVAL": { + "anndata": "0.12.10", + "matplotlib": "3.10.8", + "pandas": "2.3.3", + "python": "3.13.12", + "upsetplot": "0.9.0" + } + }, + { + "DOUBLET_DETECTION:SCANPY_SCRUBLET": { + "python": "3.12.11", + "scanpy": "1.11.2" + } + } + ], + { + "n_obs": 5968, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } ], - "timestamp": "2026-03-16T16:26:16.794928707", + "timestamp": "2026-03-29T11:19:54.674217844", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - stub": { diff --git a/subworkflows/local/finalize/main.nf b/subworkflows/local/finalize/main.nf index 4771260d..8aa2a5bf 100644 --- a/subworkflows/local/finalize/main.nf +++ b/subworkflows/local/finalize/main.nf @@ -40,5 +40,6 @@ workflow FINALIZE { } emit: - versions = ch_versions // channel: [ versions.yml ] + h5ad = ADATA_EXTEND.out.h5ad // channel: [ meta, h5ad ] + versions = ch_versions // channel: [ versions.yml ] } diff --git a/subworkflows/local/finalize/tests/main.nf.test b/subworkflows/local/finalize/tests/main.nf.test index b6fea76a..3e96f1fc 100644 --- a/subworkflows/local/finalize/tests/main.nf.test +++ b/subworkflows/local/finalize/tests/main.nf.test @@ -63,8 +63,18 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.h5ad[0][1]) assert workflow.success - assert snapshot(workflow.out).match() + with(adata) { + assert "scvi-global-1.0_leiden" in obs.colnames + assert "X_scvi" in obsm + assert "scvi-global-1.0_paga" in uns + } + assert snapshot( + workflow.out.h5ad, + workflow.out.versions.collect { path(it).yaml }, + adata.yaml + ).match() } } @@ -125,8 +135,13 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.h5ad[0][1]) assert workflow.success - assert snapshot(workflow.out).match() + assert snapshot( + workflow.out.h5ad, + workflow.out.versions.collect { path(it).yaml }, + adata.yaml + ).match() } } @@ -193,8 +208,13 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.h5ad[0][1]) assert workflow.success - assert snapshot(workflow.out).match() + assert snapshot( + workflow.out.h5ad, + workflow.out.versions.collect { path(it).yaml }, + adata.yaml + ).match() } } diff --git a/subworkflows/local/finalize/tests/main.nf.test.snap b/subworkflows/local/finalize/tests/main.nf.test.snap index 31d1939a..56c53a1e 100644 --- a/subworkflows/local/finalize/tests/main.nf.test.snap +++ b/subworkflows/local/finalize/tests/main.nf.test.snap @@ -1,18 +1,77 @@ { "Should run without failures - with fragments": { "content": [ + [ + [ + { + "id": "test" + }, + "test.h5ad:md5,88250dce39d3ebc42b13639bb9a9bc81" + ] + ], + [ + { + "FINALIZE:ADATA_EXTEND": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "pandas": "2.3.3", + "python": "3.13.12" + } + }, + { + "FINALIZE:ADATA_TORDS": { + "anndataR": "1.0.2" + } + } + ], { - "0": [ - "versions.yml:md5,cbeebeb2116035eeb1a2c11972c74d79", - "versions.yml:md5,fe9c91eed91a74cf24e85fd6f7c3932c" + "n_obs": 23373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "celltypist:Adult_Human_Skin", + "celltypist:Adult_Human_Skin:conf", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "scvi-global-1.0_leiden", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + ], - "versions": [ - "versions.yml:md5,cbeebeb2116035eeb1a2c11972c74d79", - "versions.yml:md5,fe9c91eed91a74cf24e85fd6f7c3932c" + "obsm": [ + "X_scvi" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + "scvi-global-1.0_paga" ] } ], - "timestamp": "2026-03-17T22:18:57.499343763", + "timestamp": "2026-03-29T11:12:29.040402189", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -20,20 +79,84 @@ }, "Should run without failures - with prep_cellxgene": { "content": [ + [ + [ + { + "id": "test" + }, + "test.h5ad:md5,f1586170686d73b8143e95aad0f331ce" + ] + ], + [ + { + "FINALIZE:ADATA_PREPCELLXGENE": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "FINALIZE:ADATA_EXTEND": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "pandas": "2.3.3", + "python": "3.13.12" + } + }, + { + "FINALIZE:ADATA_TORDS": { + "anndataR": "1.0.2" + } + } + ], { - "0": [ - "versions.yml:md5,1e7c2d22af9afd605d7fdc65a5ece3b7", - "versions.yml:md5,cbeebeb2116035eeb1a2c11972c74d79", - "versions.yml:md5,fe9c91eed91a74cf24e85fd6f7c3932c" + "n_obs": 23373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "celltypist:Adult_Human_Skin", + "celltypist:Adult_Human_Skin:conf", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + ], - "versions": [ - "versions.yml:md5,1e7c2d22af9afd605d7fdc65a5ece3b7", - "versions.yml:md5,cbeebeb2116035eeb1a2c11972c74d79", - "versions.yml:md5,fe9c91eed91a74cf24e85fd6f7c3932c" + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + ] } ], - "timestamp": "2026-03-17T22:20:50.85306115", + "timestamp": "2026-03-29T11:13:56.762622049", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -43,54 +166,144 @@ "content": [ { "0": [ + [ + { + "id": "test" + }, + "test.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ], + "h5ad": [ + [ + { + "id": "test" + }, + "test.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], "versions": [ "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ] } ], - "timestamp": "2026-01-16T22:46:55.506826803", + "timestamp": "2026-03-28T18:21:21.411777638", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } }, "Should run without failures - no fragments - stub": { "content": [ { "0": [ + [ + { + "id": "test" + }, + "test.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ], + "h5ad": [ + [ + { + "id": "test" + }, + "test.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], "versions": [ "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ] } ], - "timestamp": "2026-01-16T22:47:50.084502894", + "timestamp": "2026-03-28T18:22:08.331764694", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } }, "Should run without failures - no fragments": { "content": [ + [ + [ + { + "id": "test" + }, + "test.h5ad:md5,f1586170686d73b8143e95aad0f331ce" + ] + ], + [ + { + "FINALIZE:ADATA_EXTEND": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "pandas": "2.3.3", + "python": "3.13.12" + } + }, + { + "FINALIZE:ADATA_TORDS": { + "anndataR": "1.0.2" + } + } + ], { - "0": [ - "versions.yml:md5,cbeebeb2116035eeb1a2c11972c74d79", - "versions.yml:md5,fe9c91eed91a74cf24e85fd6f7c3932c" + "n_obs": 23373, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "celltypist:Adult_Human_Skin", + "celltypist:Adult_Human_Skin:conf", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + ], - "versions": [ - "versions.yml:md5,cbeebeb2116035eeb1a2c11972c74d79", - "versions.yml:md5,fe9c91eed91a74cf24e85fd6f7c3932c" + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + ] } ], - "timestamp": "2026-03-17T22:19:50.750328034", + "timestamp": "2026-03-29T11:13:12.249331199", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/subworkflows/local/integrate/tests/main.nf.test b/subworkflows/local/integrate/tests/main.nf.test index 8cc58b83..537e9bbf 100644 --- a/subworkflows/local/integrate/tests/main.nf.test +++ b/subworkflows/local/integrate/tests/main.nf.test @@ -67,11 +67,13 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.integrations[0][1]) assert workflow.success + assert "X_emb" in adata.obsm assert snapshot( - workflow.out.versions + workflow.out.versions, + adata.yaml ).match() - assert "X_emb" in anndata(workflow.out.integrations[0][1]).obsm } } @@ -136,8 +138,17 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.integrations[0][1]) assert workflow.success - assert snapshot(workflow.out).match() + with(adata) { + assert "X_pca" in obsm + assert "connectivities" in obsp + assert "distances" in obsp + } + assert snapshot( + workflow.out.versions, + adata.yaml + ).match() } } @@ -202,11 +213,13 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.integrations[0][1]) assert workflow.success + assert "X_emb" in adata.obsm assert snapshot( - workflow.out.versions + workflow.out.versions, + adata.yaml ).match() - assert "X_emb" in anndata(workflow.out.integrations[0][1]).obsm } } diff --git a/subworkflows/local/integrate/tests/main.nf.test.snap b/subworkflows/local/integrate/tests/main.nf.test.snap index 3060642c..be6b7709 100644 --- a/subworkflows/local/integrate/tests/main.nf.test.snap +++ b/subworkflows/local/integrate/tests/main.nf.test.snap @@ -48,10 +48,10 @@ ] } ], - "timestamp": "2026-01-16T22:34:13.677132566", + "timestamp": "2026-03-28T23:05:37.694952307", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } }, "Should run without failures - bbknn - stub": { @@ -103,10 +103,10 @@ ] } ], - "timestamp": "2026-01-16T22:35:18.22501323", + "timestamp": "2026-03-25T15:47:40.215608271", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } }, "Should run without failures - combat": { @@ -115,9 +115,63 @@ "versions.yml:md5,20020d8c9cf585aaa75dd5a14aa5d3ae", "versions.yml:md5,a6c1e0a77e0d31423a9d77edba85127d", "versions.yml:md5,d28b65c4c18c54e1abc34040b584b823" - ] + ], + { + "n_obs": 12940, + "n_vars": 2077, + "obs": { + "index": "_index", + "columns": [ + "batch", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + "dispersions", + "dispersions_norm", + "highly_variable", + "mean_counts", + "means", + "mt", + "n_cells", + "n_cells_by_counts", + "n_counts", + "pct_dropout_by_counts", + "symbols", + "total_counts" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + "X_emb", + "X_pca" + ], + "varm": [ + "PCs" + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + "hvg", + "log1p", + "pca" + ] + } ], - "timestamp": "2026-03-22T14:55:07.151113899", + "timestamp": "2026-03-29T11:24:13.787124189", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -168,10 +222,10 @@ ] } ], - "timestamp": "2026-01-16T22:37:23.996766665", + "timestamp": "2026-03-28T23:09:49.392744851", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } }, "Should run without failures - combat - stub": { @@ -223,10 +277,10 @@ ] } ], - "timestamp": "2026-01-16T22:36:29.062441577", + "timestamp": "2026-03-25T15:49:26.334091777", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.4", + "nextflow": "25.10.2" } }, "Should run without failures - harmony": { @@ -235,9 +289,61 @@ "versions.yml:md5,20020d8c9cf585aaa75dd5a14aa5d3ae", "versions.yml:md5,d28b65c4c18c54e1abc34040b584b823", "versions.yml:md5,f838f281f13db0dd578a991df1d8b57c" - ] + ], + { + "n_obs": 12940, + "n_vars": 2077, + "obs": { + "index": "_index", + "columns": [ + "batch", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + "dispersions", + "dispersions_norm", + "highly_variable", + "mean_counts", + "means", + "mt", + "n_cells", + "n_cells_by_counts", + "n_counts", + "pct_dropout_by_counts", + "symbols", + "total_counts" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + "X_emb" + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + "hvg", + "log1p" + ] + } ], - "timestamp": "2026-03-22T13:40:54.235838286", + "timestamp": "2026-03-29T11:19:08.193313955", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -245,54 +351,68 @@ }, "Should run without failures - bbknn": { "content": [ + [ + "versions.yml:md5,20020d8c9cf585aaa75dd5a14aa5d3ae", + "versions.yml:md5,ccf730637c4c61a84ac4a002bf9832e0", + "versions.yml:md5,d28b65c4c18c54e1abc34040b584b823" + ], { - "0": [ - [ - { - "id": "bbknn" - }, - "bbknn.h5ad:md5,ed856f9046e0bc4e313697ca4aabcf04" + "n_obs": 12940, + "n_vars": 2077, + "obs": { + "index": "_index", + "columns": [ + "batch", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "total_counts", + "total_counts_mt" ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,20020d8c9cf585aaa75dd5a14aa5d3ae", - "versions.yml:md5,ccf730637c4c61a84ac4a002bf9832e0", - "versions.yml:md5,d28b65c4c18c54e1abc34040b584b823" - ], - "integrations": [ - [ - { - "id": "bbknn" - }, - "bbknn.h5ad:md5,ed856f9046e0bc4e313697ca4aabcf04" + }, + "var": { + "index": "_index", + "columns": [ + "dispersions", + "dispersions_norm", + "highly_variable", + "mean_counts", + "means", + "mt", + "n_cells", + "n_cells_by_counts", + "n_counts", + "pct_dropout_by_counts", + "symbols", + "total_counts" ] - ], - "obs": [ - + }, + "layers": [ + "counts" ], "obsm": [ - + "X_pca" ], - "var": [ + "varm": [ + "PCs" + ], + "obsp": [ + "connectivities", + "distances" + ], + "varp": [ ], - "versions": [ - "versions.yml:md5,20020d8c9cf585aaa75dd5a14aa5d3ae", - "versions.yml:md5,ccf730637c4c61a84ac4a002bf9832e0", - "versions.yml:md5,d28b65c4c18c54e1abc34040b584b823" + "uns": [ + "hvg", + "log1p", + "neighbors", + "pca" ] } ], - "timestamp": "2026-03-17T22:22:18.579980166", + "timestamp": "2026-03-29T11:22:31.479708062", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/subworkflows/local/per_group/tests/main.nf.test b/subworkflows/local/per_group/tests/main.nf.test index 30783857..0e07b0e9 100644 --- a/subworkflows/local/per_group/tests/main.nf.test +++ b/subworkflows/local/per_group/tests/main.nf.test @@ -7,6 +7,36 @@ nextflow_workflow { tag "subworkflows" tag "subworkflows_local" + test("Should run without failures - PAGA only - stub") { + + options '-stub' + + when { + params { + outdir = "$outputDir" + skip_liana = true + skip_rankgenesgroups = true + } + workflow { + """ + input[0] = channel.of([ + [id: 'test', obs_key: 'leiden', condition_col: 'condition'], + file(params.pipelines_testdata_base_path + '/pbmc/with_label_and_condition_pca.h5ad', checkIfExists: true) + ]) + input[1] = channel.empty() + input[2] = true + input[3] = true + """ + } + } + + then { + assert workflow.success + assert snapshot(workflow.out).match() + } + + } + test("Should run without failures - PAGA only") { when { @@ -28,6 +58,43 @@ nextflow_workflow { } } + then { + assert workflow.success + // PAGA produces exactly one uns pkl + assert workflow.out.uns.size() == 1 + assert workflow.out.uns.any { file(it).name == "test_paga.pkl" } + assert workflow.out.multiqc_files.size() == 1 + assert snapshot( + workflow.out.versions.collect { path(it).yaml } + ).match() + } + + } + + test("Should run without failures - full run - stub") { + + options '-stub' + + when { + params { + outdir = "$outputDir" + skip_liana = false + skip_rankgenesgroups = false + } + workflow { + """ + def h5ad = channel.of([ + [id: 'test', obs_key: 'leiden', condition_col: 'condition'], + file(params.pipelines_testdata_base_path + '/pbmc/with_label_and_condition_pca.h5ad', checkIfExists: true) + ]) + input[0] = h5ad + input[1] = h5ad + input[2] = false + input[3] = false + """ + } + } + then { assert workflow.success assert snapshot(workflow.out).match() @@ -59,7 +126,14 @@ nextflow_workflow { then { assert workflow.success - assert snapshot(workflow.out).match() + // PAGA + LIANA + RANKGENESGROUPS all produce uns pkls + assert workflow.out.uns.size() >= 1 + assert workflow.out.uns.any { file(it).name == "test_paga.pkl" } + assert workflow.out.uns.any { file(it).name == "test_liana.pkl" } + assert workflow.out.multiqc_files.size() >= 1 + assert snapshot( + workflow.out.versions.collect { path(it).yaml } + ).match() } } diff --git a/subworkflows/local/per_group/tests/main.nf.test.snap b/subworkflows/local/per_group/tests/main.nf.test.snap index 5c47fe4a..a1891678 100644 --- a/subworkflows/local/per_group/tests/main.nf.test.snap +++ b/subworkflows/local/per_group/tests/main.nf.test.snap @@ -1,157 +1,308 @@ { "Should run without failures - PAGA only": { + "content": [ + [ + { + "PER_GROUP:SCANPY_PAGA": { + "python": "3.13.12", + "scanpy": "1.12" + } + } + ] + ], + "timestamp": "2026-03-29T13:29:55.686223135", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } + }, + "Should run without failures - PAGA only - stub": { "content": [ { "0": [ - "test_paga.pkl:md5,fbd4ae54e51678480c8c4712a9aad0c8" + "test_paga.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "1": [ - "test_paga_mqc.json:md5,71c52f6ea9306b6763abd0496e55fe98" + "test_paga_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e" ], "2": [ - "versions.yml:md5,7d65ff4a31af5f58251f2f57320c8c94" + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ], "multiqc_files": [ - "test_paga_mqc.json:md5,71c52f6ea9306b6763abd0496e55fe98" + "test_paga_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e" ], "uns": [ - "test_paga.pkl:md5,fbd4ae54e51678480c8c4712a9aad0c8" + "test_paga.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "versions": [ - "versions.yml:md5,7d65ff4a31af5f58251f2f57320c8c94" + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ] } ], - "timestamp": "2026-03-22T16:22:14.976995704", + "timestamp": "2026-03-29T13:27:01.860499372", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" } }, "Should run without failures - full run": { + "content": [ + [ + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "PER_GROUP:DIFFERENTIAL_EXPRESSION:SCANPY_RANKGENESGROUPS": { + "pandas": "2.3.3", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "liana": "1.6.1", + "python": "3.12.12", + "scanpy": "1.11.5" + }, + { + "PER_GROUP:SCANPY_PAGA": { + "python": "3.13.12", + "scanpy": "1.12" + } + } + ] + ], + "timestamp": "2026-03-29T13:32:00.149772102", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } + }, + "Should run without failures - full run - stub": { "content": [ { "0": [ - "condition:leiden:0_characteristic_genes.pkl:md5,d6be6f9447ed67f6bb5d5df1acf22b86", - "condition:leiden:10_characteristic_genes.pkl:md5,7fd29daa10b8008e16f5c9639a402587", - "condition:leiden:11_characteristic_genes.pkl:md5,9e96aaf44b8d0f0c26a5bda59f63b096", - "condition:leiden:1_characteristic_genes.pkl:md5,f2d38b8ddd01bfd820945fc25fb15f06", - "condition:leiden:2_characteristic_genes.pkl:md5,184a05f08b741d4a0b6e0ee17a9609ec", - "condition:leiden:3_characteristic_genes.pkl:md5,b1bcd5c5d3332c121b01d24cb46a2334", - "condition:leiden:4_characteristic_genes.pkl:md5,15bc73779b616c2276eeedc94bd448b6", - "condition:leiden:5_characteristic_genes.pkl:md5,f314433d06e822b6bcdcccfe1635d32c", - "condition:leiden:6_characteristic_genes.pkl:md5,96e0edc86bf4df08008ff1af3cc10522", - "condition:leiden:7_characteristic_genes.pkl:md5,91ae9da4509aaddb59fb79505f6d37af", - "condition:leiden:8_characteristic_genes.pkl:md5,fae74f6935930804cd95b1e62b393f44", - "condition:leiden:9_characteristic_genes.pkl:md5,635e5ca72000437e64a458a4fc89dc4b", - "leiden:condition:Disease_characteristic_genes.pkl:md5,029b3b97860e8ba00b2b7701c0ef4836", - "leiden:condition:Healthy_characteristic_genes.pkl:md5,f638b9a63be41a80c24367c329ad9c92", - "leiden:condition:Treated_characteristic_genes.pkl:md5,5761aff9c5fff490dee108a0127a8af4", - "leiden_characteristic_genes.pkl:md5,e387d9c66878055c92c3d4de44cec54a", - "test_liana.pkl:md5,45ccfc4e57fcb1687a4fe33535900110", - "test_paga.pkl:md5,fbd4ae54e51678480c8c4712a9aad0c8" + "condition:leiden:0_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:10_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:11_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:1_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:2_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:3_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:4_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:5_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:6_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:7_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:8_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:9_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Disease_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Healthy_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Treated_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_liana.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_paga.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "1": [ - "condition:leiden:0_characteristic_genes_mqc.json:md5,0d9173af58f05a6a017b7bf62a8ab6a8", - "condition:leiden:10_characteristic_genes_mqc.json:md5,1c42e764ba8a629df84a9f6a7b7cb889", - "condition:leiden:11_characteristic_genes_mqc.json:md5,0778f0f0cd0bd3edf2317a7b557ce952", - "condition:leiden:1_characteristic_genes_mqc.json:md5,a3b5df45edbd4dcc5fb3cf73864f4e76", - "condition:leiden:2_characteristic_genes_mqc.json:md5,1656d5018a65811325f95449b34f302b", - "condition:leiden:3_characteristic_genes_mqc.json:md5,1ce90ec438f14d33bebd26db002544cb", - "condition:leiden:4_characteristic_genes_mqc.json:md5,375733d6a0a018ad6ef0776d5039fb64", - "condition:leiden:5_characteristic_genes_mqc.json:md5,17df859608e296b50492d4fbcaff66f2", - "condition:leiden:6_characteristic_genes_mqc.json:md5,21ec62fdde2bb968127d4f8b5acabaa7", - "condition:leiden:7_characteristic_genes_mqc.json:md5,d1fa8613daecf0aafb769d14c9be39d7", - "condition:leiden:8_characteristic_genes_mqc.json:md5,2602bc68c47188fda2742ad9f222cf4e", - "condition:leiden:9_characteristic_genes_mqc.json:md5,c968bea56d8763520f0d68de394ccb79", - "leiden:condition:Disease_characteristic_genes_mqc.json:md5,46ee7c6e656b2419d618650d7c67d0b0", - "leiden:condition:Healthy_characteristic_genes_mqc.json:md5,cc6e0fe227a84f1036f893945604dcc2", - "leiden:condition:Treated_characteristic_genes_mqc.json:md5,a7a78be0d9f0655ae8a5cae77daf0a74", - "leiden_characteristic_genes_mqc.json:md5,875d02a88fd8f4f0c0462f4da112d1ed", - "test_paga_mqc.json:md5,71c52f6ea9306b6763abd0496e55fe98" + "condition:leiden:0_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:10_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:11_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:1_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:2_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:3_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:4_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:5_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:6_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:7_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:8_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:9_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Disease_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Healthy_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Treated_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_paga_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e" ], "2": [ - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,44f181a9b2e8bebcda641e7400af14cd", - "versions.yml:md5,7d65ff4a31af5f58251f2f57320c8c94" + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ], "multiqc_files": [ - "condition:leiden:0_characteristic_genes_mqc.json:md5,0d9173af58f05a6a017b7bf62a8ab6a8", - "condition:leiden:10_characteristic_genes_mqc.json:md5,1c42e764ba8a629df84a9f6a7b7cb889", - "condition:leiden:11_characteristic_genes_mqc.json:md5,0778f0f0cd0bd3edf2317a7b557ce952", - "condition:leiden:1_characteristic_genes_mqc.json:md5,a3b5df45edbd4dcc5fb3cf73864f4e76", - "condition:leiden:2_characteristic_genes_mqc.json:md5,1656d5018a65811325f95449b34f302b", - "condition:leiden:3_characteristic_genes_mqc.json:md5,1ce90ec438f14d33bebd26db002544cb", - "condition:leiden:4_characteristic_genes_mqc.json:md5,375733d6a0a018ad6ef0776d5039fb64", - "condition:leiden:5_characteristic_genes_mqc.json:md5,17df859608e296b50492d4fbcaff66f2", - "condition:leiden:6_characteristic_genes_mqc.json:md5,21ec62fdde2bb968127d4f8b5acabaa7", - "condition:leiden:7_characteristic_genes_mqc.json:md5,d1fa8613daecf0aafb769d14c9be39d7", - "condition:leiden:8_characteristic_genes_mqc.json:md5,2602bc68c47188fda2742ad9f222cf4e", - "condition:leiden:9_characteristic_genes_mqc.json:md5,c968bea56d8763520f0d68de394ccb79", - "leiden:condition:Disease_characteristic_genes_mqc.json:md5,46ee7c6e656b2419d618650d7c67d0b0", - "leiden:condition:Healthy_characteristic_genes_mqc.json:md5,cc6e0fe227a84f1036f893945604dcc2", - "leiden:condition:Treated_characteristic_genes_mqc.json:md5,a7a78be0d9f0655ae8a5cae77daf0a74", - "leiden_characteristic_genes_mqc.json:md5,875d02a88fd8f4f0c0462f4da112d1ed", - "test_paga_mqc.json:md5,71c52f6ea9306b6763abd0496e55fe98" + "condition:leiden:0_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:10_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:11_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:1_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:2_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:3_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:4_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:5_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:6_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:7_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:8_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:9_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Disease_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Healthy_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Treated_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden_characteristic_genes_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_paga_mqc.json:md5,d41d8cd98f00b204e9800998ecf8427e" ], "uns": [ - "condition:leiden:0_characteristic_genes.pkl:md5,d6be6f9447ed67f6bb5d5df1acf22b86", - "condition:leiden:10_characteristic_genes.pkl:md5,7fd29daa10b8008e16f5c9639a402587", - "condition:leiden:11_characteristic_genes.pkl:md5,9e96aaf44b8d0f0c26a5bda59f63b096", - "condition:leiden:1_characteristic_genes.pkl:md5,f2d38b8ddd01bfd820945fc25fb15f06", - "condition:leiden:2_characteristic_genes.pkl:md5,184a05f08b741d4a0b6e0ee17a9609ec", - "condition:leiden:3_characteristic_genes.pkl:md5,b1bcd5c5d3332c121b01d24cb46a2334", - "condition:leiden:4_characteristic_genes.pkl:md5,15bc73779b616c2276eeedc94bd448b6", - "condition:leiden:5_characteristic_genes.pkl:md5,f314433d06e822b6bcdcccfe1635d32c", - "condition:leiden:6_characteristic_genes.pkl:md5,96e0edc86bf4df08008ff1af3cc10522", - "condition:leiden:7_characteristic_genes.pkl:md5,91ae9da4509aaddb59fb79505f6d37af", - "condition:leiden:8_characteristic_genes.pkl:md5,fae74f6935930804cd95b1e62b393f44", - "condition:leiden:9_characteristic_genes.pkl:md5,635e5ca72000437e64a458a4fc89dc4b", - "leiden:condition:Disease_characteristic_genes.pkl:md5,029b3b97860e8ba00b2b7701c0ef4836", - "leiden:condition:Healthy_characteristic_genes.pkl:md5,f638b9a63be41a80c24367c329ad9c92", - "leiden:condition:Treated_characteristic_genes.pkl:md5,5761aff9c5fff490dee108a0127a8af4", - "leiden_characteristic_genes.pkl:md5,e387d9c66878055c92c3d4de44cec54a", - "test_liana.pkl:md5,45ccfc4e57fcb1687a4fe33535900110", - "test_paga.pkl:md5,fbd4ae54e51678480c8c4712a9aad0c8" + "condition:leiden:0_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:10_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:11_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:1_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:2_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:3_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:4_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:5_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:6_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:7_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:8_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "condition:leiden:9_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Disease_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Healthy_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden:condition:Treated_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "leiden_characteristic_genes.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_liana.pkl:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_paga.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "versions": [ - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,1a9c1aa04f881610ab37fe0d8c9c9cb1", - "versions.yml:md5,44f181a9b2e8bebcda641e7400af14cd", - "versions.yml:md5,7d65ff4a31af5f58251f2f57320c8c94" + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ] } ], - "timestamp": "2026-03-22T16:23:46.565771167", + "timestamp": "2026-03-29T13:30:19.935000889", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/subworkflows/local/pseudobulking/tests/main.nf.test b/subworkflows/local/pseudobulking/tests/main.nf.test index 37c2a3a9..399e6df2 100644 --- a/subworkflows/local/pseudobulking/tests/main.nf.test +++ b/subworkflows/local/pseudobulking/tests/main.nf.test @@ -28,8 +28,17 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.h5ad_pseudobulk[0][1]) assert workflow.success - assert snapshot(workflow.out).match() + with(adata) { + assert "sample" in obs.colnames + assert n_obs > 0 + } + assert snapshot( + workflow.out, + workflow.out.versions.collect { path(it).yaml }, + adata.yaml + ).match() } } diff --git a/subworkflows/local/pseudobulking/tests/main.nf.test.snap b/subworkflows/local/pseudobulking/tests/main.nf.test.snap index eee8a9c3..680db832 100644 --- a/subworkflows/local/pseudobulking/tests/main.nf.test.snap +++ b/subworkflows/local/pseudobulking/tests/main.nf.test.snap @@ -57,9 +57,54 @@ "versions": [ "versions.yml:md5,7629f78da2c667f7f5975f67b4cc521c" ] + }, + [ + { + "PSEUDOBULKING:PSEUDOBULK": { + "anndata": "0.12.10", + "python": "3.12.13", + "scimilarity": "0.4.1" + } + } + ], + { + "n_obs": 3, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "cells", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + "count_nonzero", + "sum" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-22T16:29:32.242181196", + "timestamp": "2026-03-29T14:30:24.242646237", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/subworkflows/local/quality_control/main.nf b/subworkflows/local/quality_control/main.nf index 2d7c812b..31812988 100644 --- a/subworkflows/local/quality_control/main.nf +++ b/subworkflows/local/quality_control/main.nf @@ -75,7 +75,6 @@ workflow QUALITY_CONTROL { [meta, unfiltered] } ) - ch_versions = ch_versions.mix(EMPTY_DROPLET_REMOVAL.out.versions) ch_complete = ch_complete.mix( ch_needs_filtering diff --git a/subworkflows/local/quality_control/tests/main.nf.test b/subworkflows/local/quality_control/tests/main.nf.test index 6c58839f..126f77b2 100644 --- a/subworkflows/local/quality_control/tests/main.nf.test +++ b/subworkflows/local/quality_control/tests/main.nf.test @@ -41,7 +41,12 @@ nextflow_workflow { then { assert workflow.success - assert snapshot(workflow.out).match() + // sample is fully filtered out by SCANPY_FILTER quality thresholds + assert workflow.out.h5ad.size() == 0 + assert snapshot( + workflow.out.multiqc_files, + workflow.out.versions.collect { path(it).yaml } + ).match() } } @@ -81,7 +86,12 @@ nextflow_workflow { then { assert workflow.success - assert snapshot(workflow.out).match() + // sample is fully filtered out by SCANPY_FILTER quality thresholds + assert workflow.out.h5ad.size() == 0 + assert snapshot( + workflow.out.multiqc_files, + workflow.out.versions.collect { path(it).yaml } + ).match() } } @@ -119,12 +129,22 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + with(adata) { + assert "pct_counts_mt" in obs.colnames + assert "batch" in obs.colnames + assert "label" in obs.colnames + assert "condition" in obs.colnames + assert "sample" in obs.colnames + } assert snapshot( workflow.out.multiqc_files, - workflow.out.versions, - anndata(workflow.out.h5ad[0][1]).n_obs, - anndata(workflow.out.h5ad[0][1]).n_vars + workflow.out.versions.collect { path(it).yaml }, + adata.n_obs, + adata.n_vars, + adata.yaml ).match() } @@ -205,7 +225,12 @@ nextflow_workflow { then { assert workflow.success - assert snapshot(workflow.out).match() + // sample is fully filtered out by SCANPY_FILTER quality thresholds + assert workflow.out.h5ad.size() == 0 + assert snapshot( + workflow.out.multiqc_files, + workflow.out.versions.collect { path(it).yaml } + ).match() } } diff --git a/subworkflows/local/quality_control/tests/main.nf.test.snap b/subworkflows/local/quality_control/tests/main.nf.test.snap index 0a5af692..1d61e4c6 100644 --- a/subworkflows/local/quality_control/tests/main.nf.test.snap +++ b/subworkflows/local/quality_control/tests/main.nf.test.snap @@ -1,50 +1,67 @@ { "Should run without ambient RNA removal and doublet detection": { "content": [ - { - "0": [ - - ], - "1": [ - - ], - "2": [ - "sizes_mqc.json:md5,756ad6aae0f322aadfac95c2b38fcef2", - "test_raw_mqc.json:md5,1892d1a9408417050623e6bc2c2480a3" - ], - "3": [ - "versions.yml:md5,09337464bba597568401c441bedb9b61", - "versions.yml:md5,53938cd26fe63616cc4524da4b6062c5", - "versions.yml:md5,5ce128aab0a55bc373e4a4f1c945a603", - "versions.yml:md5,88b8f8687e69ee5ccecf75b7e6845176", - "versions.yml:md5,c4bcd7799f794fb7a2ab6b9a32d346f9", - "versions.yml:md5,d5b598692c585148c4d3027bc296f6fd", - "versions.yml:md5,e10aa3cdeade2300701438cb1bc47b29", - "versions.yml:md5,e98df7a38d5622b937cdabcf7dd7a7d4" - ], - "h5ad": [ - - ], - "multiqc_files": [ - "sizes_mqc.json:md5,756ad6aae0f322aadfac95c2b38fcef2", - "test_raw_mqc.json:md5,1892d1a9408417050623e6bc2c2480a3" - ], - "obs": [ - - ], - "versions": [ - "versions.yml:md5,09337464bba597568401c441bedb9b61", - "versions.yml:md5,53938cd26fe63616cc4524da4b6062c5", - "versions.yml:md5,5ce128aab0a55bc373e4a4f1c945a603", - "versions.yml:md5,88b8f8687e69ee5ccecf75b7e6845176", - "versions.yml:md5,c4bcd7799f794fb7a2ab6b9a32d346f9", - "versions.yml:md5,d5b598692c585148c4d3027bc296f6fd", - "versions.yml:md5,e10aa3cdeade2300701438cb1bc47b29", - "versions.yml:md5,e98df7a38d5622b937cdabcf7dd7a7d4" - ] - } + [ + "sizes_mqc.json:md5,756ad6aae0f322aadfac95c2b38fcef2", + "test_raw_mqc.json:md5,1892d1a9408417050623e6bc2c2480a3" + ], + [ + { + "QUALITY_CONTROL:SCANPY_FILTER": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "QUALITY_CONTROL:GET_UNFILTERED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:QC_RAW": { + "matplotlib": "3.10.8", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "QUALITY_CONTROL:GET_FILTERED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:GET_THRESHOLDED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:UNIFY:ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "QUALITY_CONTROL:UNIFY:UPSET_GENES": { + "anndata": "0.12.10", + "matplotlib": "3.10.8", + "python": "3.13.12", + "upsetplot": "0.9.0" + } + }, + { + "QUALITY_CONTROL:COLLECT_SIZES": { + "pandas": "2.3.3", + "python": "3.13.12" + } + } + ] ], - "timestamp": "2026-03-22T17:47:36.928267661", + "timestamp": "2026-03-28T19:42:23.484650804", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -52,50 +69,67 @@ }, "Should run without ambient RNA removal and doublet detection, but with custom mito genes": { "content": [ - { - "0": [ - - ], - "1": [ - - ], - "2": [ - "sizes_mqc.json:md5,756ad6aae0f322aadfac95c2b38fcef2", - "test_raw_mqc.json:md5,1892d1a9408417050623e6bc2c2480a3" - ], - "3": [ - "versions.yml:md5,09337464bba597568401c441bedb9b61", - "versions.yml:md5,53938cd26fe63616cc4524da4b6062c5", - "versions.yml:md5,5ce128aab0a55bc373e4a4f1c945a603", - "versions.yml:md5,88b8f8687e69ee5ccecf75b7e6845176", - "versions.yml:md5,c4bcd7799f794fb7a2ab6b9a32d346f9", - "versions.yml:md5,d5b598692c585148c4d3027bc296f6fd", - "versions.yml:md5,e10aa3cdeade2300701438cb1bc47b29", - "versions.yml:md5,e98df7a38d5622b937cdabcf7dd7a7d4" - ], - "h5ad": [ - - ], - "multiqc_files": [ - "sizes_mqc.json:md5,756ad6aae0f322aadfac95c2b38fcef2", - "test_raw_mqc.json:md5,1892d1a9408417050623e6bc2c2480a3" - ], - "obs": [ - - ], - "versions": [ - "versions.yml:md5,09337464bba597568401c441bedb9b61", - "versions.yml:md5,53938cd26fe63616cc4524da4b6062c5", - "versions.yml:md5,5ce128aab0a55bc373e4a4f1c945a603", - "versions.yml:md5,88b8f8687e69ee5ccecf75b7e6845176", - "versions.yml:md5,c4bcd7799f794fb7a2ab6b9a32d346f9", - "versions.yml:md5,d5b598692c585148c4d3027bc296f6fd", - "versions.yml:md5,e10aa3cdeade2300701438cb1bc47b29", - "versions.yml:md5,e98df7a38d5622b937cdabcf7dd7a7d4" - ] - } + [ + "sizes_mqc.json:md5,756ad6aae0f322aadfac95c2b38fcef2", + "test_raw_mqc.json:md5,1892d1a9408417050623e6bc2c2480a3" + ], + [ + { + "QUALITY_CONTROL:SCANPY_FILTER": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "QUALITY_CONTROL:GET_UNFILTERED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:QC_RAW": { + "matplotlib": "3.10.8", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "QUALITY_CONTROL:GET_FILTERED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:GET_THRESHOLDED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:UNIFY:ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "QUALITY_CONTROL:UNIFY:UPSET_GENES": { + "anndata": "0.12.10", + "matplotlib": "3.10.8", + "python": "3.13.12", + "upsetplot": "0.9.0" + } + }, + { + "QUALITY_CONTROL:COLLECT_SIZES": { + "pandas": "2.3.3", + "python": "3.13.12" + } + } + ] ], - "timestamp": "2026-03-22T17:49:49.029435332", + "timestamp": "2026-03-28T19:43:09.6069317", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" @@ -198,75 +232,218 @@ "test_raw_mqc.json:md5,1892d1a9408417050623e6bc2c2480a3" ], [ - "versions.yml:md5,09337464bba597568401c441bedb9b61", - "versions.yml:md5,2a595c6f30f1d3a0217f04cc2ffdf4de", - "versions.yml:md5,36d44f6713879308f604b5387983c640", - "versions.yml:md5,3c7417bff601859a86cdcb86fa6bfcb3", - "versions.yml:md5,53938cd26fe63616cc4524da4b6062c5", - "versions.yml:md5,5ce128aab0a55bc373e4a4f1c945a603", - "versions.yml:md5,88b8f8687e69ee5ccecf75b7e6845176", - "versions.yml:md5,8a904ed120b0307240c5a2ebe6dc34f8", - "versions.yml:md5,8cbafef2498da69040e524cc42260989", - "versions.yml:md5,c4bcd7799f794fb7a2ab6b9a32d346f9", - "versions.yml:md5,d5b598692c585148c4d3027bc296f6fd", - "versions.yml:md5,e10aa3cdeade2300701438cb1bc47b29", - "versions.yml:md5,e98df7a38d5622b937cdabcf7dd7a7d4" + { + "QUALITY_CONTROL:SCANPY_FILTER": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "QUALITY_CONTROL:AMBIENT_CORRECTION:CELDA_DECONTX": { + "r": "4.5.3", + "anndataR": "1.0.2", + "celda": "1.26.0" + } + }, + { + "QUALITY_CONTROL:DOUBLET_DETECTION:DOUBLET_REMOVAL": { + "anndata": "0.12.10", + "matplotlib": "3.10.8", + "pandas": "2.3.3", + "python": "3.13.12", + "upsetplot": "0.9.0" + } + }, + { + "QUALITY_CONTROL:GET_DEDOUBLETED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:GET_UNFILTERED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:QC_RAW": { + "matplotlib": "3.10.8", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "QUALITY_CONTROL:GET_FILTERED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:DOUBLET_DETECTION:SCANPY_SCRUBLET": { + "python": "3.12.11", + "scanpy": "1.11.2" + } + }, + { + "QUALITY_CONTROL:QC_FILTERED": { + "matplotlib": "3.10.8", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "QUALITY_CONTROL:GET_THRESHOLDED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:UNIFY:ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "QUALITY_CONTROL:UNIFY:UPSET_GENES": { + "anndata": "0.12.10", + "matplotlib": "3.10.8", + "python": "3.13.12", + "upsetplot": "0.9.0" + } + }, + { + "QUALITY_CONTROL:COLLECT_SIZES": { + "pandas": "2.3.3", + "python": "3.13.12" + } + } ], 12939, - 9887 - ], - "timestamp": "2026-03-22T17:57:09.098006399", - "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.2" - } - }, - "Should run with cell cycle scoring": { - "content": [ + 9887, { - "0": [ + "n_obs": 12939, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "n_counts", + "n_genes", + "n_genes_by_counts", + "pct_counts_mt", + "sample", + "sample_original", + "total_counts", + "total_counts_mt" + ] + }, + "var": { + "index": "_index", + "columns": [ + "mean_counts", + "mt", + "n_cells", + "n_cells_by_counts", + "n_counts", + "pct_dropout_by_counts", + "symbols", + "total_counts" + ] + }, + "layers": [ ], - "1": [ + "obsm": [ ], - "2": [ - "sizes_mqc.json:md5,756ad6aae0f322aadfac95c2b38fcef2", - "test_raw_mqc.json:md5,1892d1a9408417050623e6bc2c2480a3" - ], - "3": [ - "versions.yml:md5,09337464bba597568401c441bedb9b61", - "versions.yml:md5,53938cd26fe63616cc4524da4b6062c5", - "versions.yml:md5,5ce128aab0a55bc373e4a4f1c945a603", - "versions.yml:md5,88b8f8687e69ee5ccecf75b7e6845176", - "versions.yml:md5,c4bcd7799f794fb7a2ab6b9a32d346f9", - "versions.yml:md5,d5b598692c585148c4d3027bc296f6fd", - "versions.yml:md5,e10aa3cdeade2300701438cb1bc47b29", - "versions.yml:md5,e98df7a38d5622b937cdabcf7dd7a7d4" - ], - "h5ad": [ + "varm": [ ], - "multiqc_files": [ - "sizes_mqc.json:md5,756ad6aae0f322aadfac95c2b38fcef2", - "test_raw_mqc.json:md5,1892d1a9408417050623e6bc2c2480a3" + "obsp": [ + ], - "obs": [ + "varp": [ ], - "versions": [ - "versions.yml:md5,09337464bba597568401c441bedb9b61", - "versions.yml:md5,53938cd26fe63616cc4524da4b6062c5", - "versions.yml:md5,5ce128aab0a55bc373e4a4f1c945a603", - "versions.yml:md5,88b8f8687e69ee5ccecf75b7e6845176", - "versions.yml:md5,c4bcd7799f794fb7a2ab6b9a32d346f9", - "versions.yml:md5,d5b598692c585148c4d3027bc296f6fd", - "versions.yml:md5,e10aa3cdeade2300701438cb1bc47b29", - "versions.yml:md5,e98df7a38d5622b937cdabcf7dd7a7d4" + "uns": [ + ] } ], - "timestamp": "2026-03-22T17:58:51.427722446", + "timestamp": "2026-03-29T11:24:39.776574078", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } + }, + "Should run with cell cycle scoring": { + "content": [ + [ + "sizes_mqc.json:md5,756ad6aae0f322aadfac95c2b38fcef2", + "test_raw_mqc.json:md5,1892d1a9408417050623e6bc2c2480a3" + ], + [ + { + "QUALITY_CONTROL:SCANPY_FILTER": { + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "QUALITY_CONTROL:GET_UNFILTERED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:QC_RAW": { + "matplotlib": "3.10.8", + "python": "3.13.12", + "scanpy": "1.12" + } + }, + { + "QUALITY_CONTROL:GET_FILTERED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:GET_THRESHOLDED_SIZE": { + "python": "3.13.0", + "anndata": "0.10.9" + } + }, + { + "QUALITY_CONTROL:UNIFY:ADATA_UNIFY": { + "anndata": "0.12.10", + "numpy": "2.3.5", + "python": "3.13.12", + "scipy": "1.17.1" + } + }, + { + "QUALITY_CONTROL:UNIFY:UPSET_GENES": { + "anndata": "0.12.10", + "matplotlib": "3.10.8", + "python": "3.13.12", + "upsetplot": "0.9.0" + } + }, + { + "QUALITY_CONTROL:COLLECT_SIZES": { + "pandas": "2.3.3", + "python": "3.13.12" + } + } + ] + ], + "timestamp": "2026-03-28T19:47:47.258742454", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.2" diff --git a/subworkflows/local/scimilarity/main.nf b/subworkflows/local/scimilarity/main.nf index 252dee99..25ed98ca 100644 --- a/subworkflows/local/scimilarity/main.nf +++ b/subworkflows/local/scimilarity/main.nf @@ -28,7 +28,6 @@ workflow SCIMILARITY { UNTAR ( ch_scimilarity_model ) - ch_versions = ch_versions.mix(UNTAR.out.versions) ch_scimilarity_model = UNTAR.out.untar } diff --git a/subworkflows/local/scimilarity/tests/main.nf.test.snap b/subworkflows/local/scimilarity/tests/main.nf.test.snap index 9a4e2cbd..afd1cab9 100644 --- a/subworkflows/local/scimilarity/tests/main.nf.test.snap +++ b/subworkflows/local/scimilarity/tests/main.nf.test.snap @@ -17,7 +17,6 @@ "X_test.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "3": [ - "versions.yml:md5,48890903e09c762a5003d3630680f8f1", "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ], @@ -36,17 +35,16 @@ "X_test.pkl:md5,d41d8cd98f00b204e9800998ecf8427e" ], "versions": [ - "versions.yml:md5,48890903e09c762a5003d3630680f8f1", "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e", "versions.yml:md5,d41d8cd98f00b204e9800998ecf8427e" ] } ], + "timestamp": "2026-03-30T08:23:19.253074422", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2026-01-10T23:00:05.637283949" + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } }, "Should run without failures - stub - uncompressed model": { "content": [ @@ -89,10 +87,10 @@ ] } ], + "timestamp": "2026-01-10T23:01:38.877123044", "meta": { "nf-test": "0.9.2", "nextflow": "25.04.6" - }, - "timestamp": "2026-01-10T23:01:38.877123044" + } } } \ No newline at end of file diff --git a/subworkflows/local/singler/main.nf b/subworkflows/local/singler/main.nf index f5109b7c..4200fa5a 100644 --- a/subworkflows/local/singler/main.nf +++ b/subworkflows/local/singler/main.nf @@ -17,13 +17,11 @@ workflow SINGLER { CELLDEX_FETCHREFERENCE ( ch_reference.names - .map { - meta, ref -> { + .map { meta, ref -> if (!meta.version) { error "If you specify a celldex reference, you also need to specify a version" } - return [meta, ref, meta.version] - } + [meta, ref, meta.version] } ) ch_versions = ch_versions.mix(CELLDEX_FETCHREFERENCE.out.versions) diff --git a/subworkflows/local/singler/tests/main.nf.test b/subworkflows/local/singler/tests/main.nf.test index 83dbfa07..e8ab2c5d 100644 --- a/subworkflows/local/singler/tests/main.nf.test +++ b/subworkflows/local/singler/tests/main.nf.test @@ -32,8 +32,21 @@ nextflow_workflow { } then { + def predictions = path(workflow.out.obs[0][1]).csv assert workflow.success - assert snapshot(workflow.out).match() + assert workflow.out.obs.size() == 1 + with(predictions) { + assert rowCount > 0 + // one label column per reference, keyed by the reference meta.id + assert columnNames.any { it.endsWith("labels_hpca_direct") } + assert columnNames.any { it.endsWith("pruned.labels_hpca_direct") } + assert columnNames.any { it.endsWith("labels_immune_celldex") } + assert columnNames.any { it.endsWith("pruned.labels_immune_celldex") } + } + assert snapshot( + workflow.out.obs, + workflow.out.versions.collect { path(it).yaml } + ).match() } } diff --git a/subworkflows/local/singler/tests/main.nf.test.snap b/subworkflows/local/singler/tests/main.nf.test.snap index 04ef113e..c723ca46 100644 --- a/subworkflows/local/singler/tests/main.nf.test.snap +++ b/subworkflows/local/singler/tests/main.nf.test.snap @@ -36,37 +36,39 @@ }, "Should run without failures": { "content": [ - { - "0": [ - [ - { - "id": "test" - }, - "test_singler_predictions.csv:md5,dae3881eb387e231fccb6c4302d93077" - ] - ], - "1": [ - "versions.yml:md5,9055f318b5890f047abf54b761b99cd1", - "versions.yml:md5,af2576b779b477b66790d98fa63566a6" - ], - "obs": [ - [ - { - "id": "test" - }, - "test_singler_predictions.csv:md5,dae3881eb387e231fccb6c4302d93077" - ] - ], - "versions": [ - "versions.yml:md5,9055f318b5890f047abf54b761b99cd1", - "versions.yml:md5,af2576b779b477b66790d98fa63566a6" + [ + [ + { + "id": "test" + }, + "test_singler_predictions.csv:md5,dae3881eb387e231fccb6c4302d93077" ] - } + ], + [ + { + "SINGLER:CELLTYPES_SINGLER": { + "R": "R version 4.5.3 (2026-03-11)", + "SingleR": "2.12.0", + "celldex": "1.20.0", + "anndataR": "1.0.2", + "ggplot2": "4.0.2" + } + }, + { + "SINGLER:CELLDEX_FETCHREFERENCE": { + "R": "R version 4.4.1 (2024-06-14)", + "celldex": "1.16.0", + "yaml": "2.3.10", + "SingleCellExperiment": "1.28.0", + "HDF5Array": "1.34.0" + } + } + ] ], - "timestamp": "2026-03-17T21:50:58.100916466", + "timestamp": "2026-03-28T19:19:04.019970429", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/subworkflows/local/unify/tests/main.nf.test b/subworkflows/local/unify/tests/main.nf.test index 2bc6e5d1..e75b292a 100644 --- a/subworkflows/local/unify/tests/main.nf.test +++ b/subworkflows/local/unify/tests/main.nf.test @@ -57,8 +57,20 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.h5ad[0][1]) assert workflow.success - assert snapshot(workflow.out).match() + with(adata) { + assert "batch" in obs.colnames + assert "label" in obs.colnames + assert "condition" in obs.colnames + assert "sample" in obs.colnames + assert var.rownames.size() > 0 + assert obs.rownames.size() > 0 + } + assert snapshot( + workflow.out, + adata.yaml + ).match() } } @@ -113,35 +125,20 @@ nextflow_workflow { } then { + def adata = anndata(workflow.out.h5ad[0][1]) assert workflow.success - assert snapshot(workflow.out).match() - } - - } - - test("Should run without failures - symbol_col index, unify_gene_symbols false, snapshot stability") { - - when { - params { - outdir = "$outputDir" - unify_gene_symbols = false - } - workflow { - """ - input[0] = channel.of([ - [id: 'test', symbol_col: 'index', batch_col: 'batch', label_col: ''], - file(params.pipelines_testdata_base_path + '/anndata-variations/symbols_as_index.h5ad', checkIfExists: true) - ]) - input[1] = false - input[2] = 'sum' - input[3] = false - """ + with(adata) { + assert "batch" in obs.colnames + assert "label" in obs.colnames + assert "condition" in obs.colnames + assert "sample" in obs.colnames + assert var.rownames.size() > 0 + assert obs.rownames.size() > 0 } - } - - then { - assert workflow.success - assert snapshot(workflow.out).match() + assert snapshot( + workflow.out, + adata.yaml + ).match() } } @@ -196,16 +193,20 @@ nextflow_workflow { } then { - def filename = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { - with(anndata(filename)) { - assert var.rownames.size() > 0 - assert obs.rownames.size() > 0 - } + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + with(adata) { + assert "batch" in obs.colnames + assert "label" in obs.colnames + assert "condition" in obs.colnames + assert "sample" in obs.colnames + assert var.rownames.size() > 0 + assert obs.rownames.size() > 0 } - ) + assert snapshot( + workflow.out, + adata.yaml + ).match() } } diff --git a/subworkflows/local/unify/tests/main.nf.test.snap b/subworkflows/local/unify/tests/main.nf.test.snap index f04158d1..c854d4cf 100644 --- a/subworkflows/local/unify/tests/main.nf.test.snap +++ b/subworkflows/local/unify/tests/main.nf.test.snap @@ -99,15 +99,53 @@ "versions.yml:md5,56975dcf8aab71705ad7f822233409b8", "versions.yml:md5,f4baeb211a033b2534fb83ba7ec2cd86" ] + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T16:27:36.451603253", + "timestamp": "2026-03-29T11:17:31.315941656", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, - "Should run without failures - symbol_col index, unify_gene_symbols false, snapshot stability": { + "Should run without failures - symbol_col index, unify_gene_symbols true": { "content": [ { "0": [ @@ -121,13 +159,16 @@ "unknown_label": "unknown", "counts_layer": "X" }, - "test_unified.h5ad:md5,634cda43f3cc2ce7ffeddcd8cb0a1e76" + "test_unified.h5ad:md5,95eaecd7513a2cec94ff17aa626d11cd" ] ], "1": [ ], "2": [ + "versions.yml:md5,36bf3fb866d0085291382bf6713f7698", + "versions.yml:md5,4e6f35e1d0c91cec3120567db9f0bdfe", + "versions.yml:md5,56867b1608bf70187c185b4fecb3eab7", "versions.yml:md5,56975dcf8aab71705ad7f822233409b8", "versions.yml:md5,f4baeb211a033b2534fb83ba7ec2cd86" ], @@ -142,22 +183,63 @@ "unknown_label": "unknown", "counts_layer": "X" }, - "test_unified.h5ad:md5,634cda43f3cc2ce7ffeddcd8cb0a1e76" + "test_unified.h5ad:md5,95eaecd7513a2cec94ff17aa626d11cd" ] ], "multiqc_files": [ ], "versions": [ + "versions.yml:md5,36bf3fb866d0085291382bf6713f7698", + "versions.yml:md5,4e6f35e1d0c91cec3120567db9f0bdfe", + "versions.yml:md5,56867b1608bf70187c185b4fecb3eab7", "versions.yml:md5,56975dcf8aab71705ad7f822233409b8", "versions.yml:md5,f4baeb211a033b2534fb83ba7ec2cd86" ] + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample", + "sample_original" + ] + }, + "var": { + "index": "_index", + "columns": [ + + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T16:28:57.027859362", + "timestamp": "2026-03-29T11:22:29.327390466", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } }, "Should run without failures - symbol_col index, unify_gene_symbols false - stub": { @@ -321,12 +403,50 @@ "versions.yml:md5,d206caf8bf0d007a1c248652300a3834", "versions.yml:md5,f4baeb211a033b2534fb83ba7ec2cd86" ] + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "batch", + "condition", + "label", + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "original_index", + "symbols" + ] + }, + "layers": [ + + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] } ], - "timestamp": "2026-03-16T16:28:45.097590752", + "timestamp": "2026-03-29T11:19:53.355480172", "meta": { "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nextflow": "25.10.2" } } } \ No newline at end of file diff --git a/subworkflows/local/unify_genes/tests/main.nf.test b/subworkflows/local/unify_genes/tests/main.nf.test index f2371333..ab576964 100644 --- a/subworkflows/local/unify_genes/tests/main.nf.test +++ b/subworkflows/local/unify_genes/tests/main.nf.test @@ -49,16 +49,17 @@ nextflow_workflow { } then { - def filename = workflow.out.h5ad[0][1] - assertAll( - { assert workflow.success }, - { - with(anndata(filename)) { - assert var.rownames.size() > 0 - assert obs.rownames.size() > 0 - } + def adata = anndata(workflow.out.h5ad[0][1]) + assert workflow.success + with(adata) { + assert "symbols" in var.colnames + assert var.rownames.size() > 0 + assert obs.rownames.size() > 0 } - ) + assert snapshot( + workflow.out.versions.collect { path(it).yaml }, + adata.yaml + ).match() } } @@ -105,21 +106,24 @@ nextflow_workflow { } then { - assertAll( - { assert workflow.success }, - { - with(anndata(workflow.out.h5ad[0][1])) { - assert var.rownames.size() > 0 - assert obs.rownames.size() > 0 - } - }, - { - with(anndata(workflow.out.h5ad[1][1])) { - assert var.rownames.size() > 0 - assert obs.rownames.size() > 0 - } + def adata1 = anndata(workflow.out.h5ad[0][1]) + def adata2 = anndata(workflow.out.h5ad[1][1]) + assert workflow.success + with(adata1) { + assert "symbols" in var.colnames + assert var.rownames.size() > 0 + assert obs.rownames.size() > 0 + } + with(adata2) { + assert "symbols" in var.colnames + assert var.rownames.size() > 0 + assert obs.rownames.size() > 0 } - ) + assert snapshot( + workflow.out.versions.collect { path(it).yaml }, + adata1.yaml, + adata2.yaml + ).match() } } diff --git a/subworkflows/local/unify_genes/tests/main.nf.test.snap b/subworkflows/local/unify_genes/tests/main.nf.test.snap index 627adb9e..719f2cfd 100644 --- a/subworkflows/local/unify_genes/tests/main.nf.test.snap +++ b/subworkflows/local/unify_genes/tests/main.nf.test.snap @@ -1,4 +1,59 @@ { + "Should run without failures - single sample": { + "content": [ + [ + { + "UNIFY_GENES:HUGOUNIFIER_GET": { + "hugo-unifier": "0.3.1" + } + }, + { + "UNIFY_GENES:HUGOUNIFIER_APPLY": { + "hugo-unifier": "0.3.1" + } + } + ], + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } + ], + "timestamp": "2026-03-29T14:30:07.824538049", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } + }, "Should run without failures - multiple samples - stub": { "content": [ { @@ -77,10 +132,104 @@ ] } ], - "timestamp": "2026-01-17T08:56:25.329555915", + "timestamp": "2026-01-17T08:56:25.329515915", "meta": { "nf-test": "0.9.2", "nextflow": "25.04.6" } + }, + "Should run without failures - multiple samples": { + "content": [ + [ + { + "UNIFY_GENES:HUGOUNIFIER_GET": { + "hugo-unifier": "0.3.1" + } + }, + { + "UNIFY_GENES:HUGOUNIFIER_APPLY": { + "hugo-unifier": "0.3.1" + } + }, + { + "UNIFY_GENES:HUGOUNIFIER_APPLY": { + "hugo-unifier": "0.3.1" + } + } + ], + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + }, + { + "n_obs": 12940, + "n_vars": 9887, + "obs": { + "index": "_index", + "columns": [ + "sample" + ] + }, + "var": { + "index": "_index", + "columns": [ + "symbols" + ] + }, + "layers": [ + "counts" + ], + "obsm": [ + + ], + "varm": [ + + ], + "obsp": [ + + ], + "varp": [ + + ], + "uns": [ + + ] + } + ], + "timestamp": "2026-03-29T14:31:03.525495969", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.2" + } } -} +} \ No newline at end of file diff --git a/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/main.nf b/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/main.nf index c7a019f4..997d5d7d 100644 --- a/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/main.nf +++ b/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/main.nf @@ -10,16 +10,10 @@ workflow H5AD_REMOVEBACKGROUND_BARCODES_CELLBENDER_ANNDATA { ch_unfiltered // channel: [mandatory] meta, h5ad main: - ch_versions = channel.empty() - CELLBENDER_REMOVEBACKGROUND(ch_unfiltered) - ch_versions = ch_versions.mix(CELLBENDER_REMOVEBACKGROUND.out.versions) ANNDATA_BARCODES(ch_unfiltered.join(CELLBENDER_REMOVEBACKGROUND.out.barcodes)) - ch_versions = ch_versions.mix(ANNDATA_BARCODES.out.versions) emit: h5ad = ANNDATA_BARCODES.out.h5ad // channel: [ val(meta), path(h5ad) ] - - versions = ch_versions // channel: [ path(versions.yml) ] } diff --git a/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/tests/main.nf.test b/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/tests/main.nf.test index 066aa0ce..350ccf64 100644 --- a/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/tests/main.nf.test +++ b/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/tests/main.nf.test @@ -25,8 +25,7 @@ nextflow_workflow { then { assertAll( { assert workflow.success}, - { assert file(workflow.out.h5ad.get(0).get(1)).exists()}, - { assert snapshot(workflow.out.versions).match()} + { assert file(workflow.out.h5ad.get(0).get(1)).exists()} ) } } diff --git a/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/tests/main.nf.test.snap b/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/tests/main.nf.test.snap index 3069c17f..bc69c04d 100644 --- a/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/tests/main.nf.test.snap +++ b/subworkflows/nf-core/h5ad_removebackground_barcodes_cellbender_anndata/tests/main.nf.test.snap @@ -1,16 +1,15 @@ { "h5ad - h5ad_removebackground_barcodes_cellbender_anndata": { "content": [ - [ - "versions.yml:md5,3b268371ecd09ac624398c004f5e279d", - "versions.yml:md5,d18fac1840ecbc7e6ee830d26e83ac91" - ] + { + + } ], + "timestamp": "2026-03-13T16:10:00.940145898", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-11T13:36:03.576334046" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "h5ad - h5ad_removebackground_barcodes_cellbender_anndata - stub": { "content": [ @@ -23,10 +22,6 @@ "test.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "1": [ - "versions.yml:md5,3b268371ecd09ac624398c004f5e279d", - "versions.yml:md5,44799738472a56b1d09e916215b2a006" - ], "h5ad": [ [ { @@ -34,17 +29,13 @@ }, "test.h5ad:md5,d41d8cd98f00b204e9800998ecf8427e" ] - ], - "versions": [ - "versions.yml:md5,3b268371ecd09ac624398c004f5e279d", - "versions.yml:md5,44799738472a56b1d09e916215b2a006" ] } ], + "timestamp": "2026-03-12T15:06:01.974773939", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-11T13:36:15.057527557" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/tests/default.nf.test b/tests/default.nf.test index a429dccb..87ba45be 100644 --- a/tests/default.nf.test +++ b/tests/default.nf.test @@ -14,7 +14,7 @@ nextflow_pipeline { then { // stable_name: All files + folders in ${params.outdir}/ with a stable name - def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', 'per_group/**']) + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', 'per_group/**', 'multiqc/**']) // stable_path: All files in ${params.outdir}/ with stable content def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') assertAll( diff --git a/tests/default.nf.test.snap b/tests/default.nf.test.snap index e9e5123f..73710576 100644 --- a/tests/default.nf.test.snap +++ b/tests/default.nf.test.snap @@ -250,23 +250,6 @@ "finalized/merged.rds", "finalized/merged_metadata.csv", "multiqc", - "multiqc/multiqc_data", - "multiqc/multiqc_data/llms-full.txt", - "multiqc/multiqc_data/multiqc.log", - "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_citations.txt", - "multiqc/multiqc_data/multiqc_data.json", - "multiqc/multiqc_data/multiqc_sizes.txt", - "multiqc/multiqc_data/multiqc_software_versions.txt", - "multiqc/multiqc_data/multiqc_sources.txt", - "multiqc/multiqc_plots", - "multiqc/multiqc_plots/pdf", - "multiqc/multiqc_plots/pdf/sizes.pdf", - "multiqc/multiqc_plots/png", - "multiqc/multiqc_plots/png/sizes.png", - "multiqc/multiqc_plots/svg", - "multiqc/multiqc_plots/svg/sizes.svg", - "multiqc/multiqc_report.html", "per_group", "pipeline_info", "pipeline_info/nf_core_scdownstream_software_mqc_versions.yml", @@ -286,7 +269,7 @@ "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f" ] ], - "timestamp": "2026-03-22T18:03:44.32474555", + "timestamp": "2026-03-31T19:29:42.315558141", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" diff --git a/tests/main_pipeline_build.nf.test b/tests/main_pipeline_build.nf.test index 203b8cf9..631f11a3 100644 --- a/tests/main_pipeline_build.nf.test +++ b/tests/main_pipeline_build.nf.test @@ -10,7 +10,7 @@ nextflow_pipeline { params { input = 'https://github.com/nf-core/test-datasets/raw/refs/heads/scdownstream/samplesheet.csv' integration_methods = 'scvi,harmony,bbknn,combat,seurat' - doublet_detection = 'scrublet,doubletdetection,scds' + doublet_detection = 'scrublet,scds' celltypist_model = 'Adult_COVID19_PBMC' integration_hvgs = 500 outdir = "$outputDir" @@ -19,7 +19,7 @@ nextflow_pipeline { then { // stable_name: All files + folders in ${params.outdir}/ with a stable name - def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', 'per_group/**']) + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', 'per_group/**', 'multiqc/**']) // stable_path: All files in ${params.outdir}/ with stable content def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') assertAll( diff --git a/tests/main_pipeline_build.nf.test.snap b/tests/main_pipeline_build.nf.test.snap index e6bbf4b5..53bdd5cb 100644 --- a/tests/main_pipeline_build.nf.test.snap +++ b/tests/main_pipeline_build.nf.test.snap @@ -59,11 +59,6 @@ "pandas": "2.3.3", "python": "3.13.12" }, - "DOUBLETDETECTION": { - "anndata": "0.11.4", - "doubletdetection": "4.3.0.post1", - "python": "3.13.3" - }, "DOUBLET_REMOVAL": { "anndata": "0.12.10", "matplotlib": "3.10.8", @@ -155,6 +150,10 @@ "python": "3.13.12", "scanpy": "1.12" }, + "SCANPY_SCRUBLET": { + "python": "3.12.11", + "scanpy": "1.11.2" + }, "SCVITOOLS_SCVI": { "scvi": "1.3.3" }, @@ -264,23 +263,6 @@ "finalized/merged.rds", "finalized/merged_metadata.csv", "multiqc", - "multiqc/multiqc_data", - "multiqc/multiqc_data/llms-full.txt", - "multiqc/multiqc_data/multiqc.log", - "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_citations.txt", - "multiqc/multiqc_data/multiqc_data.json", - "multiqc/multiqc_data/multiqc_sizes.txt", - "multiqc/multiqc_data/multiqc_software_versions.txt", - "multiqc/multiqc_data/multiqc_sources.txt", - "multiqc/multiqc_plots", - "multiqc/multiqc_plots/pdf", - "multiqc/multiqc_plots/pdf/sizes.pdf", - "multiqc/multiqc_plots/png", - "multiqc/multiqc_plots/png/sizes.png", - "multiqc/multiqc_plots/svg", - "multiqc/multiqc_plots/svg/sizes.svg", - "multiqc/multiqc_report.html", "per_group", "pipeline_info", "pipeline_info/nf_core_scdownstream_software_mqc_versions.yml", @@ -300,9 +282,9 @@ "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f" ] ], - "timestamp": "2026-03-22T21:31:34.14074829", + "timestamp": "2026-04-01T12:30:18.209142", "meta": { - "nf-test": "0.9.4", + "nf-test": "0.9.5", "nextflow": "25.10.4" } } diff --git a/tests/main_pipeline_extend.nf.test b/tests/main_pipeline_extend.nf.test index a2a64a04..891e69cb 100644 --- a/tests/main_pipeline_extend.nf.test +++ b/tests/main_pipeline_extend.nf.test @@ -10,7 +10,7 @@ nextflow_pipeline { params { input = 'https://github.com/nf-core/test-datasets/raw/refs/heads/scdownstream/samplesheet_single.csv' integration_methods = 'scvi' - doublet_detection = 'scrublet,doubletdetection,scds' + doublet_detection = 'scrublet,scds' celltypist_model = 'Adult_COVID19_PBMC' integration_hvgs = 500 outdir = "$outputDir" @@ -21,7 +21,7 @@ nextflow_pipeline { then { // stable_name: All files + folders in ${params.outdir}/ with a stable name - def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', 'per_group/**']) + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', 'per_group/**', 'multiqc/**']) // stable_path: All files in ${params.outdir}/ with stable content def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') assertAll( diff --git a/tests/main_pipeline_extend.nf.test.snap b/tests/main_pipeline_extend.nf.test.snap index 4ccff40d..770e8c8e 100644 --- a/tests/main_pipeline_extend.nf.test.snap +++ b/tests/main_pipeline_extend.nf.test.snap @@ -56,11 +56,6 @@ "pandas": "2.3.3", "python": "3.13.12" }, - "DOUBLETDETECTION": { - "anndata": "0.11.4", - "doubletdetection": "4.3.0.post1", - "python": "3.13.3" - }, "DOUBLET_REMOVAL": { "anndata": "0.12.10", "matplotlib": "3.10.8", @@ -130,6 +125,10 @@ "python": "3.13.12", "scanpy": "1.12" }, + "SCANPY_SCRUBLET": { + "python": "3.12.11", + "scanpy": "1.11.2" + }, "SCVITOOLS_SCVI": { "scvi": "1.3.3" }, @@ -183,23 +182,6 @@ "finalized/merged.rds", "finalized/merged_metadata.csv", "multiqc", - "multiqc/multiqc_data", - "multiqc/multiqc_data/llms-full.txt", - "multiqc/multiqc_data/multiqc.log", - "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_citations.txt", - "multiqc/multiqc_data/multiqc_data.json", - "multiqc/multiqc_data/multiqc_sizes.txt", - "multiqc/multiqc_data/multiqc_software_versions.txt", - "multiqc/multiqc_data/multiqc_sources.txt", - "multiqc/multiqc_plots", - "multiqc/multiqc_plots/pdf", - "multiqc/multiqc_plots/pdf/sizes.pdf", - "multiqc/multiqc_plots/png", - "multiqc/multiqc_plots/png/sizes.png", - "multiqc/multiqc_plots/svg", - "multiqc/multiqc_plots/svg/sizes.svg", - "multiqc/multiqc_report.html", "per_group", "pipeline_info", "pipeline_info/nf_core_scdownstream_software_mqc_versions.yml", @@ -215,7 +197,7 @@ "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f" ] ], - "timestamp": "2026-03-22T18:03:53.563393217", + "timestamp": "2026-03-31T19:27:24.64774367", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" diff --git a/tests/main_pipeline_qc.nf.test b/tests/main_pipeline_qc.nf.test index d915ebf1..73ca00e8 100644 --- a/tests/main_pipeline_qc.nf.test +++ b/tests/main_pipeline_qc.nf.test @@ -9,7 +9,7 @@ nextflow_pipeline { when { params { input = 'https://github.com/nf-core/test-datasets/raw/refs/heads/scdownstream/samplesheet.csv' - doublet_detection = 'scrublet,doubletdetection,scds' + doublet_detection = 'scrublet,scds' celltypist_model = 'Adult_COVID19_PBMC' qc_only = true outdir = "$outputDir" @@ -18,14 +18,14 @@ nextflow_pipeline { then { // stable_name: All files + folders in ${params.outdir}/ with a stable name - def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', 'per_group/**', 'multiqc/**']) // stable_path: All files in ${params.outdir}/ with stable content def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') assertAll( { assert workflow.success}, { assert snapshot( // Number of successful tasks - workflow.trace.succeeded().size(), + // workflow.trace.succeeded().size(), disabled, because tool versions may differ and affect exact task counts // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions removeNextflowVersion("$outputDir/pipeline_info/nf_core_scdownstream_software_mqc_versions.yml"), // All stable path name, with a relative path diff --git a/tests/main_pipeline_qc.nf.test.snap b/tests/main_pipeline_qc.nf.test.snap index f62b78e3..8899834e 100644 --- a/tests/main_pipeline_qc.nf.test.snap +++ b/tests/main_pipeline_qc.nf.test.snap @@ -1,7 +1,6 @@ { "Should process data from scratch": { "content": [ - 60, { "ADATA_READRDS": { "anndata": "0.11.1", @@ -45,11 +44,6 @@ "pandas": "2.3.3", "python": "3.13.12" }, - "DOUBLETDETECTION": { - "anndata": "0.11.4", - "doubletdetection": "4.3.0.post1", - "python": "3.13.3" - }, "DOUBLET_REMOVAL": { "anndata": "0.12.10", "matplotlib": "3.10.8", @@ -97,6 +91,10 @@ "python": "3.13.12", "scanpy": "1.12" }, + "SCANPY_SCRUBLET": { + "python": "3.12.11", + "scanpy": "1.11.2" + }, "UPSET_GENES": { "anndata": "0.12.10", "matplotlib": "3.10.8", @@ -141,23 +139,6 @@ "combine/merge", "combine/merge/upset_genes.png", "multiqc", - "multiqc/multiqc_data", - "multiqc/multiqc_data/llms-full.txt", - "multiqc/multiqc_data/multiqc.log", - "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_citations.txt", - "multiqc/multiqc_data/multiqc_data.json", - "multiqc/multiqc_data/multiqc_sizes.txt", - "multiqc/multiqc_data/multiqc_software_versions.txt", - "multiqc/multiqc_data/multiqc_sources.txt", - "multiqc/multiqc_plots", - "multiqc/multiqc_plots/pdf", - "multiqc/multiqc_plots/pdf/sizes.pdf", - "multiqc/multiqc_plots/png", - "multiqc/multiqc_plots/png/sizes.png", - "multiqc/multiqc_plots/svg", - "multiqc/multiqc_plots/svg/sizes.svg", - "multiqc/multiqc_report.html", "pipeline_info", "pipeline_info/nf_core_scdownstream_software_mqc_versions.yml", "quality_control", @@ -176,7 +157,7 @@ "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f" ] ], - "timestamp": "2026-03-22T18:02:21.271429508", + "timestamp": "2026-03-31T19:16:27.846620062", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" diff --git a/tests/main_pipeline_reference_mapping.nf.test b/tests/main_pipeline_reference_mapping.nf.test index 9b8b1b90..e20eaed8 100644 --- a/tests/main_pipeline_reference_mapping.nf.test +++ b/tests/main_pipeline_reference_mapping.nf.test @@ -10,7 +10,7 @@ nextflow_pipeline { params { input = 'https://github.com/nf-core/test-datasets/raw/refs/heads/scdownstream/samplesheet_single.csv' integration_methods = 'scvi' - doublet_detection = 'scrublet,doubletdetection,scds' + doublet_detection = 'scrublet,scds' celltypist_model = 'Adult_COVID19_PBMC' integration_hvgs = 500 outdir = "$outputDir" @@ -20,7 +20,7 @@ nextflow_pipeline { then { // stable_name: All files + folders in ${params.outdir}/ with a stable name - def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', 'per_group/**']) + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', 'per_group/**', 'multiqc/**']) // stable_path: All files in ${params.outdir}/ with stable content def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') assertAll( diff --git a/tests/main_pipeline_reference_mapping.nf.test.snap b/tests/main_pipeline_reference_mapping.nf.test.snap index 4cbbf825..15610464 100644 --- a/tests/main_pipeline_reference_mapping.nf.test.snap +++ b/tests/main_pipeline_reference_mapping.nf.test.snap @@ -52,11 +52,6 @@ "pandas": "2.3.3", "python": "3.13.12" }, - "DOUBLETDETECTION": { - "anndata": "0.11.4", - "doubletdetection": "4.3.0.post1", - "python": "3.13.3" - }, "DOUBLET_REMOVAL": { "anndata": "0.12.10", "matplotlib": "3.10.8", @@ -130,6 +125,10 @@ "python": "3.13.12", "scanpy": "1.12" }, + "SCANPY_SCRUBLET": { + "python": "3.12.11", + "scanpy": "1.11.2" + }, "SCVITOOLS_SCVI": { "scvi": "1.3.3" }, @@ -183,23 +182,6 @@ "finalized/merged.rds", "finalized/merged_metadata.csv", "multiqc", - "multiqc/multiqc_data", - "multiqc/multiqc_data/llms-full.txt", - "multiqc/multiqc_data/multiqc.log", - "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_citations.txt", - "multiqc/multiqc_data/multiqc_data.json", - "multiqc/multiqc_data/multiqc_sizes.txt", - "multiqc/multiqc_data/multiqc_software_versions.txt", - "multiqc/multiqc_data/multiqc_sources.txt", - "multiqc/multiqc_plots", - "multiqc/multiqc_plots/pdf", - "multiqc/multiqc_plots/pdf/sizes.pdf", - "multiqc/multiqc_plots/png", - "multiqc/multiqc_plots/png/sizes.png", - "multiqc/multiqc_plots/svg", - "multiqc/multiqc_plots/svg/sizes.svg", - "multiqc/multiqc_report.html", "per_group", "pipeline_info", "pipeline_info/nf_core_scdownstream_software_mqc_versions.yml", @@ -215,7 +197,7 @@ "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f" ] ], - "timestamp": "2026-03-22T18:01:37.608502342", + "timestamp": "2026-03-31T19:23:28.911087783", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" diff --git a/tests/main_pipeline_sub.nf.test b/tests/main_pipeline_sub.nf.test index ed061091..740f29f9 100644 --- a/tests/main_pipeline_sub.nf.test +++ b/tests/main_pipeline_sub.nf.test @@ -20,14 +20,14 @@ nextflow_pipeline { then { // stable_name: All files + folders in ${params.outdir}/ with a stable name - def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', 'per_group/**', 'multiqc/**']) // stable_path: All files in ${params.outdir}/ with stable content def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') assertAll( { assert workflow.success}, { assert snapshot( // Number of successful tasks - workflow.trace.succeeded().size(), + // workflow.trace.succeeded().size(), disabled, because clustering is not stable and the DIFFERENTIAL_EXPRESSION subworkflow creates tasks based on the number of clusters // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions removeNextflowVersion("$outputDir/pipeline_info/nf_core_scdownstream_software_mqc_versions.yml"), // All stable path name, with a relative path diff --git a/tests/main_pipeline_sub.nf.test.snap b/tests/main_pipeline_sub.nf.test.snap index d97db967..73abfecf 100644 --- a/tests/main_pipeline_sub.nf.test.snap +++ b/tests/main_pipeline_sub.nf.test.snap @@ -1,7 +1,6 @@ { "Should be able to perform subclustering": { "content": [ - 291, { "ADATA_EXTEND": { "anndata": "0.12.10", @@ -113,475 +112,7 @@ "finalized/base.rds", "finalized/base_metadata.csv", "multiqc", - "multiqc/multiqc_data", - "multiqc/multiqc_data/llms-full.txt", - "multiqc/multiqc_data/multiqc.log", - "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_citations.txt", - "multiqc/multiqc_data/multiqc_data.json", - "multiqc/multiqc_data/multiqc_software_versions.txt", - "multiqc/multiqc_data/multiqc_sources.txt", - "multiqc/multiqc_report.html", "per_group", - "per_group/combat-SRR28679756", - "per_group/combat-SRR28679756-0.5", - "per_group/combat-SRR28679756-0.5/paga", - "per_group/combat-SRR28679756-0.5/paga/combat-SRR28679756-0.5_paga.png", - "per_group/combat-SRR28679756-0.5_leiden", - "per_group/combat-SRR28679756-0.5_leiden/characteristic_genes", - "per_group/combat-SRR28679756-0.5_leiden/characteristic_genes/combat-SRR28679756-0.5_leiden_characteristic_genes.png", - "per_group/combat-SRR28679756-1.0", - "per_group/combat-SRR28679756-1.0/paga", - "per_group/combat-SRR28679756-1.0/paga/combat-SRR28679756-1.0_paga.png", - "per_group/combat-SRR28679756-1.0_leiden", - "per_group/combat-SRR28679756-1.0_leiden/characteristic_genes", - "per_group/combat-SRR28679756-1.0_leiden/characteristic_genes/combat-SRR28679756-1.0_leiden_characteristic_genes.png", - "per_group/combat-SRR28679756/paga", - "per_group/combat-SRR28679757", - "per_group/combat-SRR28679757-0.5", - "per_group/combat-SRR28679757-0.5/paga", - "per_group/combat-SRR28679757-0.5/paga/combat-SRR28679757-0.5_paga.png", - "per_group/combat-SRR28679757-0.5_leiden", - "per_group/combat-SRR28679757-0.5_leiden/characteristic_genes", - "per_group/combat-SRR28679757-0.5_leiden/characteristic_genes/combat-SRR28679757-0.5_leiden_characteristic_genes.png", - "per_group/combat-SRR28679757-1.0", - "per_group/combat-SRR28679757-1.0/paga", - "per_group/combat-SRR28679757-1.0/paga/combat-SRR28679757-1.0_paga.png", - "per_group/combat-SRR28679757-1.0_leiden", - "per_group/combat-SRR28679757-1.0_leiden/characteristic_genes", - "per_group/combat-SRR28679757-1.0_leiden/characteristic_genes/combat-SRR28679757-1.0_leiden_characteristic_genes.png", - "per_group/combat-SRR28679757/paga", - "per_group/combat-SRR28679758", - "per_group/combat-SRR28679758-0.5", - "per_group/combat-SRR28679758-0.5/paga", - "per_group/combat-SRR28679758-0.5/paga/combat-SRR28679758-0.5_paga.png", - "per_group/combat-SRR28679758-0.5_leiden", - "per_group/combat-SRR28679758-0.5_leiden/characteristic_genes", - "per_group/combat-SRR28679758-0.5_leiden/characteristic_genes/combat-SRR28679758-0.5_leiden_characteristic_genes.png", - "per_group/combat-SRR28679758-1.0", - "per_group/combat-SRR28679758-1.0/paga", - "per_group/combat-SRR28679758-1.0/paga/combat-SRR28679758-1.0_paga.png", - "per_group/combat-SRR28679758-1.0_leiden", - "per_group/combat-SRR28679758-1.0_leiden/characteristic_genes", - "per_group/combat-SRR28679758-1.0_leiden/characteristic_genes/combat-SRR28679758-1.0_leiden_characteristic_genes.png", - "per_group/combat-SRR28679758/paga", - "per_group/condition:combat-SRR28679756-0.5_leiden:0", - "per_group/condition:combat-SRR28679756-0.5_leiden:0/characteristic_genes", - "per_group/condition:combat-SRR28679756-0.5_leiden:1", - "per_group/condition:combat-SRR28679756-0.5_leiden:1/characteristic_genes", - "per_group/condition:combat-SRR28679756-0.5_leiden:2", - "per_group/condition:combat-SRR28679756-0.5_leiden:2/characteristic_genes", - "per_group/condition:combat-SRR28679756-0.5_leiden:3", - "per_group/condition:combat-SRR28679756-0.5_leiden:3/characteristic_genes", - "per_group/condition:combat-SRR28679756-0.5_leiden:4", - "per_group/condition:combat-SRR28679756-0.5_leiden:4/characteristic_genes", - "per_group/condition:combat-SRR28679756-0.5_leiden:5", - "per_group/condition:combat-SRR28679756-0.5_leiden:5/characteristic_genes", - "per_group/condition:combat-SRR28679756-0.5_leiden:6", - "per_group/condition:combat-SRR28679756-0.5_leiden:6/characteristic_genes", - "per_group/condition:combat-SRR28679756-0.5_leiden:7", - "per_group/condition:combat-SRR28679756-0.5_leiden:7/characteristic_genes", - "per_group/condition:combat-SRR28679756-0.5_leiden:8", - "per_group/condition:combat-SRR28679756-0.5_leiden:8/characteristic_genes", - "per_group/condition:combat-SRR28679756-0.5_leiden:9", - "per_group/condition:combat-SRR28679756-0.5_leiden:9/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:0", - "per_group/condition:combat-SRR28679756-1.0_leiden:0/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:1", - "per_group/condition:combat-SRR28679756-1.0_leiden:1/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:10", - "per_group/condition:combat-SRR28679756-1.0_leiden:10/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:11", - "per_group/condition:combat-SRR28679756-1.0_leiden:11/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:12", - "per_group/condition:combat-SRR28679756-1.0_leiden:12/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:13", - "per_group/condition:combat-SRR28679756-1.0_leiden:13/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:14", - "per_group/condition:combat-SRR28679756-1.0_leiden:14/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:15", - "per_group/condition:combat-SRR28679756-1.0_leiden:15/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:2", - "per_group/condition:combat-SRR28679756-1.0_leiden:2/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:3", - "per_group/condition:combat-SRR28679756-1.0_leiden:3/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:4", - "per_group/condition:combat-SRR28679756-1.0_leiden:4/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:5", - "per_group/condition:combat-SRR28679756-1.0_leiden:5/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:6", - "per_group/condition:combat-SRR28679756-1.0_leiden:6/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:7", - "per_group/condition:combat-SRR28679756-1.0_leiden:7/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:8", - "per_group/condition:combat-SRR28679756-1.0_leiden:8/characteristic_genes", - "per_group/condition:combat-SRR28679756-1.0_leiden:9", - "per_group/condition:combat-SRR28679756-1.0_leiden:9/characteristic_genes", - "per_group/condition:combat-SRR28679757-0.5_leiden:0", - "per_group/condition:combat-SRR28679757-0.5_leiden:0/characteristic_genes", - "per_group/condition:combat-SRR28679757-0.5_leiden:1", - "per_group/condition:combat-SRR28679757-0.5_leiden:1/characteristic_genes", - "per_group/condition:combat-SRR28679757-0.5_leiden:2", - "per_group/condition:combat-SRR28679757-0.5_leiden:2/characteristic_genes", - "per_group/condition:combat-SRR28679757-0.5_leiden:3", - "per_group/condition:combat-SRR28679757-0.5_leiden:3/characteristic_genes", - "per_group/condition:combat-SRR28679757-0.5_leiden:4", - "per_group/condition:combat-SRR28679757-0.5_leiden:4/characteristic_genes", - "per_group/condition:combat-SRR28679757-0.5_leiden:5", - "per_group/condition:combat-SRR28679757-0.5_leiden:5/characteristic_genes", - "per_group/condition:combat-SRR28679757-0.5_leiden:6", - "per_group/condition:combat-SRR28679757-0.5_leiden:6/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:0", - "per_group/condition:combat-SRR28679757-1.0_leiden:0/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:1", - "per_group/condition:combat-SRR28679757-1.0_leiden:1/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:10", - "per_group/condition:combat-SRR28679757-1.0_leiden:10/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:11", - "per_group/condition:combat-SRR28679757-1.0_leiden:11/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:12", - "per_group/condition:combat-SRR28679757-1.0_leiden:12/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:2", - "per_group/condition:combat-SRR28679757-1.0_leiden:2/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:3", - "per_group/condition:combat-SRR28679757-1.0_leiden:3/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:4", - "per_group/condition:combat-SRR28679757-1.0_leiden:4/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:5", - "per_group/condition:combat-SRR28679757-1.0_leiden:5/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:6", - "per_group/condition:combat-SRR28679757-1.0_leiden:6/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:7", - "per_group/condition:combat-SRR28679757-1.0_leiden:7/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:8", - "per_group/condition:combat-SRR28679757-1.0_leiden:8/characteristic_genes", - "per_group/condition:combat-SRR28679757-1.0_leiden:9", - "per_group/condition:combat-SRR28679757-1.0_leiden:9/characteristic_genes", - "per_group/condition:combat-SRR28679758-0.5_leiden:0", - "per_group/condition:combat-SRR28679758-0.5_leiden:0/characteristic_genes", - "per_group/condition:combat-SRR28679758-0.5_leiden:1", - "per_group/condition:combat-SRR28679758-0.5_leiden:1/characteristic_genes", - "per_group/condition:combat-SRR28679758-0.5_leiden:2", - "per_group/condition:combat-SRR28679758-0.5_leiden:2/characteristic_genes", - "per_group/condition:combat-SRR28679758-0.5_leiden:3", - "per_group/condition:combat-SRR28679758-0.5_leiden:3/characteristic_genes", - "per_group/condition:combat-SRR28679758-0.5_leiden:4", - "per_group/condition:combat-SRR28679758-0.5_leiden:4/characteristic_genes", - "per_group/condition:combat-SRR28679758-0.5_leiden:5", - "per_group/condition:combat-SRR28679758-0.5_leiden:5/characteristic_genes", - "per_group/condition:combat-SRR28679758-0.5_leiden:6", - "per_group/condition:combat-SRR28679758-0.5_leiden:6/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:0", - "per_group/condition:combat-SRR28679758-1.0_leiden:0/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:1", - "per_group/condition:combat-SRR28679758-1.0_leiden:1/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:10", - "per_group/condition:combat-SRR28679758-1.0_leiden:10/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:11", - "per_group/condition:combat-SRR28679758-1.0_leiden:11/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:12", - "per_group/condition:combat-SRR28679758-1.0_leiden:12/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:13", - "per_group/condition:combat-SRR28679758-1.0_leiden:13/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:2", - "per_group/condition:combat-SRR28679758-1.0_leiden:2/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:3", - "per_group/condition:combat-SRR28679758-1.0_leiden:3/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:4", - "per_group/condition:combat-SRR28679758-1.0_leiden:4/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:5", - "per_group/condition:combat-SRR28679758-1.0_leiden:5/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:6", - "per_group/condition:combat-SRR28679758-1.0_leiden:6/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:7", - "per_group/condition:combat-SRR28679758-1.0_leiden:7/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:8", - "per_group/condition:combat-SRR28679758-1.0_leiden:8/characteristic_genes", - "per_group/condition:combat-SRR28679758-1.0_leiden:9", - "per_group/condition:combat-SRR28679758-1.0_leiden:9/characteristic_genes", - "per_group/condition:harmony-SRR28679756-0.5_leiden:0", - "per_group/condition:harmony-SRR28679756-0.5_leiden:0/characteristic_genes", - "per_group/condition:harmony-SRR28679756-0.5_leiden:1", - "per_group/condition:harmony-SRR28679756-0.5_leiden:1/characteristic_genes", - "per_group/condition:harmony-SRR28679756-0.5_leiden:2", - "per_group/condition:harmony-SRR28679756-0.5_leiden:2/characteristic_genes", - "per_group/condition:harmony-SRR28679756-0.5_leiden:3", - "per_group/condition:harmony-SRR28679756-0.5_leiden:3/characteristic_genes", - "per_group/condition:harmony-SRR28679756-0.5_leiden:4", - "per_group/condition:harmony-SRR28679756-0.5_leiden:4/characteristic_genes", - "per_group/condition:harmony-SRR28679756-1.0_leiden:0", - "per_group/condition:harmony-SRR28679756-1.0_leiden:0/characteristic_genes", - "per_group/condition:harmony-SRR28679756-1.0_leiden:1", - "per_group/condition:harmony-SRR28679756-1.0_leiden:1/characteristic_genes", - "per_group/condition:harmony-SRR28679756-1.0_leiden:2", - "per_group/condition:harmony-SRR28679756-1.0_leiden:2/characteristic_genes", - "per_group/condition:harmony-SRR28679756-1.0_leiden:3", - "per_group/condition:harmony-SRR28679756-1.0_leiden:3/characteristic_genes", - "per_group/condition:harmony-SRR28679756-1.0_leiden:4", - "per_group/condition:harmony-SRR28679756-1.0_leiden:4/characteristic_genes", - "per_group/condition:harmony-SRR28679756-1.0_leiden:5", - "per_group/condition:harmony-SRR28679756-1.0_leiden:5/characteristic_genes", - "per_group/condition:harmony-SRR28679756-1.0_leiden:6", - "per_group/condition:harmony-SRR28679756-1.0_leiden:6/characteristic_genes", - "per_group/condition:harmony-SRR28679756-1.0_leiden:7", - "per_group/condition:harmony-SRR28679756-1.0_leiden:7/characteristic_genes", - "per_group/condition:harmony-SRR28679756-1.0_leiden:8", - "per_group/condition:harmony-SRR28679756-1.0_leiden:8/characteristic_genes", - "per_group/condition:harmony-SRR28679757-0.5_leiden:0", - "per_group/condition:harmony-SRR28679757-0.5_leiden:0/characteristic_genes", - "per_group/condition:harmony-SRR28679757-0.5_leiden:1", - "per_group/condition:harmony-SRR28679757-0.5_leiden:1/characteristic_genes", - "per_group/condition:harmony-SRR28679757-0.5_leiden:2", - "per_group/condition:harmony-SRR28679757-0.5_leiden:2/characteristic_genes", - "per_group/condition:harmony-SRR28679757-0.5_leiden:3", - "per_group/condition:harmony-SRR28679757-0.5_leiden:3/characteristic_genes", - "per_group/condition:harmony-SRR28679757-0.5_leiden:4", - "per_group/condition:harmony-SRR28679757-0.5_leiden:4/characteristic_genes", - "per_group/condition:harmony-SRR28679757-1.0_leiden:0", - "per_group/condition:harmony-SRR28679757-1.0_leiden:0/characteristic_genes", - "per_group/condition:harmony-SRR28679757-1.0_leiden:1", - "per_group/condition:harmony-SRR28679757-1.0_leiden:1/characteristic_genes", - "per_group/condition:harmony-SRR28679757-1.0_leiden:2", - "per_group/condition:harmony-SRR28679757-1.0_leiden:2/characteristic_genes", - "per_group/condition:harmony-SRR28679757-1.0_leiden:3", - "per_group/condition:harmony-SRR28679757-1.0_leiden:3/characteristic_genes", - "per_group/condition:harmony-SRR28679757-1.0_leiden:4", - "per_group/condition:harmony-SRR28679757-1.0_leiden:4/characteristic_genes", - "per_group/condition:harmony-SRR28679757-1.0_leiden:5", - "per_group/condition:harmony-SRR28679757-1.0_leiden:5/characteristic_genes", - "per_group/condition:harmony-SRR28679757-1.0_leiden:6", - "per_group/condition:harmony-SRR28679757-1.0_leiden:6/characteristic_genes", - "per_group/condition:harmony-SRR28679757-1.0_leiden:7", - "per_group/condition:harmony-SRR28679757-1.0_leiden:7/characteristic_genes", - "per_group/condition:harmony-SRR28679757-1.0_leiden:8", - "per_group/condition:harmony-SRR28679757-1.0_leiden:8/characteristic_genes", - "per_group/condition:harmony-SRR28679757-1.0_leiden:9", - "per_group/condition:harmony-SRR28679757-1.0_leiden:9/characteristic_genes", - "per_group/condition:harmony-SRR28679758-0.5_leiden:0", - "per_group/condition:harmony-SRR28679758-0.5_leiden:0/characteristic_genes", - "per_group/condition:harmony-SRR28679758-0.5_leiden:1", - "per_group/condition:harmony-SRR28679758-0.5_leiden:1/characteristic_genes", - "per_group/condition:harmony-SRR28679758-0.5_leiden:2", - "per_group/condition:harmony-SRR28679758-0.5_leiden:2/characteristic_genes", - "per_group/condition:harmony-SRR28679758-0.5_leiden:3", - "per_group/condition:harmony-SRR28679758-0.5_leiden:3/characteristic_genes", - "per_group/condition:harmony-SRR28679758-0.5_leiden:4", - "per_group/condition:harmony-SRR28679758-0.5_leiden:4/characteristic_genes", - "per_group/condition:harmony-SRR28679758-1.0_leiden:0", - "per_group/condition:harmony-SRR28679758-1.0_leiden:0/characteristic_genes", - "per_group/condition:harmony-SRR28679758-1.0_leiden:1", - "per_group/condition:harmony-SRR28679758-1.0_leiden:1/characteristic_genes", - "per_group/condition:harmony-SRR28679758-1.0_leiden:2", - "per_group/condition:harmony-SRR28679758-1.0_leiden:2/characteristic_genes", - "per_group/condition:harmony-SRR28679758-1.0_leiden:3", - "per_group/condition:harmony-SRR28679758-1.0_leiden:3/characteristic_genes", - "per_group/condition:harmony-SRR28679758-1.0_leiden:4", - "per_group/condition:harmony-SRR28679758-1.0_leiden:4/characteristic_genes", - "per_group/condition:harmony-SRR28679758-1.0_leiden:5", - "per_group/condition:harmony-SRR28679758-1.0_leiden:5/characteristic_genes", - "per_group/condition:harmony-SRR28679758-1.0_leiden:6", - "per_group/condition:harmony-SRR28679758-1.0_leiden:6/characteristic_genes", - "per_group/condition:harmony-SRR28679758-1.0_leiden:7", - "per_group/condition:harmony-SRR28679758-1.0_leiden:7/characteristic_genes", - "per_group/condition:harmony-SRR28679758-1.0_leiden:8", - "per_group/condition:harmony-SRR28679758-1.0_leiden:8/characteristic_genes", - "per_group/condition:sample:SRR28679756", - "per_group/condition:sample:SRR28679756/characteristic_genes", - "per_group/condition:sample:SRR28679757", - "per_group/condition:sample:SRR28679757/characteristic_genes", - "per_group/condition:sample:SRR28679758", - "per_group/condition:sample:SRR28679758/characteristic_genes", - "per_group/condition:scvi-SRR28679756-0.5_leiden:0", - "per_group/condition:scvi-SRR28679756-0.5_leiden:0/characteristic_genes", - "per_group/condition:scvi-SRR28679756-0.5_leiden:1", - "per_group/condition:scvi-SRR28679756-0.5_leiden:1/characteristic_genes", - "per_group/condition:scvi-SRR28679756-0.5_leiden:2", - "per_group/condition:scvi-SRR28679756-0.5_leiden:2/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:0", - "per_group/condition:scvi-SRR28679756-1.0_leiden:0/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:1", - "per_group/condition:scvi-SRR28679756-1.0_leiden:1/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:10", - "per_group/condition:scvi-SRR28679756-1.0_leiden:10/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:11", - "per_group/condition:scvi-SRR28679756-1.0_leiden:11/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:12", - "per_group/condition:scvi-SRR28679756-1.0_leiden:12/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:2", - "per_group/condition:scvi-SRR28679756-1.0_leiden:2/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:3", - "per_group/condition:scvi-SRR28679756-1.0_leiden:3/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:4", - "per_group/condition:scvi-SRR28679756-1.0_leiden:4/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:5", - "per_group/condition:scvi-SRR28679756-1.0_leiden:5/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:6", - "per_group/condition:scvi-SRR28679756-1.0_leiden:6/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:7", - "per_group/condition:scvi-SRR28679756-1.0_leiden:7/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:8", - "per_group/condition:scvi-SRR28679756-1.0_leiden:8/characteristic_genes", - "per_group/condition:scvi-SRR28679756-1.0_leiden:9", - "per_group/condition:scvi-SRR28679756-1.0_leiden:9/characteristic_genes", - "per_group/condition:scvi-SRR28679757-0.5_leiden:0", - "per_group/condition:scvi-SRR28679757-0.5_leiden:0/characteristic_genes", - "per_group/condition:scvi-SRR28679757-0.5_leiden:1", - "per_group/condition:scvi-SRR28679757-0.5_leiden:1/characteristic_genes", - "per_group/condition:scvi-SRR28679757-0.5_leiden:2", - "per_group/condition:scvi-SRR28679757-0.5_leiden:2/characteristic_genes", - "per_group/condition:scvi-SRR28679757-0.5_leiden:3", - "per_group/condition:scvi-SRR28679757-0.5_leiden:3/characteristic_genes", - "per_group/condition:scvi-SRR28679757-0.5_leiden:4", - "per_group/condition:scvi-SRR28679757-0.5_leiden:4/characteristic_genes", - "per_group/condition:scvi-SRR28679757-0.5_leiden:5", - "per_group/condition:scvi-SRR28679757-0.5_leiden:5/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:0", - "per_group/condition:scvi-SRR28679757-1.0_leiden:0/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:1", - "per_group/condition:scvi-SRR28679757-1.0_leiden:1/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:10", - "per_group/condition:scvi-SRR28679757-1.0_leiden:10/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:11", - "per_group/condition:scvi-SRR28679757-1.0_leiden:11/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:12", - "per_group/condition:scvi-SRR28679757-1.0_leiden:12/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:2", - "per_group/condition:scvi-SRR28679757-1.0_leiden:2/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:3", - "per_group/condition:scvi-SRR28679757-1.0_leiden:3/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:4", - "per_group/condition:scvi-SRR28679757-1.0_leiden:4/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:5", - "per_group/condition:scvi-SRR28679757-1.0_leiden:5/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:6", - "per_group/condition:scvi-SRR28679757-1.0_leiden:6/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:7", - "per_group/condition:scvi-SRR28679757-1.0_leiden:7/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:8", - "per_group/condition:scvi-SRR28679757-1.0_leiden:8/characteristic_genes", - "per_group/condition:scvi-SRR28679757-1.0_leiden:9", - "per_group/condition:scvi-SRR28679757-1.0_leiden:9/characteristic_genes", - "per_group/condition:scvi-SRR28679758-0.5_leiden:0", - "per_group/condition:scvi-SRR28679758-0.5_leiden:0/characteristic_genes", - "per_group/condition:scvi-SRR28679758-0.5_leiden:1", - "per_group/condition:scvi-SRR28679758-0.5_leiden:1/characteristic_genes", - "per_group/condition:scvi-SRR28679758-0.5_leiden:2", - "per_group/condition:scvi-SRR28679758-0.5_leiden:2/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:0", - "per_group/condition:scvi-SRR28679758-1.0_leiden:0/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:1", - "per_group/condition:scvi-SRR28679758-1.0_leiden:1/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:10", - "per_group/condition:scvi-SRR28679758-1.0_leiden:10/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:11", - "per_group/condition:scvi-SRR28679758-1.0_leiden:11/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:12", - "per_group/condition:scvi-SRR28679758-1.0_leiden:12/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:13", - "per_group/condition:scvi-SRR28679758-1.0_leiden:13/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:2", - "per_group/condition:scvi-SRR28679758-1.0_leiden:2/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:3", - "per_group/condition:scvi-SRR28679758-1.0_leiden:3/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:4", - "per_group/condition:scvi-SRR28679758-1.0_leiden:4/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:5", - "per_group/condition:scvi-SRR28679758-1.0_leiden:5/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:6", - "per_group/condition:scvi-SRR28679758-1.0_leiden:6/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:7", - "per_group/condition:scvi-SRR28679758-1.0_leiden:7/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:8", - "per_group/condition:scvi-SRR28679758-1.0_leiden:8/characteristic_genes", - "per_group/condition:scvi-SRR28679758-1.0_leiden:9", - "per_group/condition:scvi-SRR28679758-1.0_leiden:9/characteristic_genes", - "per_group/harmony-SRR28679756", - "per_group/harmony-SRR28679756-0.5", - "per_group/harmony-SRR28679756-0.5/paga", - "per_group/harmony-SRR28679756-0.5/paga/harmony-SRR28679756-0.5_paga.png", - "per_group/harmony-SRR28679756-0.5_leiden", - "per_group/harmony-SRR28679756-0.5_leiden/characteristic_genes", - "per_group/harmony-SRR28679756-0.5_leiden/characteristic_genes/harmony-SRR28679756-0.5_leiden_characteristic_genes.png", - "per_group/harmony-SRR28679756-1.0", - "per_group/harmony-SRR28679756-1.0/paga", - "per_group/harmony-SRR28679756-1.0/paga/harmony-SRR28679756-1.0_paga.png", - "per_group/harmony-SRR28679756-1.0_leiden", - "per_group/harmony-SRR28679756-1.0_leiden/characteristic_genes", - "per_group/harmony-SRR28679756-1.0_leiden/characteristic_genes/harmony-SRR28679756-1.0_leiden_characteristic_genes.png", - "per_group/harmony-SRR28679756/paga", - "per_group/harmony-SRR28679757", - "per_group/harmony-SRR28679757-0.5", - "per_group/harmony-SRR28679757-0.5/paga", - "per_group/harmony-SRR28679757-0.5/paga/harmony-SRR28679757-0.5_paga.png", - "per_group/harmony-SRR28679757-0.5_leiden", - "per_group/harmony-SRR28679757-0.5_leiden/characteristic_genes", - "per_group/harmony-SRR28679757-0.5_leiden/characteristic_genes/harmony-SRR28679757-0.5_leiden_characteristic_genes.png", - "per_group/harmony-SRR28679757-1.0", - "per_group/harmony-SRR28679757-1.0/paga", - "per_group/harmony-SRR28679757-1.0/paga/harmony-SRR28679757-1.0_paga.png", - "per_group/harmony-SRR28679757-1.0_leiden", - "per_group/harmony-SRR28679757-1.0_leiden/characteristic_genes", - "per_group/harmony-SRR28679757-1.0_leiden/characteristic_genes/harmony-SRR28679757-1.0_leiden_characteristic_genes.png", - "per_group/harmony-SRR28679757/paga", - "per_group/harmony-SRR28679758", - "per_group/harmony-SRR28679758-0.5", - "per_group/harmony-SRR28679758-0.5/paga", - "per_group/harmony-SRR28679758-0.5/paga/harmony-SRR28679758-0.5_paga.png", - "per_group/harmony-SRR28679758-0.5_leiden", - "per_group/harmony-SRR28679758-0.5_leiden/characteristic_genes", - "per_group/harmony-SRR28679758-0.5_leiden/characteristic_genes/harmony-SRR28679758-0.5_leiden_characteristic_genes.png", - "per_group/harmony-SRR28679758-1.0", - "per_group/harmony-SRR28679758-1.0/paga", - "per_group/harmony-SRR28679758-1.0/paga/harmony-SRR28679758-1.0_paga.png", - "per_group/harmony-SRR28679758-1.0_leiden", - "per_group/harmony-SRR28679758-1.0_leiden/characteristic_genes", - "per_group/harmony-SRR28679758-1.0_leiden/characteristic_genes/harmony-SRR28679758-1.0_leiden_characteristic_genes.png", - "per_group/harmony-SRR28679758/paga", - "per_group/sample", - "per_group/sample/characteristic_genes", - "per_group/sample/characteristic_genes/sample_characteristic_genes.png", - "per_group/scvi-SRR28679756", - "per_group/scvi-SRR28679756-0.5", - "per_group/scvi-SRR28679756-0.5/paga", - "per_group/scvi-SRR28679756-0.5/paga/scvi-SRR28679756-0.5_paga.png", - "per_group/scvi-SRR28679756-0.5_leiden", - "per_group/scvi-SRR28679756-0.5_leiden/characteristic_genes", - "per_group/scvi-SRR28679756-0.5_leiden/characteristic_genes/scvi-SRR28679756-0.5_leiden_characteristic_genes.png", - "per_group/scvi-SRR28679756-1.0", - "per_group/scvi-SRR28679756-1.0/paga", - "per_group/scvi-SRR28679756-1.0/paga/scvi-SRR28679756-1.0_paga.png", - "per_group/scvi-SRR28679756-1.0_leiden", - "per_group/scvi-SRR28679756-1.0_leiden/characteristic_genes", - "per_group/scvi-SRR28679756-1.0_leiden/characteristic_genes/scvi-SRR28679756-1.0_leiden_characteristic_genes.png", - "per_group/scvi-SRR28679756/paga", - "per_group/scvi-SRR28679757", - "per_group/scvi-SRR28679757-0.5", - "per_group/scvi-SRR28679757-0.5/paga", - "per_group/scvi-SRR28679757-0.5/paga/scvi-SRR28679757-0.5_paga.png", - "per_group/scvi-SRR28679757-0.5_leiden", - "per_group/scvi-SRR28679757-0.5_leiden/characteristic_genes", - "per_group/scvi-SRR28679757-0.5_leiden/characteristic_genes/scvi-SRR28679757-0.5_leiden_characteristic_genes.png", - "per_group/scvi-SRR28679757-1.0", - "per_group/scvi-SRR28679757-1.0/paga", - "per_group/scvi-SRR28679757-1.0/paga/scvi-SRR28679757-1.0_paga.png", - "per_group/scvi-SRR28679757-1.0_leiden", - "per_group/scvi-SRR28679757-1.0_leiden/characteristic_genes", - "per_group/scvi-SRR28679757-1.0_leiden/characteristic_genes/scvi-SRR28679757-1.0_leiden_characteristic_genes.png", - "per_group/scvi-SRR28679757/paga", - "per_group/scvi-SRR28679758", - "per_group/scvi-SRR28679758-0.5", - "per_group/scvi-SRR28679758-0.5/paga", - "per_group/scvi-SRR28679758-0.5/paga/scvi-SRR28679758-0.5_paga.png", - "per_group/scvi-SRR28679758-0.5_leiden", - "per_group/scvi-SRR28679758-0.5_leiden/characteristic_genes", - "per_group/scvi-SRR28679758-0.5_leiden/characteristic_genes/scvi-SRR28679758-0.5_leiden_characteristic_genes.png", - "per_group/scvi-SRR28679758-1.0", - "per_group/scvi-SRR28679758-1.0/paga", - "per_group/scvi-SRR28679758-1.0/paga/scvi-SRR28679758-1.0_paga.png", - "per_group/scvi-SRR28679758-1.0_leiden", - "per_group/scvi-SRR28679758-1.0_leiden/characteristic_genes", - "per_group/scvi-SRR28679758-1.0_leiden/characteristic_genes/scvi-SRR28679758-1.0_leiden_characteristic_genes.png", - "per_group/scvi-SRR28679758/paga", "pipeline_info", "pipeline_info/nf_core_scdownstream_software_mqc_versions.yml", "splitcol", @@ -593,7 +124,7 @@ "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f" ] ], - "timestamp": "2026-03-22T17:54:46.906369255", + "timestamp": "2026-03-31T19:17:28.230563871", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" diff --git a/workflows/scdownstream.nf b/workflows/scdownstream.nf index 15f708e4..2fe98b5c 100644 --- a/workflows/scdownstream.nf +++ b/workflows/scdownstream.nf @@ -320,16 +320,9 @@ workflow SCDOWNSTREAM { // // MODULE: MultiQC // - ch_multiqc_config = channel.fromPath( - "${projectDir}/assets/multiqc_config.yml", - checkIfExists: true - ) - ch_multiqc_custom_config = multiqc_config - ? channel.fromPath(multiqc_config, checkIfExists: true) - : channel.empty() - ch_multiqc_logo = multiqc_logo - ? channel.fromPath(multiqc_logo, checkIfExists: true) - : channel.empty() + def mqc_config = file("${projectDir}/assets/multiqc_config.yml", checkIfExists: true) + def mqc_configs = multiqc_config ? [mqc_config, file(multiqc_config, checkIfExists: true)] : [mqc_config] + def mqc_logo = multiqc_logo ? file(multiqc_logo, checkIfExists: true) : [] summary_params = paramsSummaryMap( workflow, @@ -353,14 +346,11 @@ workflow SCDOWNSTREAM { ) MULTIQC ( - ch_multiqc_files.collect(), - ch_multiqc_config.toList(), - ch_multiqc_custom_config.toList(), - ch_multiqc_logo.toList(), - [], - [], + ch_multiqc_files + .collect() + .map { files -> [[id: 'multiqc'], files, mqc_configs, mqc_logo, [], []] } ) - ch_multiqc_report = MULTIQC.out.report.toList() + ch_multiqc_report = MULTIQC.out.report.map { _meta, report -> report }.toList() emit: multiqc_report = ch_multiqc_report // channel: [ path(multiqc_report.html) ]