From d2986bae529d407d999ff0d154401aa44d3ca0ae Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Wed, 14 Oct 2026 18:05:40 +0100 Subject: [PATCH 01/24] taxonomy decision and add euk rna support --- bin/count_rna.py | 48 +- conf/containers_conda_lock_files_amd64.config | 3 +- conf/containers_conda_lock_files_arm64.config | 2 +- conf/containers_docker_amd64.config | 1 + conf/containers_docker_arm64.config | 1 - .../containers_singularity_https_amd64.config | 1 + conf/containers_singularity_oras_amd64.config | 1 + conf/modules.config | 6 + modules.json | 10 + modules/local/count_rna/main.nf | 2 + modules/local/count_rna/meta.yml | 30 +- modules/local/eukcc/binlinks/environment.yml | 0 modules/local/eukcc/binlinks/main.nf | 76 + modules/local/eukcc/folder/environment.yml | 7 + modules/local/eukcc/folder/main.nf | 70 + .../linux_amd64-bd-6d1f7006d91892b3_1.txt | 3042 +++++++++++++++++ modules/nf-core/busco/busco/environment.yml | 7 + modules/nf-core/busco/busco/main.nf | 132 + modules/nf-core/busco/busco/meta.yml | 248 ++ .../nf-core/busco/busco/tests/main.nf.test | 422 +++ .../busco/busco/tests/main.nf.test.snap | 182 + .../nf-core/busco/busco/tests/nextflow.config | 5 + subworkflows/local/rna_detection/main.nf | 2 +- subworkflows/local/rna_detection/meta.yml | 21 +- .../local/rna_detection/tests/main.nf.test | 132 + .../rna_detection/tests/main.nf.test.snap | 81 + workflows/genomesubmit.nf | 100 +- 27 files changed, 4549 insertions(+), 83 deletions(-) create mode 100644 modules/local/eukcc/binlinks/environment.yml create mode 100644 modules/local/eukcc/binlinks/main.nf create mode 100644 modules/local/eukcc/folder/environment.yml create mode 100644 modules/local/eukcc/folder/main.nf create mode 100644 modules/nf-core/busco/busco/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt create mode 100644 modules/nf-core/busco/busco/environment.yml create mode 100644 modules/nf-core/busco/busco/main.nf create mode 100644 modules/nf-core/busco/busco/meta.yml create mode 100644 modules/nf-core/busco/busco/tests/main.nf.test create mode 100644 modules/nf-core/busco/busco/tests/main.nf.test.snap create mode 100644 modules/nf-core/busco/busco/tests/nextflow.config create mode 100644 subworkflows/local/rna_detection/tests/main.nf.test create mode 100644 subworkflows/local/rna_detection/tests/main.nf.test.snap diff --git a/bin/count_rna.py b/bin/count_rna.py index 8f340118..6af073c4 100755 --- a/bin/count_rna.py +++ b/bin/count_rna.py @@ -6,6 +6,7 @@ import argparse import logging +import re # Expected rRNA gene lengths @@ -18,6 +19,13 @@ "5_8S_rRNA": 155, } +# rRNA genes required per domain (gene names as reported by barrnap for each --kingdom) +REQUIRED_RRNA = { + "bac": ["16S_rRNA", "23S_rRNA", "5S_rRNA"], + "arc": ["16S_rRNA", "23S_rRNA", "5S_rRNA"], + "euk": ["18S_rRNA", "28S_rRNA", "5_8S_rRNA", "5S_rRNA"], +} + AA = [ "Ala", "Gly", @@ -41,14 +49,17 @@ "Trp", ] +TRNASCAN_REGEXP = r"^\s*(\S+)\s*:\s*(\d+)" + logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') def parse_args(): parser = argparse.ArgumentParser( description="Script parses tRNAscan-SE output and barrnap GFF output, and writes a decision " "of whether RNA genes are present in the genome. Decision is 'True' if number of tRNA genes " - "is at least --trna-limit and 16S, 23S, and 5S rRNA genes have more than --rrna-limit percentage " - "of gene length recovered, and 'False' otherwise." + "is at least --trna-limit and all rRNA genes required for --domain (16S, 23S and 5S for bac/arc; " + "18S, 28S, 5.8S and 5S for euk) have at least --rrna-limit percentage of gene length recovered, " + "and 'False' otherwise." ) parser.add_argument("-t", "--trna", dest="trna", help="trnas_stats.out from tRNAscan-SE", required=True) @@ -60,8 +71,10 @@ def parse_args(): default="rna_decision.tsv", required=False) parser.add_argument("--trna-limit", dest="trna_limit", help="Minimal required number of tRNA", required=True, type=int) - parser.add_argument("--rrna-limit", dest="rrna_limit", help="Minimum percentage of 16S, 23S, and 5S rRNA gene length recovered to count the gene as present.", - required=True, type=int) + parser.add_argument("--rrna-limit", dest="rrna_limit", help="Minimum percentage of rRNA gene length recovered to count the gene as present.", + required=True, type=float) + parser.add_argument("-d", "--domain", dest="domain", help="Taxonomic domain of the genome, defines which rRNA genes are required (default: bac)", + choices=sorted(REQUIRED_RRNA), default="bac", required=False) return parser.parse_args() @@ -87,18 +100,18 @@ def parse_trna(trna_input): if "Isotype / Anticodon" in line: start_parsing = True elif start_parsing: - cols = line.split() - if len(cols) > 1: - aa_pred = line.split()[0] - counts = int(line.split()[2]) - if aa_pred in AA: + match = re.match(TRNASCAN_REGEXP, line) + if match: + aa_pred = match.group(1) + counts = int(match.group(2)) + if any(i in aa_pred for i in AA): trnas += counts logging.info(f"Found {counts} tRNA genes for amino acid {aa_pred}") return trnas -def parse_rrna(rrna_input, rrna_limit): - """Parses barrnap GFF output and counts 16S, 23S, and 5S rRNA genes that have more than --rrna-limit percentage of gene length recovered. +def parse_rrna(rrna_input, rrna_limit, required_genes): + """Parses barrnap GFF output and counts required rRNA genes that have at least --rrna-limit percentage of gene length recovered. File example: ##gff-version 3 @@ -128,8 +141,7 @@ def parse_rrna(rrna_input, rrna_limit): break # Check if gene length meets the threshold - # For now we only consider bacterial/archaeal rRNA genes - if gene_name in ["16S_rRNA", "23S_rRNA", "5S_rRNA"]: + if gene_name in required_genes: expected_length = EXPECTED_LENGTHS[gene_name] percentage_recovered = (gene_length / expected_length) * 100 logging.info(f"Found {gene_name} with length {gene_length} bp, which is {percentage_recovered:.2f}% of expected length.") @@ -147,11 +159,13 @@ def main(): logging.info(f"Found {trna_count} tRNA in total") # parsing rRNA logging.info(f"Parsing rRNA genes from {args.rrna}") - rrna_count = parse_rrna(rrna_input=args.rrna, rrna_limit=args.rrna_limit) - logging.info(f"Found {rrna_count} rRNA subunit types in total") + required_genes = REQUIRED_RRNA[args.domain] + logging.info(f"Required rRNA genes for domain '{args.domain}': {', '.join(required_genes)}") + rrna_count = parse_rrna(rrna_input=args.rrna, rrna_limit=args.rrna_limit, required_genes=required_genes) + logging.info(f"Found {rrna_count} of {len(required_genes)} required rRNA subunit types") - # rrna_count should be 3 to make sure all 3 rRNA genes are present - decision = "True" if trna_count >= args.trna_limit and rrna_count == 3 else "False" + # all required rRNA genes must be present + decision = "True" if trna_count >= args.trna_limit and rrna_count == len(required_genes) else "False" logging.info(f"RNA presented: {decision}") with open(args.output, 'w') as file_out: diff --git a/conf/containers_conda_lock_files_amd64.config b/conf/containers_conda_lock_files_amd64.config index eb32fe50..50044143 100644 --- a/conf/containers_conda_lock_files_amd64.config +++ b/conf/containers_conda_lock_files_amd64.config @@ -1 +1,2 @@ -process { withName: 'MULTIQC' { conda = 'modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt' } } +process { withName: 'BUSCO/DOWNLOAD' { container = 'modules/nf-core/busco/download/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt' } } +process { withName: 'MULTIQC' { container = 'modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt' } } diff --git a/conf/containers_conda_lock_files_arm64.config b/conf/containers_conda_lock_files_arm64.config index 3733ddfd..6864e0b1 100644 --- a/conf/containers_conda_lock_files_arm64.config +++ b/conf/containers_conda_lock_files_arm64.config @@ -1 +1 @@ -process { withName: 'MULTIQC' { conda = 'modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt' } } +process { withName: 'MULTIQC' { container = 'modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt' } } diff --git a/conf/containers_docker_amd64.config b/conf/containers_docker_amd64.config index ea18c3f9..6b811cfc 100644 --- a/conf/containers_docker_amd64.config +++ b/conf/containers_docker_amd64.config @@ -1 +1,2 @@ +process { withName: 'BUSCO/DOWNLOAD' { container = 'community.wave.seqera.io/library/busco:6.1.0--6d1f7006d91892b3' } } process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc' } } diff --git a/conf/containers_docker_arm64.config b/conf/containers_docker_arm64.config index 11a7ab95..369f743a 100644 --- a/conf/containers_docker_arm64.config +++ b/conf/containers_docker_arm64.config @@ -1,2 +1 @@ -process { withName: 'FALINT' { container = 'community.wave.seqera.io/library/fa-lint:1.2.0--9dec293ee366e2bd' } } process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--5c84a5000a226ab5' } } diff --git a/conf/containers_singularity_https_amd64.config b/conf/containers_singularity_https_amd64.config index 932fc7c0..7ede98e1 100644 --- a/conf/containers_singularity_https_amd64.config +++ b/conf/containers_singularity_https_amd64.config @@ -1 +1,2 @@ +process { withName: 'BUSCO/DOWNLOAD' { container = 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/96/963bad66c10646cf0adb1967cc462ad04d02789ddbfae4fbb94182291dbddf8c/data' } } process { withName: 'MULTIQC' { container = 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c8/c8e346f4f6080eadf1253505e6ff09ef004454fc18e8d672006fd7b222cc412e/data' } } diff --git a/conf/containers_singularity_oras_amd64.config b/conf/containers_singularity_oras_amd64.config index 2fa065b3..a44f53d6 100644 --- a/conf/containers_singularity_oras_amd64.config +++ b/conf/containers_singularity_oras_amd64.config @@ -1 +1,2 @@ +process { withName: 'BUSCO/DOWNLOAD' { container = 'oras://community.wave.seqera.io/library/busco:6.1.0--c7528d5825eb19b5' } } process { withName: 'MULTIQC' { container = 'oras://community.wave.seqera.io/library/multiqc:1.35--c680f2aea25ccec2' } } diff --git a/conf/modules.config b/conf/modules.config index 082d9e8f..d9525adf 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -43,6 +43,7 @@ process { } withName: 'CATPACK_BINS' { + ext.args = '--no_stars' publishDir = [ path: { "${params.outdir}/${params.mode}/${meta.id}/taxonomy" }, mode: params.publish_dir_mode, @@ -86,6 +87,7 @@ process { } withName: 'TRNASCANSE' { + ext.args = { [euk: '-E', arc: '-A', bac: '-B'].get(meta.domain, '-G') } publishDir = [ path: { "${params.outdir}/${params.mode}/${meta.id}/rna/trnascanse" }, mode: params.publish_dir_mode, @@ -93,6 +95,10 @@ process { ] } + withName: 'EUKCC_FOLDER' { + ext.args = '--improve_percent 10 --n_combine 1 --improve_ratio 5 --min_links 100 --suffix .fa' + } + withName: 'COUNT_RNA' { publishDir = [ enabled: false diff --git a/modules.json b/modules.json index 8b1d819d..4f12033e 100644 --- a/modules.json +++ b/modules.json @@ -10,6 +10,16 @@ "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", "installed_by": ["modules"] }, + "busco/busco": { + "branch": "master", + "git_sha": "3927a974459b80b8e24d73e00da029e8c7335c4d", + "installed_by": ["modules"] + }, + "busco/download": { + "branch": "master", + "git_sha": "3927a974459b80b8e24d73e00da029e8c7335c4d", + "installed_by": ["modules"] + }, "catpack/addnames": { "branch": "master", "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", diff --git a/modules/local/count_rna/main.nf b/modules/local/count_rna/main.nf index 2bf5758a..e78f58d8 100644 --- a/modules/local/count_rna/main.nf +++ b/modules/local/count_rna/main.nf @@ -25,11 +25,13 @@ process COUNT_RNA { script: def prefix = task.ext.prefix ?: "${meta.id}" + def domain = meta.domain ?: 'bac' """ count_rna.py \\ --trna ${trnas_stats} \\ --rrna ${rrna_gff} \\ --name ${prefix} \\ + --domain ${domain} \\ --trna-limit ${min_trna_count} \\ --rrna-limit ${min_rrna_percentage} \\ --output ${prefix}_rna_decision.tsv diff --git a/modules/local/count_rna/meta.yml b/modules/local/count_rna/meta.yml index 4b505cfe..e4926897 100644 --- a/modules/local/count_rna/meta.yml +++ b/modules/local/count_rna/meta.yml @@ -11,42 +11,48 @@ tools: - count_rna: description: | Script that parses tRNAscan-SE output and barrnap GFF output to determine - whether RNA genes are present in the genome. Returns 'Yes' if the number of - tRNA genes meets the threshold and all three rRNA subunits (16S, 23S, 5S) - have sufficient length coverage, otherwise 'No'. + whether RNA genes are present in the genome. Returns 'True' if the number of + tRNA genes meets the threshold and all rRNA genes required for the genome's + domain have sufficient length coverage, otherwise 'False'. + Required rRNA genes: 16S, 23S and 5S for bacteria and archaea; + 18S, 28S, 5.8S and 5S for eukaryotes. licence: ["GPL v3"] input: - meta: type: map description: | - Groovy Map containing sample information - e.g. [ id:'test' ] + Groovy Map containing sample information. + `domain` defines which rRNA genes are required: 'bac', 'arc' or 'euk' (default: 'bac'). + e.g. [ id:'test', domain:'bac' ] - trnas_stats: type: file description: tRNA statistics file from tRNAscan-SE (.stats format) pattern: "*.stats" - rrna_gff: type: file - description: rRNA annotation file from barrnap (GFF3 format) + description: rRNA annotation file from barrnap (GFF3 format), predicted with the kingdom matching meta.domain pattern: "*.gff" - min_trna_count: - type: value - description: Minimum required number of tRNA genes. + type: integer + description: | + Minimum required total number of tRNA genes for the 20 standard amino acids (e.g. 18). - min_rrna_percentage: - type: value - description: Minimum required percentage coverage for each rRNA subunit. + type: float + description: | + Minimum percentage of expected gene length that must be recovered for each + required rRNA gene to count it as present (e.g. 80). output: - meta: type: map description: | Groovy Map containing sample information - e.g. [ id:'test' ] + e.g. [ id:'test', domain:'bac' ] - rna_decision: type: file description: | - Tab-separated file containing genome ID and decision (Yes/No) on whether + Tab-separated file with one line: genome ID and decision (True/False) on whether sufficient RNA genes are present pattern: "*_rna_decision.tsv" diff --git a/modules/local/eukcc/binlinks/environment.yml b/modules/local/eukcc/binlinks/environment.yml new file mode 100644 index 00000000..e69de29b diff --git a/modules/local/eukcc/binlinks/main.nf b/modules/local/eukcc/binlinks/main.nf new file mode 100644 index 00000000..27418b60 --- /dev/null +++ b/modules/local/eukcc/binlinks/main.nf @@ -0,0 +1,76 @@ +process EUKCC_LINKTABLE { + + /* + This module aligns reads to the reference using specified arguments + and produces output in the form of FASTQ.GZ, BAM and BAM.BAI files. + It also runs: + - eukcc linktable + */ + + label 'process_medium' + tag "${meta.id}" + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'oras://community.wave.seqera.io/library/eukcc:2.2.0--050b7bea3f69b4a8': + 'community.wave.seqera.io/library/bwa-mem2_eukcc_samtools:5bd64ce41bca11bf' }" + + input: + tuple val(meta), path(reads), path(ref_fasta), path(bins), path(depth) + + output: + tuple val(meta), path("*.links.csv"), emit: links_table + tuple val(meta), path("*.idxstats") , emit: idxstats + path "versions.yml" , emit: versions + + script: + def prefix = task.ext.prefix ?: "${meta.id}" + def samtools_args = task.ext.alignment_args + + """ + mkdir -p output + + echo " ---> index fasta" + bwa-mem2 index ${ref_fasta} + + echo " ---> mapping files to assembly" + bwa-mem2 mem -M \ + -t ${task.cpus} \ + ${ref_fasta} \ + ${reads} | \ + samtools view -@ ${task.cpus} ${samtools_args} - | \ + samtools sort -@ ${task.cpus} -O bam - -o output/${meta.id}_sorted.bam + + echo "samtools index sorted bam" + samtools index -@ ${task.cpus} output/${meta.id}_sorted.bam + + echo " ---> samtools idxstats sorted bam" + samtools idxstats --threads ${task.cpus} output/${meta.id}_sorted.bam > ${prefix}.idxstats + + echo "linktable" + mkdir -p bins + cp ${bins}/* bins/ + + export BINS=\$(ls bins | grep -v "unbinned" | wc -l) + if [ \$BINS -eq 0 ]; then + echo "Bins directory is empty" + touch ${meta.id}.links.csv + else + ggp_binlinks.py --ANI 99 \ + --within 1500 \ + --out ${meta.id}.links.csv \ + --debug \ + --bindir bins \ + --bam output/${meta.id}_sorted.bam + fi + + rm -rf output + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bwa-mem2: \$(bwa-mem2 version 2> /dev/null) + biopython: \$(python3 -c "import pkg_resources; print(pkg_resources.get_distribution('biopython').version)") + pysam: \$(python3 -c "import pkg_resources; print(pkg_resources.get_distribution('pysam').version)") + END_VERSIONS + """ +} \ No newline at end of file diff --git a/modules/local/eukcc/folder/environment.yml b/modules/local/eukcc/folder/environment.yml new file mode 100644 index 00000000..15d04b42 --- /dev/null +++ b/modules/local/eukcc/folder/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - "bioconda::eukcc=2.2.0" diff --git a/modules/local/eukcc/folder/main.nf b/modules/local/eukcc/folder/main.nf new file mode 100644 index 00000000..605f4272 --- /dev/null +++ b/modules/local/eukcc/folder/main.nf @@ -0,0 +1,70 @@ +process EUKCC_FOLDER { + tag "${meta.id}" + label 'process_medium' + label 'process_long' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? + 'oras://community.wave.seqera.io/library/eukcc:2.2.0--050b7bea3f69b4a8': + 'community.wave.seqera.io/library/eukcc:2.2.0--212dfaba26f5edd2' }" + + input: + tuple val(meta), path(links), path(bins, stageAs: 'bins/*') + tuple val(meta2), path(db) + + output: + tuple val(meta), path("${prefix}_results/merged_bins"), emit: merged_bins + tuple val(meta), path("${prefix}.eukcc.csv") , emit: csv + tuple val(meta), path("${prefix}.merged_bins.csv") , emit: merged_csv + tuple val("${task.process}"), val('eukcc'), eval('eukcc -v 2>&1 | grep -oE "[0-9]+\\.[0-9]+\\.[0-9]+" | head -n1'), emit: versions_eukcc, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + def links_arg = links ? "--links ${links}" : '' + """ + mkdir -p bins ${prefix}_results/merged_bins + + if [ -z "\$(ls -A bins)" ]; then + echo "No bins in input" >&2 + touch ${prefix}.eukcc.csv ${prefix}.merged_bins.csv + else + set +e + eukcc folder \\ + ${args} \\ + --threads ${task.cpus} \\ + ${links_arg} \\ + --db ${db} \\ + --out ${prefix}_results \\ + --prefix ${prefix}_merged. \\ + bins + exit_code=\$? + set -e + + case \$exit_code in + 0) + mv ${prefix}_results/eukcc.csv ${prefix}.eukcc.csv + mv ${prefix}_results/merged_bins.csv ${prefix}.merged_bins.csv + ;; + 204) + # EukCC exits with 204 when MetaEuk predicts zero proteins + echo "MetaEuk returned zero proteins" >&2 + touch ${prefix}.eukcc.csv ${prefix}.merged_bins.csv + ;; + *) + exit \$exit_code + ;; + esac + fi + """ + + stub: + prefix = task.ext.prefix ?: "${meta.id}" + """ + mkdir -p ${prefix}_results/merged_bins + touch ${prefix}.eukcc.csv ${prefix}.merged_bins.csv + """ +} diff --git a/modules/nf-core/busco/busco/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt b/modules/nf-core/busco/busco/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt new file mode 100644 index 00000000..bbad0b6b --- /dev/null +++ b/modules/nf-core/busco/busco/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt @@ -0,0 +1,3042 @@ + +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/linux-64/alsa-lib-1.2.16.1-hb03c661_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/augustus-3.5.0-pl5321h9716f88_9.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.6.0-py312h90b7ffd_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/bamtools-2.5.3-he132191_0.tar.bz2 +- conda: https://conda.anaconda.org/bioconda/linux-64/bbmap-39.81-h9b5c0a0_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/biopython-1.87-py312h4c3975b_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/blast-2.17.0-h66d330f_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/boost-cpp-1.85.0-h3c6214e_4.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-hed03a55_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.2.0-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py312hdb49522_1.conda +- conda: https://conda.anaconda.org/bioconda/noarch/busco-6.1.0-pyhdfd78af_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/linux-64/c-ares-1.34.6-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/cdbtools-0.99-h077b44d_12.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.6.17-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.8-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/clustalw-2.1-h9948957_12.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312h0a2e395_4.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/curl-8.21.0-hcf29cc6_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda +- conda: https://conda.anaconda.org/bioconda/noarch/dendropy-5.0.8-pyhdfd78af_1.tar.bz2 +- conda: https://conda.anaconda.org/bioconda/linux-64/diamond-2.2.3-he361c42_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/dnspython-2.8.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/entrez-direct-24.0-he881be0_0.tar.bz2 +- conda: https://conda.anaconda.org/bioconda/linux-64/fasttree-2.2.0-h7b50bb2_1.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.18.1-h27c8c51_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.3-ha770c72_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/gawk-5.4.0-h0a3468a_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-hecca717_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/gsl-2.8-hbf7d49c_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-12.2.0-h15599e2_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/hmmer-3.4-h503566f_3.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.2.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/htslib-1.23.1-h633afcb_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-75.1-he02047a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.18-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/jsoncpp-1.9.6-hf42df4d_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.0-py312h0a2e395_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-hbde042b_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_1.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/libamd-3.3.3-h456b2da_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libasprintf-0.25.1-h3f43e3d_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.85.0-h0ccab89_4.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-devel-1.85.0-h00ab1b0_4.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-headers-1.85.0-ha770c72_4.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbtf-2.3.2-hf02c80a_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcamd-3.3.3-hf02c80a_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libccolamd-3.3.4-hf02c80a_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcholmod-5.3.1-h9cf07ce_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcolamd-3.3.4-hf02c80a_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.21.0-hcf29cc6_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcxsparse-4.4.1-hf02c80a_7100101.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/libedit-3.1.20250104-pl5321h7949ede_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.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_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-0.25.1-h3f43e3d_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-15.2.0-h69a702a_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.2-h0d30a3d_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libklu-2.3.5-h95ff59c_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libldl-3.3.2-hf02c80a_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-devel-5.8.3-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenssl-static-3.6.3-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libparu-1.0.0-hc6afc67_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/librbio-4.3.4-hf02c80a_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libspex-3.2.3-h9226d62_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libspqr-4.3.4-h23b7119_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.3-h0c1763c_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsuitesparseconfig-7.10.1-h901830b_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-h9d88235_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libumfpack-6.3.5-h873dde6_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-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/libxcrypt-4.4.36-hd590300_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/lp_solve-5.5.2.11-hd590300_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/mafft-7.526-h4bc722e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.9-py312he3d6523_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/metaeuk-7.bba0d80-pl5321hd6d6fdc_2.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/metis-5.1.0-hd0bcaf9_1007.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/miniprot-0.18-h577a1d6_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-he0a73b1_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/mpi-1.0-openmpi.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/muscle-3.8.1551-h9948957_9.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-connector-c-6.1.11-h659d440_1008.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/ncbi-vdb-3.4.1-hd63eeec_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.5-py312h33ff503_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjdk-25.0.1-h5755bd7_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/openmpi-4.1.6-hc5af2df_101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py312h8ecdadd_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/pasta-1.9.3-py312h85383db_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pcre-8.45-h9c3ff4c_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-app-cpanminus-1.7048-pl5321hd8ed1ab_0.conda +- conda: https://conda.anaconda.org/bioconda/noarch/perl-archive-tar-3.12-pl5321hdfd78af_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-carp-1.50-pl5321hd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-class-method-modifiers-2.13-pl5321ha770c72_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-common-sense-3.75-pl5321hd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-compress-raw-bzip2-2.214-pl5321hda65f42_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-compress-raw-zlib-2.214-pl5321h4dac143_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-constant-1.33-pl5321hd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-dbi-1.649-pl5321hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-encode-3.24-pl5321hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-exporter-5.74-pl5321hd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-exporter-tiny-1.002002-pl5321hd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-extutils-makemaker-7.70-pl5321hd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-file-path-2.18-pl5321hd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-file-temp-0.2304-pl5321hd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-file-which-1.24-pl5321hd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-inc-latest-0.500-pl5321ha770c72_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/perl-io-compress-2.216-pl5321h503566f_0.conda +- conda: https://conda.anaconda.org/bioconda/noarch/perl-io-zlib-1.15-pl5321hdfd78af_1.tar.bz2 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-json-4.11-pl5321hdfd78af_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/perl-json-xs-4.04-pl5321h9948957_0.conda +- conda: https://conda.anaconda.org/bioconda/noarch/perl-list-moreutils-0.430-pl5321hdfd78af_0.tar.bz2 +- conda: https://conda.anaconda.org/bioconda/linux-64/perl-list-moreutils-xs-0.430-pl5321h7b50bb2_5.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-module-build-0.4234-pl5321ha770c72_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-moo-2.005004-pl5321ha770c72_0.tar.bz2 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-parallel-forkmanager-2.04-pl5321hdfd78af_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-parent-0.243-pl5321hd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-pathtools-3.75-pl5321hb9d3cd8_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-role-tiny-2.002004-pl5321ha770c72_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-scalar-list-utils-1.70-pl5321hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-storable-3.15-pl5321hb9d3cd8_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-sub-quote-2.006006-pl5321ha770c72_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-test-fatal-0.016-pl5321ha770c72_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-try-tiny-0.31-pl5321ha770c72_0.tar.bz2 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-types-serialiser-1.01-pl5321hdfd78af_0.tar.bz2 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-yaml-1.30-pl5321hdfd78af_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h50c33e8_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/prank-251117-hd63eeec_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/prodigal-2.6.3-h577a1d6_11.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pymongo-4.17.0-py312h1289d80_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_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.12.13-hd63d673_0_cpython.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/raxml-8.2.13-h7b50bb2_3.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/samtools-1.23.1-ha83d96e_0.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/sepp-4.5.5-py312h0fa9677_3.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.3-hbc0de68_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/suitesparse-7.10.1-h5b2951e_7100101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/tar-1.35-h3b78370_0.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/tzdata-2025c-hc9c84f9_1.conda +- conda: https://conda.anaconda.org/bioconda/linux-64/ucsc-fatotwobit-482-hdc0a859_0.tar.bz2 +- conda: https://conda.anaconda.org/bioconda/linux-64/ucsc-twobitinfo-482-hdc0a859_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/wget-1.25.0-h653f8fd_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.13-he1eb515_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/xorg-libxext-1.3.7-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.2-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.3-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.5-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.1-hb9d3cd8_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.8.3-ha02ee65_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xz-gpl-tools-5.8.3-ha02ee65_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xz-tools-5.8.3-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_2.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/linux-64/alsa-lib-1.2.16.1-hb03c661_0.conda +sha256: cf93ca0f1f107e95a35969a4622684e08fcb8cf37f8cf4a1e9e424828386c921 +md5: 8904e09bda369377b3dd07e2ac828c5d +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: LGPL-2.1-or-later +license_family: LGPL +size: 592377 +timestamp: 1781521980743 +- conda: https://conda.anaconda.org/bioconda/linux-64/augustus-3.5.0-pl5321h9716f88_9.conda +sha256: 383dad598de1014d694f1822172a9d25411617ed6f07d36e8287ebfe7e67c2ff +md5: aff97814997ccca7ada6f3131c1a75f6 +depends: +- bamtools >=2.5.3,<3.0a0 +- biopython +- boost-cpp +- cdbtools +- diamond +- gsl >=2.8 +- gsl >=2.8,<2.9.0a0 +- htslib >=1.22.1,<1.24.0a0 +- libamd >=3.3.3,<4.0a0 +- libblas >=3.9.0,<4.0a0 +- libbtf >=2.3.2,<3.0a0 +- libcamd >=3.3.3,<4.0a0 +- libcblas >=3.9.0,<4.0a0 +- libccolamd >=3.3.4,<4.0a0 +- libcholmod >=5.3.1,<6.0a0 +- libcolamd >=3.3.4,<4.0a0 +- libcxsparse >=4.4.1,<5.0a0 +- libgcc >=13 +- libklu >=2.3.5,<3.0a0 +- libldl >=3.3.2,<4.0a0 +- libparu >=1.0.0,<2.0a0 +- librbio >=4.3.4,<5.0a0 +- libspex >=3.2.3,<4.0a0 +- libspqr >=4.3.4,<5.0a0 +- libsqlite >=3.50.4,<4.0a0 +- libstdcxx >=13 +- libsuitesparseconfig >=7.10.1,<8.0a0 +- libumfpack >=6.3.5,<7.0a0 +- libzlib >=1.3.1,<2.0a0 +- lp_solve +- perl >=5.32.1,<5.33.0a0 *_perl5 +- perl-app-cpanminus +- perl-dbi +- perl-file-which +- perl-module-build 0.4234.* +- perl-parallel-forkmanager +- perl-scalar-list-utils +- perl-yaml +- samtools >=1.22.1,<2.0a0 +- sqlite +- suitesparse >=7.10.1,<8.0a0 +- tar +- ucsc-fatotwobit +- ucsc-twobitinfo +license: Artistic License +license_family: Other +size: 27006331 +timestamp: 1755723767609 +- conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.6.0-py312h90b7ffd_0.conda +sha256: 95b3d6d44c17c4061db703289f39915646e455f75f0c8c9d949bf081d2e61579 +md5: 55811da425538da800b89c0c588652fa +depends: +- python +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.12.* *_cp312 +- zstd >=1.5.7,<1.6.0a0 +license: BSD-3-Clause AND MIT AND EPL-2.0 +size: 239892 +timestamp: 1781450817988 +- conda: https://conda.anaconda.org/bioconda/linux-64/bamtools-2.5.3-he132191_0.tar.bz2 +sha256: 18d0c7e69cc6c775184ca7034d8e2f8b6de4a516c3de74792391882ef1bdcd0d +md5: e3302f3cd140ded877f39abe612bed08 +depends: +- jsoncpp >=1.9.6,<1.9.7.0a0 +- libgcc >=13 +- libstdcxx >=13 +- libzlib >=1.3.1,<2.0a0 +license: MIT +license_family: MIT +size: 783519 +timestamp: 1747609084710 +- conda: https://conda.anaconda.org/bioconda/linux-64/bbmap-39.81-h9b5c0a0_1.conda +sha256: 96e2ed5f82a928fe6a71893e366166390c63034b45976211cf91baf90d4e41d9 +md5: 4af20865073c32418b8553da02e436bb +depends: +- bzip2 >=1.0.8,<2.0a0 +- libgcc >=14 +- openjdk >=11.0.1 +- samtools >=1.23.1,<2.0a0 +license: BSD-3-Clause-LBNL +size: 93105368 +timestamp: 1774976438094 +- conda: https://conda.anaconda.org/conda-forge/linux-64/biopython-1.87-py312h4c3975b_0.conda +sha256: 8439485bab2f8ae5af4069b624d76186939c5218d3fdf33c49fc67a48605ccc5 +md5: 2eb5b71dfcfb2a316d0307eb696bf11e +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- numpy +- python >=3.12,<3.13.0a0 +- python_abi 3.12.* *_cp312 +license: LicenseRef-Biopython +size: 3306754 +timestamp: 1774882187035 +- conda: https://conda.anaconda.org/bioconda/linux-64/blast-2.17.0-h66d330f_0.conda +sha256: 53a319c984d8aafcf7f2d7d4c21ad2590e1bacd674443e09d79ac19694ccf99a +md5: 405ce6d52eba06fcd48197ae1eb8f5a9 +depends: +- bzip2 >=1.0.8,<2.0a0 +- curl +- entrez-direct >=24.0,<25.0a0 +- libgcc >=13 +- libsqlite >=3.50.4,<4.0a0 +- libstdcxx >=13 +- libzlib >=1.3.1,<2.0a0 +- ncbi-vdb >=3.2.1,<4.0a0 +- perl +- perl-archive-tar +- perl-json +- perl-list-moreutils +- zlib +license: NCBI-PD +size: 84832339 +timestamp: 1754909742570 +- conda: https://conda.anaconda.org/conda-forge/linux-64/boost-cpp-1.85.0-h3c6214e_4.conda +sha256: dec1f52d8869b94a9cb2b4d9a727a00ae2c54e7b5a66a51d3d9f1c33159ebb45 +md5: cc4533eabf5caa8b4fbb56418d1617a9 +depends: +- bzip2 >=1.0.8,<2.0a0 +- icu >=75.1,<76.0a0 +- libboost-devel 1.85.0 h00ab1b0_4 +- libzlib >=1.3.1,<2.0a0 +- xz >=5.2.6,<6.0a0 +- zstd >=1.5.6,<1.6.0a0 +license: BSL-1.0 +size: 18122 +timestamp: 1722289881184 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-hed03a55_1.conda +sha256: e511644d691f05eb12ebe1e971fd6dc3ae55a4df5c253b4e1788b789bdf2dfa6 +md5: 8ccf913aaba749a5496c17629d859ed1 +depends: +- __glibc >=2.17,<3.0.a0 +- brotli-bin 1.2.0 hb03c661_1 +- libbrotlidec 1.2.0 hb03c661_1 +- libbrotlienc 1.2.0 hb03c661_1 +- libgcc >=14 +license: MIT +license_family: MIT +size: 20103 +timestamp: 1764017231353 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.2.0-hb03c661_1.conda +sha256: 64b137f30b83b1dd61db6c946ae7511657eead59fdf74e84ef0ded219605aa94 +md5: af39b9a8711d4a8d437b52c1d78eb6a1 +depends: +- __glibc >=2.17,<3.0.a0 +- libbrotlidec 1.2.0 hb03c661_1 +- libbrotlienc 1.2.0 hb03c661_1 +- libgcc >=14 +license: MIT +license_family: MIT +size: 21021 +timestamp: 1764017221344 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py312hdb49522_1.conda +sha256: 49df13a1bb5e388ca0e4e87022260f9501ed4192656d23dc9d9a1b4bf3787918 +md5: 64088dffd7413a2dd557ce837b4cbbdb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +- python >=3.12,<3.13.0a0 +- python_abi 3.12.* *_cp312 +constrains: +- libbrotlicommon 1.2.0 hb03c661_1 +license: MIT +license_family: MIT +size: 368300 +timestamp: 1764017300621 +- conda: https://conda.anaconda.org/bioconda/noarch/busco-6.1.0-pyhdfd78af_1.conda +sha256: d80c2e51ad7017e6bb82e3fee982af5800ea507cdf4e46a8077936a81af3e96a +md5: 5750abc786560cfa22f409bc1cc16ca4 +depends: +- augustus >=3.3 +- bbmap +- biopython >=1.79 +- blast >=2.10.1 +- fonts-conda-ecosystem +- hmmer >=3.1b2 +- matplotlib-base +- metaeuk >=6.a5d39d9 +- miniprot +- numpy <2.4 +- pandas +- prodigal +- python >=3.3 +- requests +- sepp 4.5.5 +- wget +license: MIT +license_family: MIT +size: 355322 +timestamp: 1781104516494 +- 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/linux-64/c-ares-1.34.6-hb03c661_0.conda +sha256: cc9accf72fa028d31c2a038460787751127317dcfa991f8d1f1babf216bb454e +md5: 920bb03579f15389b9e512095ad995b7 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 207882 +timestamp: 1765214722852 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda +sha256: f8e3c730fa14ee3f170493779f06522c4acf89169f43db4f039727709b6419cf +md5: a9965dd99f683c5f444428f896635716 +depends: +- __unix +license: ISC +size: 128866 +timestamp: 1781708962055 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda +sha256: 3bd6a391ad60e471de76c0e9db34986c4b5058587fbf2efa5a7f54645e28c2c7 +md5: 09262e66b19567aff4f592fb53b28760 +depends: +- __glibc >=2.17,<3.0.a0 +- fontconfig >=2.15.0,<3.0a0 +- fonts-conda-ecosystem +- freetype >=2.12.1,<3.0a0 +- icu >=75.1,<76.0a0 +- libexpat >=2.6.4,<3.0a0 +- libgcc >=13 +- libglib >=2.82.2,<3.0a0 +- libpng >=1.6.47,<1.7.0a0 +- libstdcxx >=13 +- libxcb >=1.17.0,<2.0a0 +- libzlib >=1.3.1,<2.0a0 +- pixman >=0.44.2,<1.0a0 +- xorg-libice >=1.1.2,<2.0a0 +- xorg-libsm >=1.2.5,<2.0a0 +- xorg-libx11 >=1.8.11,<2.0a0 +- xorg-libxext >=1.3.6,<2.0a0 +- xorg-libxrender >=0.9.12,<0.10.0a0 +license: LGPL-2.1-only or MPL-1.1 +size: 978114 +timestamp: 1741554591855 +- conda: https://conda.anaconda.org/bioconda/linux-64/cdbtools-0.99-h077b44d_12.tar.bz2 +sha256: b70324c9af58110d40b8ed9b5210fe7829cadd59ffef66cf01fa818cc9476fa6 +md5: 6b938da47db28f06ca9258f92d80e7cb +depends: +- libgcc >=13 +- libstdcxx >=13 +- libzlib >=1.3.1,<2.0a0 +license: Public Domain +size: 80142 +timestamp: 1744771014271 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.6.17-pyhd8ed1ab_0.conda +sha256: 6c13620e458ba43278379d0cdacc30c497336bddfda81681fd50d114a65c702f +md5: c13824fedced67005d3832c152fe9c2f +depends: +- python >=3.10 +license: ISC +size: 133877 +timestamp: 1781719949728 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.8-pyhd8ed1ab_0.conda +sha256: a51c9aed4a0f364fe72f4730a19daef7370446b107cd5dd9a5d7ad6d00895de1 +md5: b2e6755844f4c74239dff62f1cb4adda +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 61278 +timestamp: 1783374645872 +- conda: https://conda.anaconda.org/bioconda/linux-64/clustalw-2.1-h9948957_12.tar.bz2 +sha256: d82a95c35cfdb590c266131fdbb0ec62c7977a1edbc95ac43a03220886c855a4 +md5: 5989fcb871dabc90d1bb5de3d5c79185 +depends: +- libgcc >=13 +- libstdcxx >=13 +license: LGPL-3.0-or-later +license_family: LGPL +size: 384703 +timestamp: 1738739696573 +- conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312h0a2e395_4.conda +sha256: 62447faf7e8eb691e407688c0b4b7c230de40d5ecf95bf301111b4d05c5be473 +md5: 43c2bc96af3ae5ed9e8a10ded942aa50 +depends: +- numpy >=1.25 +- python +- __glibc >=2.17,<3.0.a0 +- libstdcxx >=14 +- libgcc >=14 +- python_abi 3.12.* *_cp312 +license: BSD-3-Clause +license_family: BSD +size: 320386 +timestamp: 1769155979897 +- conda: https://conda.anaconda.org/conda-forge/linux-64/curl-8.21.0-hcf29cc6_1.conda +sha256: 8eb4ebeae7230110569da734e2420aee84f6977850bae4af94dc7f0b382f9d89 +md5: 58609be98a9725cd359a1c63ff329628 +depends: +- __glibc >=2.17,<3.0.a0 +- krb5 >=1.22.2,<1.23.0a0 +- libcurl 8.21.0 hcf29cc6_1 +- libgcc >=14 +- libssh2 >=1.11.1,<2.0a0 +- libzlib >=1.3.2,<2.0a0 +- openssl >=3.5.7,<4.0a0 +- zstd >=1.5.7,<1.6.0a0 +license: curl +license_family: MIT +size: 194657 +timestamp: 1782802525727 +- conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda +sha256: bb47aec5338695ff8efbddbc669064a3b10fe34ad881fb8ad5d64fbfa6910ed1 +md5: 4c2a8fef270f6c69591889b93f9f55c1 +depends: +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 14778 +timestamp: 1764466758386 +- conda: https://conda.anaconda.org/bioconda/noarch/dendropy-5.0.8-pyhdfd78af_1.tar.bz2 +sha256: 102790b465893f5a5c4c3fa045f677e23f990ecc6d1b61d240153c3569a5b99f +md5: 0fa94922431d1074792639704d19461d +depends: +- python >=3.6 +license: BSD-3-Clause +license_family: BSD +size: 335113 +timestamp: 1750372782364 +- conda: https://conda.anaconda.org/bioconda/linux-64/diamond-2.2.3-he361c42_0.conda +sha256: 171f8cd041aad153fe25b5f994d1e2084d7d3a6fb576172ba4520c1d47a6e1a2 +md5: a2fee5dc0c0e7a9837464ad9c17e451c +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libsqlite >=3.53.3,<4.0a0 +- libstdcxx >=14 +- libzlib >=1.3.2,<2.0a0 +license: GPL-3.0-or-later +license_family: GPL3 +size: 3078934 +timestamp: 1783427329995 +- conda: https://conda.anaconda.org/conda-forge/noarch/dnspython-2.8.0-pyhcf101f3_0.conda +sha256: ef1e7b8405997ed3d6e2b6722bd7088d4a8adf215e7c88335582e65651fb4e05 +md5: d73fdc05f10693b518f52c994d748c19 +depends: +- python >=3.10,<4.0.0 +- sniffio +- python +constrains: +- aioquic >=1.2.0 +- cryptography >=45 +- httpcore >=1.0.0 +- httpx >=0.28.0 +- h2 >=4.2.0 +- idna >=3.10 +- trio >=0.30 +- wmi >=1.5.1 +license: ISC +size: 196500 +timestamp: 1757292856922 +- conda: https://conda.anaconda.org/bioconda/linux-64/entrez-direct-24.0-he881be0_0.tar.bz2 +sha256: 71a8f349659c9c18efa544663de2db1a20b5e3d32f8e4e88cd33110a0caf4eb3 +md5: 52a3fabee9201c2c6093c13b4eaf29b4 +depends: +- wget +license: Public Domain +size: 17127014 +timestamp: 1748473197798 +- conda: https://conda.anaconda.org/bioconda/linux-64/fasttree-2.2.0-h7b50bb2_1.conda +sha256: d9a6d06fab5f22e5d6a0dfcaf2d51fa07fd9b080f12794ab53e60b1ea1d3ac97 +md5: 2d5c9b69e3dd027849eb8e29ca2bebae +depends: +- _openmp_mutex >=4.5 +- libgcc >=13 +- libgomp +license: GPL-2.0-or-later +license_family: GPL +size: 197973 +timestamp: 1764102501456 +- 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.18.1-h27c8c51_0.conda +sha256: 2e50bdcebdf70a865b81f2456bbc586386451ec601c60f2b6cd22b8c40a2d384 +md5: e0e050cfa9fa85fe39632ab11cb7f3e0 +depends: +- __glibc >=2.17,<3.0.a0 +- libexpat >=2.8.1,<3.0a0 +- libfreetype >=2.14.3 +- libfreetype6 >=2.14.3 +- libgcc >=14 +- libuuid >=2.42.1,<3.0a0 +- libzlib >=1.3.2,<2.0a0 +license: MIT +license_family: MIT +size: 281880 +timestamp: 1780450077431 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 +sha256: a997f2f1921bb9c9d76e6fa2f6b408b7fa549edd349a77639c9fe7a23ea93e61 +md5: fee5683a3f04bd15cbd8318b096a27ab +depends: +- fonts-conda-forge +license: BSD-3-Clause +license_family: BSD +size: 3667 +timestamp: 1566974674465 +- 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/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda +sha256: d235ae7075642044ceb3d922ef2a710a82665755ac9bbb7e8dad7daa72bc6d87 +md5: 294fb524171e2a2748cb7fe708aba826 +depends: +- __glibc >=2.17,<3.0.a0 +- brotli +- libgcc >=14 +- munkres +- python >=3.12,<3.13.0a0 +- python_abi 3.12.* *_cp312 +- unicodedata2 >=15.1.0 +license: MIT +license_family: MIT +size: 3007892 +timestamp: 1778770568019 +- conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.3-ha770c72_0.conda +sha256: c934c385889c7836f034039b43b05ccfa98f53c900db03d8411189892ced090b +md5: 8462b5322567212beeb025f3519fb3e2 +depends: +- libfreetype 2.14.3 ha770c72_0 +- libfreetype6 2.14.3 h73754d4_0 +license: GPL-2.0-only OR FTL +size: 173839 +timestamp: 1774298173462 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gawk-5.4.0-h0a3468a_0.conda +sha256: 0c98fc1fd2d66dbac3f97e9721a523cd5a4bb15ad115a2dbb96d46a130a6f89a +md5: 85817e8a5230ebde83b9ca2a8282e004 +depends: +- gmp +- mpfr +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- readline >=8.3,<9.0a0 +- gmp >=6.3.0,<7.0a0 +- libasprintf >=0.25.1,<1.0a0 +- libgettextpo >=0.25.1,<1.0a0 +- mpfr >=4.2.2,<5.0a0 +license: GPL-3.0-or-later +license_family: GPL +size: 1505698 +timestamp: 1777297022541 +- conda: https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda +sha256: aac402a8298f0c0cc528664249170372ef6b37ac39fdc92b40601a6aed1e32ff +md5: 3bf7b9fd5a7136126e0234db4b87c8b6 +depends: +- libgcc-ng >=12 +license: MIT +license_family: MIT +size: 77248 +timestamp: 1712692454246 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda +sha256: 309cf4f04fec0c31b6771a5809a1909b4b3154a2208f52351e1ada006f4c750c +md5: c94a5994ef49749880a8139cf9afcbe1 +depends: +- libgcc-ng >=12 +- libstdcxx-ng >=12 +license: GPL-2.0-or-later OR LGPL-3.0-or-later +size: 460055 +timestamp: 1718980856608 +- conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-hecca717_0.conda +sha256: 885fa7d1d7e2ad9ed0a700ee0d81ceb49de278253082d517959b22d6336eecce +md5: cf09e9fc938518e91d0706572cadf17a +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: LGPL-2.0-or-later +license_family: LGPL +size: 100054 +timestamp: 1780454302233 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gsl-2.8-hbf7d49c_1.conda +sha256: f923af07c3a3db746d3be8efebdaa9c819a6007ee3cc12445cee059641611e05 +md5: 04e128d2adafe3c844cde58f103c481b +depends: +- __glibc >=2.17,<3.0.a0 +- libblas >=3.9.0,<4.0a0 +- libcblas >=3.9.0,<4.0a0 +- libgcc >=13 +license: GPL-3.0-or-later +license_family: GPL +size: 2486744 +timestamp: 1737621160295 +- 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/linux-64/harfbuzz-12.2.0-h15599e2_0.conda +sha256: 6bd8b22beb7d40562b2889dc68232c589ff0d11a5ad3addd41a8570d11f039d9 +md5: b8690f53007e9b5ee2c2178dd4ac778c +depends: +- __glibc >=2.17,<3.0.a0 +- cairo >=1.18.4,<2.0a0 +- graphite2 >=1.3.14,<2.0a0 +- icu >=75.1,<76.0a0 +- libexpat >=2.7.1,<3.0a0 +- libfreetype >=2.14.1 +- libfreetype6 >=2.14.1 +- libgcc >=14 +- libglib >=2.86.1,<3.0a0 +- libstdcxx >=14 +- libzlib >=1.3.1,<2.0a0 +license: MIT +license_family: MIT +size: 2411408 +timestamp: 1762372726141 +- conda: https://conda.anaconda.org/bioconda/linux-64/hmmer-3.4-h503566f_3.tar.bz2 +sha256: d3c37ebbd6254cded0937c1f3d389f8c8c0ca59986aa61846c476e41a82e3c27 +md5: 0536103ba1af5d75454868affd7575c1 +depends: +- libgcc >=13 +- libstdcxx >=13 +license: BSD +size: 11627027 +timestamp: 1733932139092 +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.2.0-pyhd8ed1ab_0.conda +sha256: fdcea5d7cb314485d3907192ef024c704311548c5b0cbeb390cd1951051e29d2 +md5: b395909221b9bd1df066e5930e18855b +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 32884 +timestamp: 1782283986153 +- conda: https://conda.anaconda.org/bioconda/linux-64/htslib-1.23.1-h633afcb_0.conda +sha256: d0977efb1885c9f00ca76ee13e7c0f9a8936bf271eec25ffa78606cd816a13c9 +md5: 209caa9e4ff0b9ed02dd09c3161917e5 +depends: +- bzip2 >=1.0.8,<2.0a0 +- libcurl >=8.19.0,<9.0a0 +- libdeflate >=1.25,<1.26.0a0 +- libgcc >=14 +- liblzma >=5.8.2,<6.0a0 +- libzlib >=1.3.1,<2.0a0 +- openssl >=3.5.5,<4.0a0 +license: MIT +license_family: MIT +size: 1195461 +timestamp: 1773854995668 +- 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-75.1-he02047a_0.conda +sha256: 71e750d509f5fa3421087ba88ef9a7b9be11c53174af3aa4d06aff4c18b38e8e +md5: 8b189310083baabfb622af68fd9d3ae3 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc-ng >=12 +- libstdcxx-ng >=12 +license: MIT +license_family: MIT +size: 12129203 +timestamp: 1720853576813 +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.18-pyhcf101f3_0.conda +sha256: c75632ea624aa450a394f570749420c5a2e0997d0216bc29d5d45b0f39df0426 +md5: 577b04680ae422adb86fc60d7b940659 +depends: +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 163869 +timestamp: 1781620148226 +- conda: https://conda.anaconda.org/conda-forge/linux-64/jsoncpp-1.9.6-hf42df4d_1.conda +sha256: ed4b1878be103deb2e4c6d0eea3c9bdddfd7fc3178383927dce7578fb1063520 +md5: 7bdc5e2cc11cb0a0f795bdad9732b0f2 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- libstdcxx >=13 +license: LicenseRef-Public-Domain OR MIT +size: 169093 +timestamp: 1733780223643 +- conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda +sha256: 0960d06048a7185d3542d850986d807c6e37ca2e644342dd0c72feefcf26c2a4 +md5: b38117a3c920364aff79f870c984b4a3 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +license: LGPL-2.1-or-later +size: 134088 +timestamp: 1754905959823 +- conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.0-py312h0a2e395_0.conda +sha256: eec7654c2d68f06590862c6e845cc70987b6d6559222b6f0e619dea4268f5dd5 +md5: cd74a9525dc74bbbf93cf8aa2fa9eb5b +depends: +- python +- libstdcxx >=14 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.12.* *_cp312 +license: BSD-3-Clause +license_family: BSD +size: 77120 +timestamp: 1773067050308 +- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-hbde042b_1.conda +sha256: 9b07046870772f28740e3f6149f09ff222843733087a33c5540b169c6289652d +md5: 54157a1c8c0bb70f62dd0b17fba7e7f2 +depends: +- __glibc >=2.17,<3.0.a0 +- keyutils >=1.6.3,<2.0a0 +- libedit >=3.1.20250104,<3.2.0a0 +- libedit >=3.1.20250104,<4.0a0 +- libgcc >=14 +- libstdcxx >=14 +- openssl >=3.5.7,<4.0a0 +license: MIT +license_family: MIT +size: 1388990 +timestamp: 1781859420533 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_1.conda +sha256: 112b5b9462572d970f4abd2912f76a25ee7db158b1e7260163d91dd8a630db84 +md5: 8b3ce45e929cd8e8e5f4d18586b56d8b +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.4.1,<4.0a0 +- libtiff >=4.7.1,<4.8.0a0 +license: MIT +license_family: MIT +size: 251971 +timestamp: 1780211695895 +- 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/libamd-3.3.3-h456b2da_7100101.conda +sha256: 5fc32a5497c9919ffde729a604b0acfa97c403ce5b2b27b28ca261cf0c4643aa +md5: a067596d679bcde85375143e7c374738 +depends: +- __glibc >=2.17,<3.0.a0 +- libgfortran5 >=13.3.0 +- libgfortran +- libgcc >=13 +- libsuitesparseconfig >=7.10.1,<8.0a0 +license: BSD-3-Clause +license_family: BSD +size: 48250 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libasprintf-0.25.1-h3f43e3d_1.conda +sha256: cb728a2a95557bb6a5184be2b8be83a6f2083000d0c7eff4ad5bbe5792133541 +md5: 3b0d184bc9404516d418d4509e418bdc +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: LGPL-2.1-or-later +size: 53582 +timestamp: 1753342901341 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda +build_number: 8 +sha256: b2da6bfd72a1c9cb143ccf64bf5b28790cb4eb58bd1cb978f6537b2322f7d48b +md5: 00fc660ab1b2f5ca07e92b4900d10c79 +depends: +- libopenblas >=0.3.33,<0.3.34.0a0 +- libopenblas >=0.3.33,<1.0a0 +constrains: +- blas 2.308 openblas +- mkl <2027 +- libcblas 3.11.0 8*_openblas +- liblapack 3.11.0 8*_openblas +- liblapacke 3.11.0 8*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18804 +timestamp: 1779859100675 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.85.0-h0ccab89_4.conda +sha256: dc19dfc636c363871763384219269ce6a027fcf3831f17e018caeecb2ffbb20a +md5: 4da1690badd566fc1041f91cd5655727 +depends: +- __glibc >=2.17,<3.0.a0 +- bzip2 >=1.0.8,<2.0a0 +- icu >=75.1,<76.0a0 +- libgcc-ng >=12 +- libstdcxx-ng >=12 +- libzlib >=1.3.1,<2.0a0 +- xz >=5.2.6,<6.0a0 +- zstd >=1.5.6,<1.6.0a0 +constrains: +- boost-cpp =1.85.0 +license: BSL-1.0 +size: 2869710 +timestamp: 1722289756758 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-devel-1.85.0-h00ab1b0_4.conda +sha256: 04ec5a59e87d75cf6f8b539493f7f71c0cca3f50976251895f51da45e39cddf7 +md5: ded76b8670cb505006c891c4d45844a5 +depends: +- libboost 1.85.0 h0ccab89_4 +- libboost-headers 1.85.0 ha770c72_4 +constrains: +- boost-cpp =1.85.0 +license: BSL-1.0 +size: 40881 +timestamp: 1722289871820 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-headers-1.85.0-ha770c72_4.conda +sha256: 55aa2ac604bd7ed76fae0c93698d37aae455ca2fb229ff9aa45e085ff7ad48ec +md5: 00e4848983222729ccb7c69f1039f4b9 +constrains: +- boost-cpp =1.85.0 +license: BSL-1.0 +size: 13961521 +timestamp: 1722289776587 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-hb03c661_1.conda +sha256: 318f36bd49ca8ad85e6478bd8506c88d82454cc008c1ac1c6bf00a3c42fa610e +md5: 72c8fd1af66bd67bf580645b426513ed +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 79965 +timestamp: 1764017188531 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-hb03c661_1.conda +sha256: 12fff21d38f98bc446d82baa890e01fd82e3b750378fedc720ff93522ffb752b +md5: 366b40a69f0ad6072561c1d09301c886 +depends: +- __glibc >=2.17,<3.0.a0 +- libbrotlicommon 1.2.0 hb03c661_1 +- libgcc >=14 +license: MIT +license_family: MIT +size: 34632 +timestamp: 1764017199083 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-hb03c661_1.conda +sha256: a0c15c79997820bbd3fbc8ecf146f4fe0eca36cc60b62b63ac6cf78857f1dd0d +md5: 4ffbb341c8b616aa2494b6afb26a0c5f +depends: +- __glibc >=2.17,<3.0.a0 +- libbrotlicommon 1.2.0 hb03c661_1 +- libgcc >=14 +license: MIT +license_family: MIT +size: 298378 +timestamp: 1764017210931 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbtf-2.3.2-hf02c80a_7100101.conda +sha256: fe36f414f48ab87251f02aeef1fcbb6f3929322316842dada0f8142db2710264 +md5: 6f4aec52002defbdf3e24eb79e56a209 +depends: +- libgcc >=13 +- __glibc >=2.17,<3.0.a0 +- libsuitesparseconfig >=7.10.1,<8.0a0 +license: LGPL-2.1-or-later +size: 26913 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcamd-3.3.3-hf02c80a_7100101.conda +sha256: 16e9ae4e173a8606b0b8be118dbdcf4e03c9dd9777eea6bf9dff4397133d0d06 +md5: 1c9d1532caadece8adc2d14c6d4fc726 +depends: +- libgcc >=13 +- __glibc >=2.17,<3.0.a0 +- libsuitesparseconfig >=7.10.1,<8.0a0 +license: BSD-3-Clause +license_family: BSD +size: 44119 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda +build_number: 8 +sha256: 1a2bc77bb26520255904a3d9b1f40e6bf0bf9d8d3405c7709dd162282820915a +md5: 33a413f1095f8325e5c30fde3b0d2445 +depends: +- libblas 3.11.0 8_h4a7cf45_openblas +constrains: +- blas 2.308 openblas +- liblapacke 3.11.0 8*_openblas +- liblapack 3.11.0 8*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18778 +timestamp: 1779859107964 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libccolamd-3.3.4-hf02c80a_7100101.conda +sha256: cc90aa5e0ad1f7ae9a29d9a42aacd7f7f02aba0bf5467513bfda7e6b18a4cbc8 +md5: e5107e02dc4c2f9f41eef72d72c23517 +depends: +- libgcc >=13 +- __glibc >=2.17,<3.0.a0 +- libsuitesparseconfig >=7.10.1,<8.0a0 +license: BSD-3-Clause +license_family: BSD +size: 41578 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcholmod-5.3.1-h9cf07ce_7100101.conda +sha256: 69540315b4b8de93b383243334151ed19e98968baaa59440ba645a3bff68d765 +md5: f51e24ce110ae24c92074736a308e47e +depends: +- libgcc >=13 +- libstdcxx >=13 +- libgcc >=13 +- __glibc >=2.17,<3.0.a0 +- _openmp_mutex >=4.5 +- liblapack >=3.9.0,<4.0a0 +- libcolamd >=3.3.4,<4.0a0 +- libamd >=3.3.3,<4.0a0 +- libsuitesparseconfig >=7.10.1,<8.0a0 +- libccolamd >=3.3.4,<4.0a0 +- libblas >=3.9.0,<4.0a0 +- libcamd >=3.3.3,<4.0a0 +license: LGPL-2.1-or-later AND GPL-2.0-or-later AND Apache-2.0 +size: 990886 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcolamd-3.3.4-hf02c80a_7100101.conda +sha256: 00d1b976b914f0c20ae6f81f4e4713fa87717542eba8757b9a3c9e8abcc29858 +md5: 56d4c5542887e8955f21f8546ad75d9d +depends: +- libgcc >=13 +- __glibc >=2.17,<3.0.a0 +- libsuitesparseconfig >=7.10.1,<8.0a0 +license: BSD-3-Clause +license_family: BSD +size: 33160 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda +sha256: 205c4f19550f3647832ec44e35e6d93c8c206782bdd620c1d7cf66237580ff9c +md5: 49c553b47ff679a6a1e9fc80b9c5a2d4 +depends: +- __glibc >=2.17,<3.0.a0 +- krb5 >=1.22.2,<1.23.0a0 +- libgcc >=14 +- libstdcxx >=14 +- libzlib >=1.3.1,<2.0a0 +license: Apache-2.0 +license_family: Apache +size: 4518030 +timestamp: 1770902209173 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.21.0-hcf29cc6_1.conda +sha256: 7d243f45a48f62cb8e3b871dd336137fe0fb90094a191756fb553508837f6338 +md5: 2c1e55d695b11525c760b486ac0be517 +depends: +- __glibc >=2.17,<3.0.a0 +- krb5 >=1.22.2,<1.23.0a0 +- libgcc >=14 +- libnghttp2 >=1.68.1,<2.0a0 +- libssh2 >=1.11.1,<2.0a0 +- libzlib >=1.3.2,<2.0a0 +- openssl >=3.5.7,<4.0a0 +- zstd >=1.5.7,<1.6.0a0 +license: curl +license_family: MIT +size: 478914 +timestamp: 1782802520033 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcxsparse-4.4.1-hf02c80a_7100101.conda +sha256: ab40fc8a4662f550d053576a56db896247bc81eb291eff3811f24c231829e3dd +md5: 917931d508582ef891bbac172294d9fb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- _openmp_mutex >=4.5 +- libsuitesparseconfig >=7.10.1,<8.0a0 +license: LGPL-2.1-or-later +size: 113979 +timestamp: 1741963824815 +- 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/libedit-3.1.20250104-pl5321h7949ede_0.conda +sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724 +md5: c277e0a4d549b03ac1e9d6cbbe3d017b +depends: +- ncurses +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- ncurses >=6.5,<7.0a0 +license: BSD-2-Clause +license_family: BSD +size: 134676 +timestamp: 1738479519902 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda +sha256: 1cd6048169fa0395af74ed5d8f1716e22c19a81a8a36f934c110ca3ad4dd27b4 +md5: 172bf1cd1ff8629f2b1179945ed45055 +depends: +- libgcc-ng >=12 +license: BSD-2-Clause +license_family: BSD +size: 112766 +timestamp: 1702146165126 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda +sha256: 16feffd9ddbbe5b718515d38ee376c685ba95491cd901244e24671d20b952a77 +md5: b24d3c612f71e7aa74158d92106318b2 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- expat 2.8.1.* +license: MIT +license_family: MIT +size: 77856 +timestamp: 1781203599810 +- 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_19.conda +sha256: 8e0a3b5e41272e5678499b5dfc4cddb673f9e935de01eb0767ce857001229f46 +md5: 57736f29cc2b0ec0b6c2952d3f101b6a +depends: +- __glibc >=2.17,<3.0.a0 +- _openmp_mutex >=4.5 +constrains: +- libgcc-ng ==15.2.0=*_19 +- libgomp 15.2.0 he0feb66_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 1041084 +timestamp: 1778269013026 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda +sha256: 9dcf54adfaa5e861123c2da4f2f0451a685464ea7e5a41ad91cf67b31d658d98 +md5: 331ee9b72b9dff570d56b1302c5ab37d +depends: +- libgcc 15.2.0 he0feb66_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27694 +timestamp: 1778269016987 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-0.25.1-h3f43e3d_1.conda +sha256: 50a9e9815cf3f5bce1b8c5161c0899cc5b6c6052d6d73a4c27f749119e607100 +md5: 2f4de899028319b27eb7a4023be5dfd2 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libiconv >=1.18,<2.0a0 +license: GPL-3.0-or-later +license_family: GPL +size: 188293 +timestamp: 1753342911214 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda +sha256: 561a42758ef25b9ce308c4e2cf56daee4f06138385a17e29a492cd928e00be6f +md5: 42bf7eca1a951735fa06c0e3c0d5c8e6 +depends: +- libgfortran5 15.2.0 h68bc16d_19 +constrains: +- libgfortran-ng ==15.2.0=*_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27655 +timestamp: 1778269042954 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-15.2.0-h69a702a_19.conda +sha256: 9ca1d254a3e44e608abec6186b18d372cec21e5253e6da9750f4a8f4780ea0bb +md5: 35d07243abf828674d273aecd1dd537e +depends: +- libgfortran 15.2.0 h69a702a_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27727 +timestamp: 1778269220455 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda +sha256: 057978bb69fea29ed715a9b98adf71015c31baecc4aeb2bfc20d4fd5d83579d4 +md5: 85072b0ad177c966294f129b7c04a2d5 +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: 2483673 +timestamp: 1778269025089 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.2-h0d30a3d_0.conda +sha256: 4bee10e62796f01e4fa2b5849135b1cc061337fe9cf5eb9bd79e9664922ae0e4 +md5: 889febc66cd9e4190f80ef9718fa239b +depends: +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- libiconv >=1.18,<2.0a0 +- libzlib >=1.3.2,<2.0a0 +- libffi >=3.5.2,<3.6.0a0 +- pcre2 >=10.47,<10.48.0a0 +constrains: +- glib >2.66 +license: LGPL-2.1-or-later +size: 4754220 +timestamp: 1782463895250 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda +sha256: 5abe4ab9d93f6c9757d654f1969ae2267d4505315c1f2f8fe705fd60af084f1b +md5: faac990cb7aedc7f3a2224f2c9b0c26c +depends: +- __glibc >=2.17,<3.0.a0 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 603817 +timestamp: 1778268942614 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda +sha256: c467851a7312765447155e071752d7bf9bf44d610a5687e32706f480aad2833f +md5: 915f5995e94f60e9a4826e0b0920ee88 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: LGPL-2.1-only +size: 790176 +timestamp: 1754908768807 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda +sha256: cc38c900b9a20fe75e61cbb594e749c57a06d96510722f5ddfa309682062b065 +md5: 842a81de672ddcf476337c8bde3cad33 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libunistring >=0,<1.0a0 +license: LGPL-2.0-only +license_family: LGPL +size: 139036 +timestamp: 1760385590993 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda +sha256: 10056646c28115b174de81a44e23e3a0a3b95b5347d2e6c45cc6d49d35294256 +md5: 6178c6f2fb254558238ef4e6c56fb782 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- jpeg <0.0.0a +license: IJG AND BSD-3-Clause AND Zlib +size: 633831 +timestamp: 1775962768273 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libklu-2.3.5-h95ff59c_7100101.conda +sha256: 6b4d462642c240dc3671af74f7705b23f34eea0f71e0d9dbcf14b4ed008311ff +md5: efaa5e7dc6989363585fbb591480b256 +depends: +- libgcc >=13 +- __glibc >=2.17,<3.0.a0 +- _openmp_mutex >=4.5 +- metis >=5.1.0,<5.1.1.0a0 +- libcamd >=3.3.3,<4.0a0 +- liblapack >=3.9.0,<4.0a0 +- libcblas >=3.9.0,<4.0a0 +- libsuitesparseconfig >=7.10.1,<8.0a0 +- libcolamd >=3.3.4,<4.0a0 +- libamd >=3.3.3,<4.0a0 +- libcholmod >=5.3.1,<6.0a0 +- libblas >=3.9.0,<4.0a0 +- libbtf >=2.3.2,<3.0a0 +- libccolamd >=3.3.4,<4.0a0 +license: LGPL-2.1-or-later +size: 131775 +timestamp: 1741963824816 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda +build_number: 8 +sha256: 168e327d737059553e15cc6ec36d76b9bbb3931c2a7721555fd68b4c9348b247 +md5: 809be8ba8712c77bc7d44c2d99390dc4 +depends: +- libblas 3.11.0 8_h4a7cf45_openblas +constrains: +- blas 2.308 openblas +- libcblas 3.11.0 8*_openblas +- liblapacke 3.11.0 8*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18790 +timestamp: 1779859115086 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libldl-3.3.2-hf02c80a_7100101.conda +sha256: 590232cd302047023ab31b80458833a71b10aeabee7474304dc65db322b5cd70 +md5: 19b71122fea7f6b1c4815f385b2da419 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- libsuitesparseconfig >=7.10.1,<8.0a0 +license: LGPL-2.1-or-later +size: 23391 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda +sha256: ec30e52a3c1bf7d0425380a189d209a52baa03f22fb66dd3eb587acaa765bd6d +md5: b88d90cad08e6bc8ad540cb310a761fb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- xz 5.8.3.* +license: 0BSD +size: 113478 +timestamp: 1775825492909 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-devel-5.8.3-hb03c661_0.conda +sha256: 7858f6a173206bc8a5bdc8e75690483bb66c0dcc3809ac1cb43c561a4723623a +md5: 55c20edec8e90c4703787acaade60808 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- liblzma 5.8.3 hb03c661_0 +license: 0BSD +size: 491429 +timestamp: 1775825511214 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda +sha256: 663444d77a42f2265f54fb8b48c5450bfff4388d9c0f8253dd7855f0d993153f +md5: 2a45e7f8af083626f009645a6481f12d +depends: +- __glibc >=2.17,<3.0.a0 +- c-ares >=1.34.6,<2.0a0 +- libev >=4.33,<4.34.0a0 +- libev >=4.33,<5.0a0 +- libgcc >=14 +- libstdcxx >=14 +- libzlib >=1.3.1,<2.0a0 +- openssl >=3.5.5,<4.0a0 +license: MIT +license_family: MIT +size: 663344 +timestamp: 1773854035739 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda +sha256: 927fe72b054277cde6cb82597d0fcf6baf127dcbce2e0a9d8925a68f1265eef5 +md5: d864d34357c3b65a4b731f78c0801dc4 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +license: LGPL-2.1-only +license_family: GPL +size: 33731 +timestamp: 1750274110928 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda +sha256: 3d9aa85648e5e18a6d66db98b8c4317cc426721ad7a220aa86330d1ccedc8903 +md5: 2d3278b721e40468295ca755c3b84070 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libgfortran +- libgfortran5 >=14.3.0 +constrains: +- openblas >=0.3.33,<0.3.34.0a0 +license: BSD-3-Clause +license_family: BSD +size: 5931919 +timestamp: 1776993658641 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenssl-static-3.6.3-hb03c661_0.conda +sha256: ec9e1bc233830e8532df6cb91e210196909f9e7217693a995f0a5acf5e15008f +md5: b7fab41859799a59ede70d3bc608b8d6 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- openssl 3.6.3 h35e630c_0 +license: Apache-2.0 +license_family: Apache +size: 2889172 +timestamp: 1781069869884 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libparu-1.0.0-hc6afc67_7100101.conda +sha256: 50144e87b95d1309d2043aa5bf02035b948b1ae9ec6ec44ee97b7aec1cccd70a +md5: fd1d3e26c1b12c70f7449369ae3d9c1a +depends: +- libgcc >=13 +- libstdcxx >=13 +- libgcc >=13 +- __glibc >=2.17,<3.0.a0 +- _openmp_mutex >=4.5 +- libsuitesparseconfig >=7.10.1,<8.0a0 +- libblas >=3.9.0,<4.0a0 +- libumfpack >=6.3.5,<7.0a0 +license: GPL-3.0-or-later +license_family: GPL +size: 89738 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda +sha256: 377cfe037f3eeb3b1bf3ad333f724a64d32f315ee1958581fc671891d63d3f89 +md5: eba48a68a1a2b9d3c0d9511548db85db +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libzlib >=1.3.2,<2.0a0 +license: zlib-acknowledgement +size: 317729 +timestamp: 1776315175087 +- conda: https://conda.anaconda.org/conda-forge/linux-64/librbio-4.3.4-hf02c80a_7100101.conda +sha256: c502b4203cc0d38f49005994b5c80c89660bcd40ff170c529cda90827ec6b1f4 +md5: 4b3a3d711d1c1f76f7f440e51458f512 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- libsuitesparseconfig >=7.10.1,<8.0a0 +license: GPL-2.0-or-later +license_family: GPL +size: 46633 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libspex-3.2.3-h9226d62_7100101.conda +sha256: 24dffff614943c547ba094f8eb03b412a18cc4654663202f1aab9158bfa875ba +md5: 63323b258079a75133ccecbb0902614d +depends: +- libgcc >=13 +- __glibc >=2.17,<3.0.a0 +- _openmp_mutex >=4.5 +- libamd >=3.3.3,<4.0a0 +- libcolamd >=3.3.4,<4.0a0 +- libsuitesparseconfig >=7.10.1,<8.0a0 +- gmp >=6.3.0,<7.0a0 +- mpfr >=4.2.1,<5.0a0 +license: LGPL-2.0-or-later +license_family: LGPL +size: 79220 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libspqr-4.3.4-h23b7119_7100101.conda +sha256: 52851575496122f9088c9f5a4283da7fbb277d9a877b5ce60a939554df542f3c +md5: c1ee33a71065c1f0efd9c8174d5f18b0 +depends: +- libgcc >=13 +- libstdcxx >=13 +- libgcc >=13 +- __glibc >=2.17,<3.0.a0 +- libcholmod >=5.3.1,<6.0a0 +- libblas >=3.9.0,<4.0a0 +- liblapack >=3.9.0,<4.0a0 +- libsuitesparseconfig >=7.10.1,<8.0a0 +license: GPL-2.0-or-later +license_family: GPL +size: 203419 +timestamp: 1741963824816 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.3-h0c1763c_0.conda +sha256: 365376f4815e5e80def2b3462a2419708b7c292da0da85278386c2618621fff4 +md5: 4aed8e657e9ff156bdbe849b4df44389 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libzlib >=1.3.2,<2.0a0 +license: blessing +size: 962119 +timestamp: 1782519076616 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda +sha256: fa39bfd69228a13e553bd24601332b7cfeb30ca11a3ca50bb028108fe90a7661 +md5: eecce068c7e4eddeb169591baac20ac4 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- libzlib >=1.3.1,<2.0a0 +- openssl >=3.5.0,<4.0a0 +license: BSD-3-Clause +license_family: BSD +size: 304790 +timestamp: 1745608545575 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda +sha256: dff1058c76ec6b8759e41cefa2508162d00e4a5e6721aa68ec3fd10094e702dc +md5: 5794b3bdc38177caf969dabd3af08549 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc 15.2.0 he0feb66_19 +constrains: +- libstdcxx-ng ==15.2.0=*_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 5852044 +timestamp: 1778269036376 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda +sha256: 0672b6b6e1791c92e8eccad58081a99d614fcf82bca5841f9dfa3c3e658f83b9 +md5: e5ce228e579726c07255dbf90dc62101 +depends: +- libstdcxx 15.2.0 h934c35e_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27776 +timestamp: 1778269074600 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsuitesparseconfig-7.10.1-h901830b_7100101.conda +sha256: d8f32a0b0ee17fbace7af4bd34ad554cc855b9c18e0aeccf8395e1478c161f37 +md5: 57ae1dd979da7aa88a9b38bfa2e1d6b2 +depends: +- libgcc >=13 +- __glibc >=2.17,<3.0.a0 +- libgfortran5 >=13.3.0 +- libgfortran +- libgcc >=13 +- _openmp_mutex >=4.5 +license: BSD-3-Clause +license_family: BSD +size: 42708 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-h9d88235_0.conda +sha256: b31346e1c01ab40a170e91147092ee8fd92b1dee3c66ee47ef025571c879b159 +md5: c1fcb4a88bc15a9f77ad8d27d7af1df9 +depends: +- __glibc >=2.17,<3.0.a0 +- lerc >=4.1.0,<5.0a0 +- libdeflate >=1.25,<1.26.0a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.4.1,<4.0a0 +- liblzma >=5.8.3,<6.0a0 +- libstdcxx >=14 +- libwebp-base >=1.6.0,<2.0a0 +- libzlib >=1.3.2,<2.0a0 +- zstd >=1.5.7,<1.6.0a0 +license: HPND +size: 452337 +timestamp: 1783084902636 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libumfpack-6.3.5-h873dde6_7100101.conda +sha256: 9a2c0049210c0223084c29b39404ad6da6538e7a4d1ed74ee8423212998fd686 +md5: 9626fc7667bc6c901c7a0a4004938c71 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- libsuitesparseconfig >=7.10.1,<8.0a0 +- libcholmod >=5.3.1,<6.0a0 +- libblas >=3.9.0,<4.0a0 +- libamd >=3.3.3,<4.0a0 +license: GPL-2.0-or-later +license_family: GPL +size: 404065 +timestamp: 1741963824815 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 +sha256: e88c45505921db29c08df3439ddb7f771bbff35f95e7d3103bf365d5d6ce2a6d +md5: 7245a044b4a1980ed83196176b78b73a +depends: +- libgcc-ng >=9.3.0 +license: GPL-3.0-only OR LGPL-3.0-only +size: 1433436 +timestamp: 1626955018689 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-h5347b49_0.conda +sha256: 9b1bdce27a7e31f7d241aeecff67a1f3101d52a2b1e33ccc2cdf2613072bf81f +md5: 01bb81d12c957de066ea7362007df642 +depends: +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +license: BSD-3-Clause +license_family: BSD +size: 40017 +timestamp: 1781625522462 +- 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/libxcrypt-4.4.36-hd590300_1.conda +sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c +md5: 5aa797f8787fe7a17d1b0821485b5adc +depends: +- libgcc-ng >=12 +license: LGPL-2.1-or-later +size: 100393 +timestamp: 1702724383534 +- 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/linux-64/lp_solve-5.5.2.11-hd590300_0.conda +sha256: 3c28e1494834f77cbd23467fdac0f701cb9a0c17a4251e79e83f0946e788abf9 +md5: c9ca19b1a4b4f1038b23fb8b5918929c +depends: +- libgcc-ng >=12 +license: LGPL-2.1-only +size: 410024 +timestamp: 1697545354266 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mafft-7.526-h4bc722e_0.conda +sha256: e307b4d817c5f1d1173896d8d54b1b11761b0fc7889bf618ff59dd6407b11d36 +md5: cf3b2acf649bc31e576ed43a2fa4aaa3 +depends: +- __glibc >=2.17 +- __glibc >=2.17,<3.0.a0 +- gawk +- libgcc-ng >=12 +license: BSD-3-Clause +license_family: BSD +size: 2610460 +timestamp: 1720680384725 +- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.9-py312he3d6523_0.conda +sha256: c7e133837376e53e6a52719c205a3067c42f05769bc3e8307417f8d817dfc63e +md5: 7d499b5b6d150f133800dc3a582771c7 +depends: +- __glibc >=2.17,<3.0.a0 +- contourpy >=1.0.1 +- cycler >=0.10 +- fonttools >=4.22.0 +- freetype +- kiwisolver >=1.3.1 +- libfreetype >=2.14.3 +- libfreetype6 >=2.14.3 +- libgcc >=14 +- libstdcxx >=14 +- numpy >=1.23 +- numpy >=1.23,<3 +- packaging >=20.0 +- pillow >=8 +- pyparsing >=2.3.1 +- python >=3.12,<3.13.0a0 +- python-dateutil >=2.7 +- python_abi 3.12.* *_cp312 +- qhull >=2020.2,<2020.3.0a0 +- tk >=8.6.13,<8.7.0a0 +license: PSF-2.0 +license_family: PSF +size: 8336056 +timestamp: 1777000573501 +- conda: https://conda.anaconda.org/bioconda/linux-64/metaeuk-7.bba0d80-pl5321hd6d6fdc_2.tar.bz2 +sha256: 868647bb8b9a2827cdf98ba80310900b6b7d20fee438b59a1a68616db0452781 +md5: 92d44566468d6b5f4c854d5966069de4 +depends: +- _openmp_mutex >=4.5 +- bzip2 >=1.0.8,<2.0a0 +- gawk +- libgcc >=13 +- libstdcxx >=13 +- libzlib >=1.3.1,<2.0a0 +- perl >=5.32.1,<5.33.0a0 *_perl5 +- wget +- zlib +license: GPL-3 +license_family: GPL +size: 4534632 +timestamp: 1733936657790 +- conda: https://conda.anaconda.org/conda-forge/linux-64/metis-5.1.0-hd0bcaf9_1007.conda +sha256: e8a00971e6d00bd49f375c5d8d005b37a9abba0b1768533aed0f90a422bf5cc7 +md5: 28eb714416de4eb83e2cbc47e99a1b45 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- libstdcxx >=13 +license: Apache-2.0 +license_family: APACHE +size: 3923560 +timestamp: 1728064567817 +- conda: https://conda.anaconda.org/bioconda/linux-64/miniprot-0.18-h577a1d6_0.tar.bz2 +sha256: a7785a0db01773819ba1c3b897d2987a5ec18f4c80165096c87d924c7e4e845b +md5: e60a264d0b4ba975ac1fb1c8e66753a3 +depends: +- libgcc >=13 +- libzlib >=1.3.1,<2.0a0 +license: MIT +license_family: MIT +size: 70915 +timestamp: 1752254293809 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-he0a73b1_0.conda +sha256: 8690f550a780f75d9c47f7ffc15f5ff1c149d36ac17208e50eda101ca16611b9 +md5: 85ce2ffa51ab21da5efa4a9edc5946aa +depends: +- __glibc >=2.17,<3.0.a0 +- gmp >=6.3.0,<7.0a0 +- libgcc >=14 +license: LGPL-3.0-only +license_family: LGPL +size: 730422 +timestamp: 1773413915171 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mpi-1.0-openmpi.tar.bz2 +sha256: 54cf44ee2c122bce206f834a825af06e3b14fc4fd58c968ae9329715cc281d1e +md5: 1dcc49e16749ff79ba2194fa5d4ca5e7 +license: BSD 3-clause +size: 4204 +- conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda +sha256: d09c47c2cf456de5c09fa66d2c3c5035aa1fa228a1983a433c47b876aa16ce90 +md5: 37293a85a0f4f77bbd9cf7aaefc62609 +depends: +- python >=3.9 +license: Apache-2.0 +license_family: Apache +size: 15851 +timestamp: 1749895533014 +- conda: https://conda.anaconda.org/bioconda/linux-64/muscle-3.8.1551-h9948957_9.tar.bz2 +sha256: 07f12b158989bd98b4d7af97a2739ccd7bbef0728ddc5a036bd9784363ab0ba9 +md5: abeab9c9f2802eae4f867260650837f6 +depends: +- libgcc >=13 +- libstdcxx >=13 +license: GPL-3.0-only +size: 273543 +timestamp: 1752497842816 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-connector-c-6.1.11-h659d440_1008.conda +sha256: 0d796529e90bf6f511fd7199acfb5cc788e04d853e1afd48aa6bad33a6e49008 +md5: 149e0b89cbbe09397f1147cb3736bcbe +depends: +- libgcc-ng >=12 +- libstdcxx-ng >=12 +- openssl >=3.1.3,<4.0a0 +license: GPL-2.0-only +license_family: GPL +size: 1268505 +timestamp: 1697651492989 +- conda: https://conda.anaconda.org/bioconda/linux-64/ncbi-vdb-3.4.1-hd63eeec_0.conda +sha256: 1c876e74214ef7269de12286e1b9b370e3167c0825d215de3b81bf46f3956072 +md5: 70de9f284c305131b458cf69676f1b2f +depends: +- libgcc >=14 +- libstdcxx >=14 +license: Public Domain +size: 9227191 +timestamp: 1774474370894 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda +sha256: fc89f74bbe362fb29fa3c037697a89bec140b346a2469a90f7936d1d7ea4d8a3 +md5: fc21868a1a5aacc937e7a18747acb8a5 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: X11 AND BSD-3-Clause +size: 918956 +timestamp: 1777422145199 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.5-py312h33ff503_1.conda +sha256: 76ad6a6f4761084b074a587fe1512956891f04b5250cec0fd39aca0f39ad122b +md5: 03baecffb72fa96fe234fd505908065f +depends: +- python +- __glibc >=2.17,<3.0.a0 +- libstdcxx >=14 +- libgcc >=14 +- libblas >=3.9.0,<4.0a0 +- liblapack >=3.9.0,<4.0a0 +- python_abi 3.12.* *_cp312 +- libcblas >=3.9.0,<4.0a0 +constrains: +- numpy-base <0a0 +license: BSD-3-Clause +license_family: BSD +size: 8820597 +timestamp: 1766383409220 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjdk-25.0.1-h5755bd7_0.conda +sha256: 19b2268bf2d1fc4b4f48a68b9bfac620370c1b7f539671279053b0d3bcc348f1 +md5: a40ce38da029d1d272bfd9bd7510f901 +depends: +- __glibc >=2.17,<3.0.a0 +- alsa-lib >=1.2.14,<1.3.0a0 +- fontconfig >=2.15.0,<3.0a0 +- fonts-conda-ecosystem +- giflib >=5.2.2,<5.3.0a0 +- harfbuzz >=12.1.0 +- lcms2 >=2.17,<3.0a0 +- libcups >=2.3.3,<2.4.0a0 +- libfreetype >=2.14.1 +- libfreetype6 >=2.14.1 +- libgcc >=14 +- libjpeg-turbo >=3.1.0,<4.0a0 +- libpng >=1.6.50,<1.7.0a0 +- libstdcxx >=14 +- libzlib >=1.3.1,<2.0a0 +- xorg-libx11 >=1.8.12,<2.0a0 +- xorg-libxext >=1.3.6,<2.0a0 +- xorg-libxi >=1.8.2,<2.0a0 +- xorg-libxrandr >=1.5.4,<2.0a0 +- xorg-libxrender >=0.9.12,<0.10.0a0 +- xorg-libxt >=1.3.1,<2.0a0 +- xorg-libxtst >=1.2.5,<2.0a0 +license: GPL-2.0-or-later WITH Classpath-exception-2.0 +license_family: GPL +size: 117033638 +timestamp: 1762057253080 +- 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/openmpi-4.1.6-hc5af2df_101.conda +sha256: f0769dd891e1735be4606ec8643951e5cbca199f774e58c7d933f70a70134ce4 +md5: f9a2ad0088ee38f396350515fa37d243 +depends: +- libgcc-ng >=12 +- libgfortran-ng +- libgfortran5 >=12.3.0 +- libstdcxx-ng >=12 +- libzlib >=1.2.13,<2.0.0a0 +- mpi 1.0 openmpi +- zlib +constrains: +- cudatoolkit >= 10.2 +- ucx >=1.15.0,<2.0a0 +- libpmix ==0.0.0 +- libprrte ==0.0.0 +license: BSD-3-Clause +license_family: BSD +size: 4069632 +timestamp: 1696593196408 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda +sha256: d48f5c22b9897c01e4dff3680f1f57ceb02711ab9c62f74339b080419dfad34b +md5: 79dd2074b5cd5c5c6b2930514a11e22d +depends: +- __glibc >=2.17,<3.0.a0 +- ca-certificates +- libgcc >=14 +license: Apache-2.0 +license_family: Apache +size: 3159683 +timestamp: 1781069855778 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda +sha256: 3906abfb6511a3bb309e39b9b1b7bc38f50a723971de2395489fd1f379255890 +md5: 4c06a92e74452cfa53623a81592e8934 +depends: +- python >=3.8 +- python +license: Apache-2.0 +license_family: APACHE +size: 91574 +timestamp: 1777103621679 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py312h8ecdadd_0.conda +sha256: 009408dcfdc789b8a1748d6a63fd2134ea2edc8474231ea7beba0ac3ad772a37 +md5: 15c437bfa4cbddd379b95357c9aa4150 +depends: +- python +- numpy >=1.26.0 +- python-dateutil >=2.8.2 +- libgcc >=14 +- libstdcxx >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.12.* *_cp312 +- numpy >=1.23,<3 +constrains: +- adbc-driver-postgresql >=1.2.0 +- adbc-driver-sqlite >=1.2.0 +- beautifulsoup4 >=4.12.3 +- blosc >=1.21.3 +- bottleneck >=1.4.2 +- fastparquet >=2024.11.0 +- fsspec >=2024.10.0 +- gcsfs >=2024.10.0 +- html5lib >=1.1 +- hypothesis >=6.116.0 +- jinja2 >=3.1.5 +- lxml >=5.3.0 +- matplotlib >=3.9.3 +- numba >=0.60.0 +- numexpr >=2.10.2 +- odfpy >=1.4.1 +- openpyxl >=3.1.5 +- psycopg2 >=2.9.10 +- pyarrow >=13.0.0 +- pyiceberg >=0.8.1 +- pymysql >=1.1.1 +- pyqt5 >=5.15.9 +- pyreadstat >=1.2.8 +- pytables >=3.10.1 +- pytest >=8.3.4 +- pytest-xdist >=3.6.1 +- python-calamine >=0.3.0 +- pytz >=2024.2 +- pyxlsb >=1.0.10 +- qtpy >=2.4.2 +- scipy >=1.14.1 +- s3fs >=2024.10.0 +- sqlalchemy >=2.0.36 +- tabulate >=0.9.0 +- xarray >=2024.10.0 +- xlrd >=2.0.1 +- xlsxwriter >=3.2.0 +- zstandard >=0.23.0 +license: BSD-3-Clause +license_family: BSD +size: 14872605 +timestamp: 1778602625175 +- conda: https://conda.anaconda.org/bioconda/linux-64/pasta-1.9.3-py312h85383db_1.conda +sha256: e93307492e9c4767e082db35dcf2274c7dd69f4a0e79cd20770a79198a32cfa1 +md5: a2760ddddfd4417f90003bb57a54e3b1 +depends: +- __glibc >=2.17,<3.0.a0 +- _openmp_mutex >=4.5 +- clustalw >=2.1,<3.0a0 +- dendropy >=5.0.8,<6.0a0 +- fasttree >=2.2.0,<3.0a0 +- hmmer >=3.4,<3.5.0a0 +- libgcc >=14 +- libgomp +- mafft >=7.526,<8.0a0 +- muscle <4 +- muscle >=3.8.1551,<4.0a0 +- openjdk +- openmpi >=4.1.6,<5.0a0 +- pcre >=8.45,<9.0a0 +- prank >=251117 +- pymongo +- python >=3.12,<3.13.0a0 +- python_abi 3.12.* *_cp312 +- raxml >=8.2.13,<9.0a0 +license: GPL-3.0-or-later +license_family: GPL3 +size: 1180080 +timestamp: 1781610923262 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pcre-8.45-h9c3ff4c_0.tar.bz2 +sha256: 8f35c244b1631a4f31fb1d66ab6e1d9bfac0ca9b679deced1112c7225b3ad138 +md5: c05d1820a6d34ff07aaaab7a9b7eddaa +depends: +- libgcc-ng >=9.3.0 +- libstdcxx-ng >=9.3.0 +license: BSD-3-Clause +license_family: BSD +size: 259377 +timestamp: 1623788789327 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda +sha256: 5e6f7d161356fefd981948bea5139c5aa0436767751a6930cb1ca801ebb113ff +md5: 7a3bff861a6583f1889021facefc08b1 +depends: +- __glibc >=2.17,<3.0.a0 +- bzip2 >=1.0.8,<2.0a0 +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +license: BSD-3-Clause +license_family: BSD +size: 1222481 +timestamp: 1763655398280 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda +build_number: 7 +sha256: 9ec32b6936b0e37bcb0ed34f22ec3116e75b3c0964f9f50ecea5f58734ed6ce9 +md5: f2cfec9406850991f4e3d960cc9e3321 +depends: +- libgcc-ng >=12 +- libxcrypt >=4.4.36 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 13344463 +timestamp: 1703310653947 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-app-cpanminus-1.7048-pl5321hd8ed1ab_0.conda +sha256: 20850458e691b12fc4da209e204fc4c4d1abe93311913929dc536b9b3857b681 +md5: adb8fae79589a7bb03aa9ad976e3bd92 +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 229935 +timestamp: 1730267467434 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-archive-tar-3.12-pl5321hdfd78af_0.conda +sha256: fb56a9489a87fc238fc70da7a2329495204eec30f7a5f5af1014a6fb22b528f4 +md5: 4ee2727440bf9b0b055c1f17a72701f6 +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +- perl-io-compress +- perl-io-zlib +- perl-pathtools +license: Perl_5 +size: 38811 +timestamp: 1780439474451 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-carp-1.50-pl5321hd8ed1ab_0.tar.bz2 +sha256: 1981e31113e1e77a2cdc13db657c636f047cd3be2a64d9a0bffac03c5427c1bd +md5: bdddc03e28019b902da71b722f2288d7 +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +- perl-exporter +- perl-extutils-makemaker +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 22257 +timestamp: 1636653208008 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-class-method-modifiers-2.13-pl5321ha770c72_0.tar.bz2 +sha256: bed763551ecf5e47249f4596b642f6279d64ee6e1c73998236456829c29ea6c2 +md5: 7b7ec3dd22b056c2d5ea53f9033c26b8 +depends: +- perl >=5.32.1,<5.33.0a0 *_perl5 +- perl-test-fatal 0.016.* +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 22098 +timestamp: 1666342663240 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-common-sense-3.75-pl5321hd8ed1ab_0.tar.bz2 +sha256: 38ef218e9b9d55b9fbdce6b31cf81bcf6f1b16f21b8e7cb9279b41399522a320 +md5: ef70dc77e8b10bbb62f5e843b401ef0e +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 20291 +timestamp: 1660429950685 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-compress-raw-bzip2-2.214-pl5321hda65f42_0.conda +sha256: 2cbd3fcb7028415654057ab3142cee1e5cc4cf9bdd0e590f072e8ecd29cb6382 +md5: 1ec33b9f74a71c17cc5579e35027832a +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- perl >=5.32.1,<5.33.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 55733 +timestamp: 1761332551110 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-compress-raw-zlib-2.214-pl5321h4dac143_0.conda +sha256: 4fd3a11f8dbd2c9d1a1c5547e344ad20412a3f0d36967502d9764e1b2734dd47 +md5: 943e7033e6f709adf0d89a3af51ab81b +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- perl >=5.32.1,<5.33.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 81114 +timestamp: 1761332700914 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-constant-1.33-pl5321hd8ed1ab_0.tar.bz2 +sha256: cfd5ef9af8de221292f7059d1ff88ff10f1340fc4dbbd0dc81ce2275bf76651d +md5: 7f9fc9cfa08a3fe36ffcff820c65c3ac +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 15711 +timestamp: 1636645107290 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-dbi-1.649-pl5321hb03c661_0.conda +sha256: 714c4922a4b7e84862c5daa22466d4bac874061bf8390c4b90f0ca2a319db768 +md5: 180ac4ad798ea3aae1065017f7b80602 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- perl >=5.32.1,<5.33.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 601329 +timestamp: 1782243103202 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-encode-3.24-pl5321hb03c661_0.conda +sha256: c83d8de38ce43ca15af05f76bc933ff76894aef84baed47300e463dae0c11857 +md5: 35776d4c5766e9d98754d1e7530c2961 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- perl >=5.32.1,<5.33.0a0 *_perl5 +- perl-exporter +- perl-parent +- perl-storable +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 1725053 +timestamp: 1780396038421 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-exporter-5.74-pl5321hd8ed1ab_0.tar.bz2 +sha256: 42271d0b79043a10a89044acb5febea50046b745dd2fc37e02943bc3bc75bf8e +md5: fd2eac4e35f8c970870a3961c1df3e29 +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 19071 +timestamp: 1636696009075 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-exporter-tiny-1.002002-pl5321hd8ed1ab_0.tar.bz2 +sha256: abdf86828a12a389d0feb0d70501b267842557bae11820e266526aeb6ab2bebe +md5: 48d709826875be1f2c108d3d1d8efec7 +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 28592 +timestamp: 1660341479867 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-extutils-makemaker-7.70-pl5321hd8ed1ab_0.conda +sha256: 1d3f342ca74cf2948c3edcfe0d3367b1db0fc64bb163393a2e025336dec3a40c +md5: ec3e57ed34f7765bfc7054a05868ce5d +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 157323 +timestamp: 1679847836884 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-file-path-2.18-pl5321hd8ed1ab_0.tar.bz2 +sha256: ac7a0e0c36ec199709c8523132ded35efb84941a1a476b271fd25362dfbf5339 +md5: e13e456f61b8261ba074c0aa93086afe +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +- perl-exporter +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 22382 +timestamp: 1636696260633 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-file-temp-0.2304-pl5321hd8ed1ab_0.tar.bz2 +sha256: 91f9fe152b38441386053876198d0c9437e7b4b5fa7da1e5db48b9e1b21fdae9 +md5: 0a039c4fc36748942287ee10d0431515 +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +- perl-carp +- perl-constant +- perl-exporter +- perl-file-path +- perl-parent +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 31509 +timestamp: 1636696164992 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-file-which-1.24-pl5321hd8ed1ab_0.tar.bz2 +sha256: 901e9c4177b6bdb23600446fd64a105a437112e63bc23a6163f669bc5098c502 +md5: 94e5b2c9d56ef7c4c70ddf51ac38ae3d +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 17329 +timestamp: 1636695979827 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-inc-latest-0.500-pl5321ha770c72_0.conda +sha256: ff6b6ffffd6ecbed19a00ee41bb54c283d171f3feff7f45e840441551b5ab876 +md5: 0879971f134628d37bc4b13581113134 +depends: +- perl >=5.32.1,<5.33.0a0 *_perl5 +license: Apache-2.0 +license_family: APACHE +size: 16039 +timestamp: 1669240163980 +- conda: https://conda.anaconda.org/bioconda/linux-64/perl-io-compress-2.216-pl5321h503566f_0.conda +sha256: 5241c33cf55ba0cbfc0ccab96b4a31123761db00310eab4fedd7a95226c4fca7 +md5: 0784cb3c120f934a5fe61961c8238330 +depends: +- libgcc >=13 +- libstdcxx >=13 +- perl >=5.32.1,<5.33.0a0 *_perl5 +- perl-compress-raw-bzip2 >=2.214 +- perl-compress-raw-zlib >=2.214 +- perl-encode +- perl-scalar-list-utils +license: Perl_5 +size: 87231 +timestamp: 1769815108308 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-io-zlib-1.15-pl5321hdfd78af_1.tar.bz2 +sha256: 771a44b338cac68a22893897450222b886e24bbb291b014897d561f2ba3b588f +md5: db92645dabe9467115729e4479841b5d +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 12760 +timestamp: 1752069858135 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-json-4.11-pl5321hdfd78af_0.conda +sha256: 1c1649f491c76f4ae2984b547701df91c8abfda2e3b7b44e0c007f5e78a87c08 +md5: 56411755d21870a9ec16c76fd7b66dba +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +- perl-json-xs +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 52845 +timestamp: 1774152885168 +- conda: https://conda.anaconda.org/bioconda/linux-64/perl-json-xs-4.04-pl5321h9948957_0.conda +sha256: f16cf35917a5d75fb55cfc69d8651dc72ff4e06370142b447a4864f5de7d97c6 +md5: 7916b2e794393b3389535ba750f489da +depends: +- libgcc >=13 +- libstdcxx >=13 +- perl >=5.32.1,<5.33.0a0 *_perl5 +- perl-common-sense +- perl-types-serialiser +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 70770 +timestamp: 1757352008878 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-list-moreutils-0.430-pl5321hdfd78af_0.tar.bz2 +sha256: 2190cc8430bb218ea80f5fc5e2bf75e4e20a27fb83e8c3cb789a18c32854a56c +md5: 7f04c79d216d0f8e7b6d5a51de4aafa0 +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +- perl-exporter-tiny +- perl-list-moreutils-xs >=0.430 +license: apache_2_0 +size: 32468 +timestamp: 1644871004171 +- conda: https://conda.anaconda.org/bioconda/linux-64/perl-list-moreutils-xs-0.430-pl5321h7b50bb2_5.tar.bz2 +sha256: fe2d360770fe5b856ee1e625eac6b07cea386c64b0866e323c6535eb62b9ceee +md5: 9192770eb08524038c3fcf24e915b10c +depends: +- libgcc >=13 +- perl >=5.32.1,<5.33.0a0 *_perl5 +license: apache_2_0 +size: 51506 +timestamp: 1741776389435 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-module-build-0.4234-pl5321ha770c72_1.conda +sha256: 40bc64172a969e87ade758320049c86c6a0d83cf8aeaa69ad218fa463ac6cb5b +md5: 358d42e9f08dd917b649089526e2ae1f +depends: +- perl >=5.32.1,<5.33.0a0 *_perl5 +- perl-inc-latest 0.500.* +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 137087 +timestamp: 1738241035046 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-moo-2.005004-pl5321ha770c72_0.tar.bz2 +sha256: e82a11e50392c965e88db4cba4d23ed0be5c4917319385ea23d32d9484246227 +md5: 3499fef1ed2c74f253b1f032f22deb51 +depends: +- perl >=5.32.1,<5.33.0a0 *_perl5 +- perl-class-method-modifiers 2.13.* +- perl-role-tiny 2.002004.* +- perl-sub-quote 2.006006.* +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 47669 +timestamp: 1666344231925 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-parallel-forkmanager-2.04-pl5321hdfd78af_0.conda +sha256: d71f83a9d415beb11e4f9832122236cd13686393f6336863ebc8a46d5e3e315f +md5: c0d5b1238870d70b3af64854901d7f62 +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +- perl-carp +- perl-file-path +- perl-file-temp +- perl-moo +- perl-storable +license: perl_5 +size: 24120 +timestamp: 1756574734791 +- conda: https://conda.anaconda.org/conda-forge/noarch/perl-parent-0.243-pl5321hd8ed1ab_0.conda +sha256: ec57d9e56ba86d840d5a9e65c665365fb6a290851cd13e6719628f3295eabf34 +md5: 314caa3b72d65f8078d426c6721dcacc +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 13933 +timestamp: 1733429736293 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-pathtools-3.75-pl5321hb9d3cd8_2.conda +sha256: a80bc265aa749ae03fdd6d5f2098312ea6f43cc193ea7aba0e6e4304d84ce8c0 +md5: 03d88c89dfac8a26adcdeff242f94007 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- perl >=5.32.1,<5.33.0a0 *_perl5 +- perl-carp +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 50681 +timestamp: 1741783312134 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-role-tiny-2.002004-pl5321ha770c72_0.tar.bz2 +sha256: 7895ed40c44c08ee3ddbb48a3ee70e1eda32a6c529b632af98663e7603adda08 +md5: 83b5b630aeddca09e26fded9af4f3ce5 +depends: +- perl >=5.32.1,<5.33.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 23283 +timestamp: 1666339833893 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-scalar-list-utils-1.70-pl5321hb03c661_0.conda +sha256: 00678b34a57df53fa31585ff1579f42a6dfc8b1b059fd1b386c6e89573959a9f +md5: 046486011bf7674e3c2f2a1513ac4f3d +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- perl >=5.32.1,<5.33.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 51958 +timestamp: 1753965684679 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-storable-3.15-pl5321hb9d3cd8_2.conda +sha256: 25beba40154a394189d0ff2afd31683d79c9106d47e77e12d20900d053dffaf6 +md5: 212f63a5c7c753ecf0a74c349b9270c5 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- perl >=5.32.1,<5.33.0a0 *_perl5 +license: GPL-1.0-or-later OR Artistic-1.0-Perl +license_family: OTHER +size: 71475 +timestamp: 1741353849888 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-sub-quote-2.006006-pl5321ha770c72_0.tar.bz2 +sha256: 4200429318a1a2d9276c4095bb63e29d655fc98208341b6db0752788d3016587 +md5: 3d58e92f33b2382c10ac7eccd883a42f +depends: +- perl >=5.32.1,<5.33.0a0 *_perl5 +- perl-test-fatal 0.016.* +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 26698 +timestamp: 1666342630627 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-test-fatal-0.016-pl5321ha770c72_0.tar.bz2 +sha256: d5420f90b3bca641cdad0c5674b356a060bf1587e82d3828f382a466bdaba6d1 +md5: 5c397b1fd3095004f4ff149af1c0dd3c +depends: +- perl >=5.32.1,<5.33.0a0 *_perl5 +- perl-try-tiny 0.31.* +license: GPL-1.0-or-later OR Artistic-1.0-Perl +size: 19528 +timestamp: 1666339958976 +- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-try-tiny-0.31-pl5321ha770c72_0.tar.bz2 +sha256: 7e74c95eb085b095a258a22ee2f30192d79f23a58cbbcb8ca2b14f4fe0a8c406 +md5: cc23b14ed56bf51d84832d98ebd156af +depends: +- perl >=5.32.1,<5.33.0a0 *_perl5 +license: MIT +license_family: MIT +size: 17704 +timestamp: 1659695570098 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-types-serialiser-1.01-pl5321hdfd78af_0.tar.bz2 +sha256: 20f61217b16235d0161ad6fa0a234585afcc04ec5a6142c65b5867e26216dfe3 +md5: cfc65753e827bbef80c00eaa395f6ae7 +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +- perl-common-sense +license: perl_5 +size: 13136 +timestamp: 1644512391683 +- conda: https://conda.anaconda.org/bioconda/noarch/perl-yaml-1.30-pl5321hdfd78af_0.tar.bz2 +noarch: true +sha256: 6813626ecc8859b4f16de20f35c9bfdfbdf0a60d7da33494bca6c0c34511a76e +md5: da9ef80f4c4c2374d7f4ec7af6d96b6a +depends: +- perl >=5.32.1,<6.0a0 *_perl5 +license: perl_5 +size: 43572 +timestamp: 1644444148032 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h50c33e8_0.conda +sha256: 76b2e56c7a903a06be1210d35f35c2a8dcdc57912fda5c96b2e68acfd2b281fe +md5: d749d04e1965315078f29320565c595a +depends: +- python +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- libtiff >=4.7.1,<4.8.0a0 +- libxcb >=1.17.0,<2.0a0 +- tk >=8.6.13,<8.7.0a0 +- openjpeg >=2.5.4,<3.0a0 +- zlib-ng >=2.3.3,<2.4.0a0 +- python_abi 3.12.* *_cp312 +- libjpeg-turbo >=3.1.4.1,<4.0a0 +- lcms2 >=2.19.1,<3.0a0 +- libfreetype >=2.14.3 +- libfreetype6 >=2.14.3 +- libwebp-base >=1.6.0,<2.0a0 +license: HPND +size: 1064129 +timestamp: 1782912080163 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda +sha256: 43d37bc9ca3b257c5dd7bf76a8426addbdec381f6786ff441dc90b1a49143b6a +md5: c01af13bdc553d1a8fbfff6e8db075f0 +depends: +- libgcc >=14 +- libstdcxx >=14 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +license: MIT +license_family: MIT +size: 450960 +timestamp: 1754665235234 +- conda: https://conda.anaconda.org/bioconda/linux-64/prank-251117-hd63eeec_0.conda +sha256: b1b6b8c79e42951a2a9a549a15b53cd080d738df187e1af7b9b5c455926035e9 +md5: 62e656e8faac6f46598cfdda62215869 +depends: +- libgcc >=14 +- libstdcxx >=14 +license: GPL-3.0-or-later +license_family: GPL3 +size: 453551 +timestamp: 1775699386639 +- 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/bioconda/linux-64/prodigal-2.6.3-h577a1d6_11.tar.bz2 +sha256: 1211d9f01128f141154cb4616aa5b15890afc26699767886f6655cabfd67ec06 +md5: 7b083f573760cbd88a206e05f73f5e9d +depends: +- libgcc >=13 +- libzlib >=1.3.1,<2.0a0 +license: GPL-3.0-or-later +license_family: GPL3 +size: 601984 +timestamp: 1752712731224 +- 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/linux-64/pymongo-4.17.0-py312h1289d80_0.conda +sha256: 9d5c726b2f6cf3aa0a384a4807789d1153e7e4696f01d3aaa9fd1bd978912342 +md5: 955dab0e5b7f1299628c6ca58c1a8d05 +depends: +- __glibc >=2.17,<3.0.a0 +- dnspython <3.0.0,>=2.6.1 +- libgcc >=14 +- libstdcxx >=14 +- python >=3.12,<3.13.0a0 +- python_abi 3.12.* *_cp312 +license: Apache-2.0 +license_family: APACHE +size: 2400390 +timestamp: 1776765918970 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda +sha256: 417fba4783e528ee732afa82999300859b065dc59927344b4859c64aae7182de +md5: 3687cc0b82a8b4c17e1f0eb7e47163d5 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 110893 +timestamp: 1769003998136 +- 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.12.13-hd63d673_0_cpython.conda +sha256: a44655c1c3e1d43ed8704890a91e12afd68130414ea2c0872e154e5633a13d7e +md5: 7eccb41177e15cc672e1babe9056018e +depends: +- __glibc >=2.17,<3.0.a0 +- bzip2 >=1.0.8,<2.0a0 +- ld_impl_linux-64 >=2.36.1 +- libexpat >=2.7.4,<3.0a0 +- libffi >=3.5.2,<3.6.0a0 +- libgcc >=14 +- liblzma >=5.8.2,<6.0a0 +- libnsl >=2.0.1,<2.1.0a0 +- libsqlite >=3.51.2,<4.0a0 +- libuuid >=2.41.3,<3.0a0 +- libxcrypt >=4.4.36 +- libzlib >=1.3.1,<2.0a0 +- ncurses >=6.5,<7.0a0 +- openssl >=3.5.5,<4.0a0 +- readline >=8.3,<9.0a0 +- tk >=8.6.13,<8.7.0a0 +- tzdata +constrains: +- python_abi 3.12.* *_cp312 +license: Python-2.0 +size: 31608571 +timestamp: 1772730708989 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda +sha256: d6a17ece93bbd5139e02d2bd7dbfa80bee1a4261dced63f65f679121686bf664 +md5: 5b8d21249ff20967101ffa321cab24e8 +depends: +- python >=3.9 +- six >=1.5 +- python +license: Apache-2.0 +license_family: APACHE +size: 233310 +timestamp: 1751104122689 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda +build_number: 8 +sha256: 80677180dd3c22deb7426ca89d6203f1c7f1f256f2d5a94dc210f6e758229809 +md5: c3efd25ac4d74b1584d2f7a57195ddf1 +constrains: +- python 3.12.* *_cpython +license: BSD-3-Clause +license_family: BSD +size: 6958 +timestamp: 1752805918820 +- conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda +sha256: 776363493bad83308ba30bcb88c2552632581b143e8ee25b1982c8c743e73abc +md5: 353823361b1d27eb3960efb076dfcaf6 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc-ng >=12 +- libstdcxx-ng >=12 +license: LicenseRef-Qhull +size: 552937 +timestamp: 1720813982144 +- conda: https://conda.anaconda.org/bioconda/linux-64/raxml-8.2.13-h7b50bb2_3.tar.bz2 +sha256: 2a974acb73d07dc7e142c997101f14ce865ea4b8f8fb203849002848c37171b9 +md5: 48880314905ab03663a8fb4d97c835ff +depends: +- libgcc >=13 +license: GPL +size: 3227304 +timestamp: 1734060260551 +- 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/requests-2.34.2-pyhcf101f3_0.conda +sha256: 1715246b19c9f85ee022933b4845f2fc14ac9184981b7b7d9b728bec8e9588da +md5: 4a85203c1d80c1059086ae860836ffb9 +depends: +- python >=3.10 +- certifi >=2023.5.7 +- charset-normalizer >=2,<4 +- idna >=2.5,<4 +- urllib3 >=1.26,<3 +- python +constrains: +- chardet >=3.0.2,<8 +license: Apache-2.0 +license_family: APACHE +size: 68709 +timestamp: 1778851103479 +- conda: https://conda.anaconda.org/bioconda/linux-64/samtools-1.23.1-ha83d96e_0.conda +sha256: 2cb721907a2df7c54580298d655ae7587dbed593bd5536fa8ef4a22c9ae2a496 +md5: 89624fbd17c069abcbc8b19b96d497a0 +depends: +- htslib >=1.23.1,<1.24.0a0 +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +- ncurses >=6.5,<7.0a0 +license: MIT +size: 489995 +timestamp: 1773861794171 +- conda: https://conda.anaconda.org/bioconda/linux-64/sepp-4.5.5-py312h0fa9677_3.tar.bz2 +sha256: 5fbf02bc26469c1906a13a9d51bea271bb39587be85867d5f79ee6edae91acce +md5: fa93b481d4e0b4632e24d57434d3e41f +depends: +- dendropy >=5.0.6,<6.0a0 +- hmmer >=3.4,<3.5.0a0 +- libgcc >=13 +- pasta +- python >=3.12,<3.13.0a0 +- python_abi 3.12.* *_cp312 +license: GPL-3.0-or-later +license_family: GPL3 +size: 6991084 +timestamp: 1746011168040 +- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda +sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d +md5: 3339e3b65d58accf4ca4fb8748ab16b3 +depends: +- python >=3.9 +- python +license: MIT +license_family: MIT +size: 18455 +timestamp: 1753199211006 +- conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda +sha256: dce518f45e24cd03f401cb0616917773159a210c19d601c5f2d4e0e5879d30ad +md5: 03fe290994c5e4ec17293cfb6bdce520 +depends: +- python >=3.10 +license: Apache-2.0 +license_family: Apache +size: 15698 +timestamp: 1762941572482 +- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.3-hbc0de68_0.conda +sha256: ef17725138fa72aa5a0f8ccace9727831c4b333e39575f78fb5ad1755826b687 +md5: b345ea7f13e4cae9809c69b1d1af2c99 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libsqlite 3.53.3 h0c1763c_0 +- libzlib >=1.3.2,<2.0a0 +- ncurses >=6.6,<7.0a0 +- readline >=8.3,<9.0a0 +license: blessing +size: 206481 +timestamp: 1782519082269 +- conda: https://conda.anaconda.org/conda-forge/linux-64/suitesparse-7.10.1-h5b2951e_7100101.conda +sha256: 7c1c5bd2ba8385202ac3cb4c9c7f9bb87a2e677e977afd72c910314c014b28be +md5: e927e0f248a498050443dab8bb1203a9 +depends: +- libsuitesparseconfig ==7.10.1 h901830b_7100101 +- libamd ==3.3.3 h456b2da_7100101 +- libbtf ==2.3.2 hf02c80a_7100101 +- libcamd ==3.3.3 hf02c80a_7100101 +- libccolamd ==3.3.4 hf02c80a_7100101 +- libcolamd ==3.3.4 hf02c80a_7100101 +- libcholmod ==5.3.1 h9cf07ce_7100101 +- libcxsparse ==4.4.1 hf02c80a_7100101 +- libldl ==3.3.2 hf02c80a_7100101 +- libklu ==2.3.5 h95ff59c_7100101 +- libumfpack ==6.3.5 h873dde6_7100101 +- libparu ==1.0.0 hc6afc67_7100101 +- librbio ==4.3.4 hf02c80a_7100101 +- libspex ==3.2.3 h9226d62_7100101 +- libspqr ==4.3.4 h23b7119_7100101 +license: LGPL-2.1-or-later AND BSD-3-Clause AND GPL-2.0-or-later AND Apache-2.0 +size: 12135 +timestamp: 1741963824816 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tar-1.35-h3b78370_0.conda +sha256: eab162cadb948c91c14f18b6f30a7c270d682e820c4f2fdb0030c9fc99b3fa49 +md5: 8e037804a92c84cb901bdd83a8e5ff46 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libiconv >=1.18,<2.0a0 +license: GPL-3.0-or-later +license_family: GPL +size: 778622 +timestamp: 1753467956747 +- 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/tzdata-2025c-hc9c84f9_1.conda +sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c +md5: ad659d0a2b3e47e38d829aa8cad2d610 +license: LicenseRef-Public-Domain +size: 119135 +timestamp: 1767016325805 +- conda: https://conda.anaconda.org/bioconda/linux-64/ucsc-fatotwobit-482-hdc0a859_0.tar.bz2 +sha256: 49a3812350d8bcde5993e1620e36921e7419fb98db8b160e186fff16a4bfdaf9 +md5: bfac086f1764d2aedfb35540a9009cdf +depends: +- bzip2 >=1.0.8,<2.0a0 +- libgcc >=13 +- liblzma >=5.8.1,<6.0a0 +- libopenssl-static +- libpng >=1.6.49,<1.7.0a0 +- libuuid >=2.38.1,<3.0a0 +- libzlib >=1.3.1,<2.0a0 +- mysql-connector-c >=6.1.11,<6.1.12.0a0 +license: Varies; see https://genome.ucsc.edu/license +size: 383232 +timestamp: 1750330214400 +- conda: https://conda.anaconda.org/bioconda/linux-64/ucsc-twobitinfo-482-hdc0a859_0.tar.bz2 +sha256: 113321fb70d6cd6b75c04dbd0925cb7a2f4aabfd138d0206af82f899412a1bb6 +md5: 91466585cc720548e4e4c105686fecb8 +depends: +- bzip2 >=1.0.8,<2.0a0 +- libgcc >=13 +- liblzma >=5.8.1,<6.0a0 +- libopenssl-static +- libpng >=1.6.49,<1.7.0a0 +- libuuid >=2.38.1,<3.0a0 +- libzlib >=1.3.1,<2.0a0 +- mysql-connector-c >=6.1.11,<6.1.12.0a0 +license: Varies; see https://genome.ucsc.edu/license +size: 378240 +timestamp: 1750330740699 +- conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda +sha256: 895bbfe9ee25c98c922799de901387d842d7c01cae45c346879865c6a907f229 +md5: 0b6c506ec1f272b685240e70a29261b8 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- python >=3.12,<3.13.0a0 +- python_abi 3.12.* *_cp312 +license: Apache-2.0 +license_family: Apache +size: 410641 +timestamp: 1770909099497 +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda +sha256: feff959a816f7988a0893201aa9727bbb7ee1e9cec2c4f0428269b489eb93fb4 +md5: cbb88288f74dbe6ada1c6c7d0a97223e +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: 103560 +timestamp: 1778188657149 +- conda: https://conda.anaconda.org/conda-forge/linux-64/wget-1.25.0-h653f8fd_1.conda +sha256: 66a5a05e0e44fd7a57e24d77665d5d6672646a7b316575b2f679108966d9124e +md5: 3b97a15e7345c7f6c51bb57bffad7c93 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libidn2 >=2,<3.0a0 +- libunistring >=0,<1.0a0 +- libzlib >=1.3.1,<2.0a0 +- openssl >=3.5.5,<4.0a0 +- pcre2 >=10.47,<10.48.0a0 +- zlib +license: GPL-3.0-or-later +license_family: GPL +size: 746336 +timestamp: 1772232737502 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda +sha256: c12396aabb21244c212e488bbdc4abcdef0b7404b15761d9329f5a4a39113c4b +md5: fb901ff28063514abb6046c9ec2c4a45 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +license: MIT +license_family: MIT +size: 58628 +timestamp: 1734227592886 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda +sha256: 277841c43a39f738927145930ff963c5ce4c4dacf66637a3d95d802a64173250 +md5: 1c74ff8c35dcadf952a16f752ca5aa49 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- libuuid >=2.38.1,<3.0a0 +- xorg-libice >=1.1.2,<2.0a0 +license: MIT +license_family: MIT +size: 27590 +timestamp: 1741896361728 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.13-he1eb515_0.conda +sha256: 516d4060139dbb4de49a4dcdc6317a9353fb39ebd47789c14e6fe52de0deee42 +md5: 861fb6ccbc677bb9a9fb2468430b9c6a +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libxcb >=1.17.0,<2.0a0 +license: MIT +license_family: MIT +size: 839652 +timestamp: 1770819209719 +- 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/xorg-libxext-1.3.7-hb03c661_0.conda +sha256: 79c60fc6acfd3d713d6340d3b4e296836a0f8c51602327b32794625826bd052f +md5: 34e54f03dfea3e7a2dcf1453a85f1085 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- xorg-libx11 >=1.8.12,<2.0a0 +license: MIT +license_family: MIT +size: 50326 +timestamp: 1769445253162 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.2-hb03c661_0.conda +sha256: 83c4c99d60b8784a611351220452a0a85b080668188dce5dfa394b723d7b64f4 +md5: ba231da7fccf9ea1e768caf5c7099b84 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- xorg-libx11 >=1.8.12,<2.0a0 +license: MIT +license_family: MIT +size: 20071 +timestamp: 1759282564045 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.3-hb03c661_0.conda +sha256: 495f99c8eacfa4ae2d8fed2a7f2105777af89acdc204df145d2bbbc380ac631b +md5: adba2e334082bb218db806d4c12277c9 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- xorg-libx11 >=1.8.13,<2.0a0 +- xorg-libxext >=1.3.7,<2.0a0 +- xorg-libxfixes >=6.0.2,<7.0a0 +license: MIT +license_family: MIT +size: 47717 +timestamp: 1779111857071 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.5-hb03c661_0.conda +sha256: 80ed047a5cb30632c3dc5804c7716131d767089f65877813d4ae855ee5c9d343 +md5: e192019153591938acf7322b6459d36e +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- xorg-libx11 >=1.8.12,<2.0a0 +- xorg-libxext >=1.3.6,<2.0a0 +- xorg-libxrender >=0.9.12,<0.10.0a0 +license: MIT +license_family: MIT +size: 30456 +timestamp: 1769445263457 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda +sha256: 044c7b3153c224c6cedd4484dd91b389d2d7fd9c776ad0f4a34f099b3389f4a1 +md5: 96d57aba173e878a2089d5638016dc5e +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- xorg-libx11 >=1.8.10,<2.0a0 +license: MIT +license_family: MIT +size: 33005 +timestamp: 1734229037766 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.1-hb9d3cd8_0.conda +sha256: a8afba4a55b7b530eb5c8ad89737d60d60bc151a03fbef7a2182461256953f0e +md5: 279b0de5f6ba95457190a1c459a64e31 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- xorg-libice >=1.1.1,<2.0a0 +- xorg-libsm >=1.2.4,<2.0a0 +- xorg-libx11 >=1.8.10,<2.0a0 +license: MIT +license_family: MIT +size: 379686 +timestamp: 1731860547604 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda +sha256: 752fdaac5d58ed863bbf685bb6f98092fe1a488ea8ebb7ed7b606ccfce08637a +md5: 7bbe9a0cc0df0ac5f5a8ad6d6a11af2f +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- xorg-libx11 >=1.8.10,<2.0a0 +- xorg-libxext >=1.3.6,<2.0a0 +- xorg-libxi >=1.7.10,<2.0a0 +license: MIT +license_family: MIT +size: 32808 +timestamp: 1727964811275 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.8.3-ha02ee65_0.conda +sha256: 2553fd3ec0a1020b2ca05ca10b0036a596cb0d4bf3645922fcf69dacce0e6679 +md5: 6a1b6af49a334e4e06b9f103367762bf +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- liblzma 5.8.3 hb03c661_0 +- liblzma-devel 5.8.3 hb03c661_0 +- xz-gpl-tools 5.8.3 ha02ee65_0 +- xz-tools 5.8.3 hb03c661_0 +license: 0BSD AND LGPL-2.1-or-later AND GPL-2.0-or-later +size: 24360 +timestamp: 1775825568523 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xz-gpl-tools-5.8.3-ha02ee65_0.conda +sha256: 8f139666ea18dc8340a44a54056627dd4e89e242e8cd136ab2467d6dc2c192ba +md5: 8f5e2c6726c1339287a3c76a2c138ac7 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- liblzma 5.8.3 hb03c661_0 +constrains: +- xz 5.8.3.* +license: 0BSD AND LGPL-2.1-or-later AND GPL-2.0-or-later +size: 34213 +timestamp: 1775825548743 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xz-tools-5.8.3-hb03c661_0.conda +sha256: 162ebd76803464b8c8ebc7d45df32edf0ec717b3bf369a437ae3b0254f22dc2e +md5: b62b615caa60812640f24db3a8d0fc87 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- liblzma 5.8.3 hb03c661_0 +constrains: +- xz 5.8.3.* +license: 0BSD AND LGPL-2.1-or-later +size: 95955 +timestamp: 1775825530484 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_2.conda +sha256: 245c9ee8d688e23661b95e3c6dd7272ca936fabc03d423cdb3cdee1bbcf9f2f2 +md5: c2a01a08fc991620a74b32420e97868a +depends: +- __glibc >=2.17,<3.0.a0 +- libzlib 1.3.2 h25fd6f3_2 +license: Zlib +license_family: Other +size: 95931 +timestamp: 1774072620848 +- 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/busco/busco/environment.yml b/modules/nf-core/busco/busco/environment.yml new file mode 100644 index 00000000..21c7223a --- /dev/null +++ b/modules/nf-core/busco/busco/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::busco=6.1.0 diff --git a/modules/nf-core/busco/busco/main.nf b/modules/nf-core/busco/busco/main.nf new file mode 100644 index 00000000..2cd01c63 --- /dev/null +++ b/modules/nf-core/busco/busco/main.nf @@ -0,0 +1,132 @@ +process BUSCO_BUSCO { + tag "${meta.id}" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/96/963bad66c10646cf0adb1967cc462ad04d02789ddbfae4fbb94182291dbddf8c/data' + : 'community.wave.seqera.io/library/busco:6.1.0--6d1f7006d91892b3'}" + // Note: one test had to be disabled when switching to Busco 6.0.0, cf https://github.com/nf-core/modules/pull/8781/files + // Try to restore it when upgrading Busco to a later version + + input: + tuple val(meta), path(fasta, stageAs: 'tmp_input/*') + // Required: One of genome, proteins, or transcriptome + val mode + // Required: lineage for checking against, or "auto/auto_prok/auto_euk" for enabling auto-lineage + val lineage + // Recommended: BUSCO lineages file - downloads if not set + path busco_lineages_path + // Optional: BUSCO configuration file + path config_file + val clean_intermediates + + output: + tuple val(meta), path("*-busco.batch_summary.txt"), emit: batch_summary + tuple val(meta), path("*-busco.batch_summary.failed.txt"), emit: batch_summary_failed, optional: true + tuple val(meta), path("short_summary.*.txt"), emit: short_summaries_txt, optional: true + tuple val(meta), path("short_summary.*.json"), emit: short_summaries_json, optional: true + tuple val(meta), path("*-busco.log"), emit: log, optional: true + tuple val(meta), path("*-busco/*/run_*/full_table.tsv"), emit: full_table, optional: true + tuple val(meta), path("*-busco/*/run_*/missing_busco_list.tsv"), emit: missing_busco_list, optional: true + tuple val(meta), path("*-busco/*/run_*/single_copy_proteins.faa"), emit: single_copy_proteins, optional: true + tuple val(meta), path("*-busco/*/run_*/busco_sequences"), emit: seq_dir, optional: true + tuple val(meta), path("*-busco/*/translated_proteins"), emit: translated_dir, optional: true + tuple val(meta), path("*-busco"), emit: busco_dir + tuple val(meta), path("busco_downloads/lineages/*"), emit: downloaded_lineages, optional: true + tuple val(meta), path("*-busco/*/run_*/busco_sequences/single_copy_busco_sequences/*.faa"), emit: single_copy_faa, optional: true + tuple val(meta), path("*-busco/*/run_*/busco_sequences/single_copy_busco_sequences/*.fna"), emit: single_copy_fna, optional: true + tuple val("${task.process}"), val('busco'), eval("busco --version 2> /dev/null | sed 's/BUSCO //g'"), emit: versions_busco, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + if (mode !in ['genome', 'proteins', 'transcriptome']) { + error("Mode must be one of 'genome', 'proteins', or 'transcriptome'.") + } + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}-${lineage}" + def busco_config = config_file ? "--config ${config_file}" : '' + def busco_lineage = lineage in ['auto', 'auto_prok', 'auto_euk'] + ? lineage.replaceFirst('auto', '--auto-lineage').replaceAll('_', '-') + : "--lineage_dataset ${lineage}" + def busco_lineage_dir = busco_lineages_path ? "--download_path ${busco_lineages_path}" : '' + def intermediate_files = [ + './*-busco/*/auto_lineage', + './*-busco/*/**/{miniprot,hmmer,.bbtools}_output', + './*-busco/*/prodigal_output/predicted_genes/tmp/', + './*-busco/*/tmp/', + ] + def clean_cmd = clean_intermediates ? "rm -fr ${intermediate_files.join(' ')}" : '' + + def bbtools_memory_preferred = task.memory * 0.25 + def bbtools_memory_minimum = 120.Mb + def bbtools_memory = bbtools_memory_preferred > bbtools_memory_minimum ? "${bbtools_memory_preferred.toGiga()}g" : "${bbtools_memory_minimum.toMega()}m" + """ + export BUSCO_BBTOOLS_MEMORY=${bbtools_memory} + + # Fix Augustus for Apptainer + ENV_AUGUSTUS=/opt/conda/etc/conda/activate.d/augustus.sh + set +u + if [ -z "\${AUGUSTUS_CONFIG_PATH}" ] && [ -f "\${ENV_AUGUSTUS}" ]; then + source "\${ENV_AUGUSTUS}" + fi + set -u + + # If the augustus config directory is not writable, then copy to writeable area + if [ ! -w "\${AUGUSTUS_CONFIG_PATH}" ]; then + # Create writable tmp directory for augustus + AUG_CONF_DIR=\$( mktemp -d -p \$PWD ) + cp -r \$AUGUSTUS_CONFIG_PATH/* \$AUG_CONF_DIR + export AUGUSTUS_CONFIG_PATH=\$AUG_CONF_DIR + echo "New AUGUSTUS_CONFIG_PATH=\${AUGUSTUS_CONFIG_PATH}" + fi + + # Ensure the input is uncompressed + INPUT_SEQS=input_seqs + mkdir "\$INPUT_SEQS" + cd "\$INPUT_SEQS" + for FASTA in ../tmp_input/*; do + if [ "\${FASTA##*.}" == 'gz' ]; then + gzip -cdf "\$FASTA" > \$( basename "\$FASTA" .gz ) + else + ln -s "\$FASTA" . + fi + done + cd .. + + busco \\ + --cpu ${task.cpus} \\ + --in "\$INPUT_SEQS" \\ + --out ${prefix}-busco \\ + --mode ${mode} \\ + ${busco_lineage} \\ + ${busco_lineage_dir} \\ + ${busco_config} \\ + ${args} + + # clean up + rm -rf "\$INPUT_SEQS" + ${clean_cmd} + # find and remove broken symlinks from the cleanup + find . -xtype l -delete + + # Move files to avoid staging/publishing issues + grep -v 'Run failed; check logs' ${prefix}-busco/batch_summary.txt > ${prefix}-busco.batch_summary.txt + mv ${prefix}-busco/*/short_summary.*.{json,txt} . || echo "Short summaries were not available: No genes were found." + mv ${prefix}-busco/logs/busco.log ${prefix}-busco.log + + if grep -q 'Run failed; check logs' ${prefix}-busco/batch_summary.txt; then + grep 'Run failed; check logs' ${prefix}-busco/batch_summary.txt > ${prefix}-busco.batch_summary.failed.txt + fi + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}-${lineage}" + def fasta_name = files(fasta).first().name - '.gz' + """ + touch ${prefix}-busco.batch_summary.txt + mkdir -p ${prefix}-busco/${fasta_name}/run_${lineage}/busco_sequences + """ +} diff --git a/modules/nf-core/busco/busco/meta.yml b/modules/nf-core/busco/busco/meta.yml new file mode 100644 index 00000000..f7969637 --- /dev/null +++ b/modules/nf-core/busco/busco/meta.yml @@ -0,0 +1,248 @@ +name: busco_busco +description: Benchmarking Universal Single Copy Orthologs +keywords: + - quality control + - genome + - transcriptome + - proteome +tools: + - busco: + description: BUSCO provides measures for quantitative assessment of genome assembly, gene set, and transcriptome completeness based on evolutionarily informed expectations of gene content from near-universal single-copy orthologs selected from OrthoDB. + homepage: https://busco.ezlab.org/ + documentation: https://busco.ezlab.org/busco_userguide.html + tool_dev_url: https://gitlab.com/ezlab/busco + doi: "10.1007/978-1-4939-9173-0_14" + licence: + - "MIT" + identifier: biotools:busco +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - fasta: + type: file + description: Nucleic or amino acid sequence file in FASTA format. + pattern: "*.{fasta,fna,fa,fasta.gz,fna.gz,fa.gz}" + ontologies: [] + - mode: + type: string + description: The mode to run Busco in. One of genome, proteins, or transcriptome + pattern: "{genome,proteins,transcriptome}" + - lineage: + type: string + description: The BUSCO lineage to use, or "auto", "auto_prok" or "auto_euk" to automatically select lineage + - busco_lineages_path: + type: directory + description: Path to local BUSCO lineages directory. + - config_file: + type: file + description: Path to BUSCO config file. + ontologies: [] + - clean_intermediates: + type: boolean + description: Flag to remove intermediate files. +output: + batch_summary: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco.batch_summary.txt": + type: file + description: Summary of all sequence files analyzed + pattern: "*-busco.batch_summary.txt" + ontologies: [] + batch_summary_failed: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco.batch_summary.failed.txt": + type: file + description: Batch summary lines indicating BUSCO run failures + pattern: "*-busco.batch_summary.failed.txt" + ontologies: [] + short_summaries_txt: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - short_summary.*.txt: + type: file + description: Short Busco summary in plain text format + pattern: "short_summary.*.txt" + ontologies: [] + short_summaries_json: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - short_summary.*.json: + type: file + description: Short Busco summary in JSON format + pattern: "short_summary.*.json" + ontologies: + - edam: http://edamontology.org/format_3464 + log: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco.log": + type: file + description: BUSCO main log + pattern: "*-busco.log" + ontologies: [] + full_table: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco/*/run_*/full_table.tsv": + type: file + description: Full BUSCO results table + pattern: "full_table.tsv" + ontologies: + - edam: http://edamontology.org/format_3475 + missing_busco_list: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco/*/run_*/missing_busco_list.tsv": + type: file + description: List of missing BUSCOs + pattern: "missing_busco_list.tsv" + ontologies: + - edam: http://edamontology.org/format_3475 + single_copy_proteins: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco/*/run_*/single_copy_proteins.faa": + type: file + description: Fasta file of single copy proteins (transcriptome mode) + pattern: "single_copy_proteins.faa" + ontologies: [] + seq_dir: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco/*/run_*/busco_sequences": + type: directory + description: BUSCO sequence directory + pattern: "busco_sequences" + translated_dir: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco/*/translated_proteins": + type: directory + description: Six frame translations of each transcript made by the transcriptome mode + pattern: "translated_dir" + busco_dir: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco": + type: directory + description: BUSCO lineage specific output + pattern: "*-busco" + downloaded_lineages: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - busco_downloads/lineages/*: + type: directory + description: Lineages downloaded by BUSCO when running the analysis, for example bacteria_odb12 + pattern: "busco_downloads/lineages/*" + single_copy_faa: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco/*/run_*/busco_sequences/single_copy_busco_sequences/*.faa": + type: file + description: Single copy .faa sequence files + pattern: "*-busco/*/run_*/busco_sequences/single_copy_busco_sequences/*.faa" + ontologies: [] + single_copy_fna: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*-busco/*/run_*/busco_sequences/single_copy_busco_sequences/*.fna": + type: file + description: Single copy .fna sequence files + pattern: "*-busco/*/run_*/busco_sequences/single_copy_busco_sequences/*.fna" + ontologies: [] + versions_busco: + - - ${task.process}: + type: string + description: The name of the process + - busco: + type: string + description: The name of the tool + - busco --version 2> /dev/null | sed 's/BUSCO //g': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - busco: + type: string + description: The name of the tool + - busco --version 2> /dev/null | sed 's/BUSCO //g': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@priyanka-surana" + - "@charles-plessy" + - "@mahesh-panchal" + - "@muffato" + - "@jvhagey" + - "@gallvp" +maintainers: + - "@priyanka-surana" + - "@charles-plessy" + - "@mahesh-panchal" + - "@muffato" + - "@jvhagey" + - "@gallvp" +containers: + docker: + linux/amd64: + name: community.wave.seqera.io/library/busco:6.1.0--6d1f7006d91892b3 + build_id: bd-6d1f7006d91892b3_1 + scan_id: sc-7ee408324c396471_1 + singularity: + linux/amd64: + name: oras://community.wave.seqera.io/library/busco:6.1.0--c7528d5825eb19b5 + build_id: bd-c7528d5825eb19b5_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/96/963bad66c10646cf0adb1967cc462ad04d02789ddbfae4fbb94182291dbddf8c/data + conda: + linux/amd64: + lock_file: modules/nf-core/busco/busco/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt diff --git a/modules/nf-core/busco/busco/tests/main.nf.test b/modules/nf-core/busco/busco/tests/main.nf.test new file mode 100644 index 00000000..3f1ad0d0 --- /dev/null +++ b/modules/nf-core/busco/busco/tests/main.nf.test @@ -0,0 +1,422 @@ +nextflow_process { + + name "Test Process BUSCO_BUSCO" + script "../main.nf" + process "BUSCO_BUSCO" + + tag "modules" + tag "modules_nfcore" + tag "busco" + tag "busco/busco" + + test("test_busco_genome_single_fasta") { + + config './nextflow.config' + + when { + params { + busco_args = '--tar' + } + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ] + input[1] = 'genome' + input[2] = 'bacteria_odb10' // Launch with 'auto' to use --auto-lineage, and specified lineages // 'auto' removed from test due to memory issues + input[3] = [] // Download busco lineage + input[4] = [] // No config + input[5] = false // Clean intermediates + """ + } + } + + then { + assert process.success + + with(path(process.out.short_summaries_txt[0][1]).text) { + assert contains('BUSCO version') + assert contains('The lineage dataset is') + assert contains('BUSCO was run in mode') + assert contains('Complete BUSCOs') + assert contains('Missing BUSCOs') + assert contains('Dependencies and versions') + } + + with(path(process.out.short_summaries_json[0][1]).text) { + assert contains('one_line_summary') + assert contains('mode') + assert contains('dataset') + } + + assert snapshot( + process.out.batch_summary[0][1], + process.out.full_table[0][1], + process.out.missing_busco_list[0][1], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() + + with(file(process.out.seq_dir[0][1]).listFiles().collect { it.name }) { + assert contains('single_copy_busco_sequences.tar.gz') + assert contains('multi_copy_busco_sequences.tar.gz') + assert contains('fragmented_busco_sequences.tar.gz') + } + + with(path(process.out.log[0][1]).text) { + assert contains('DEBUG:busco.run_BUSCO') + assert contains('Results from dataset') + assert contains('how to cite BUSCO') + } + + assert process.out.single_copy_proteins == [] + assert process.out.translated_dir == [] + } + } + + test("test_busco_genome_multi_fasta") { + + config './nextflow.config' + + when { + params { + busco_args = '--tar' + } + process { + """ + input[0] = [ + [ id:'test' ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/prokaryotes/candidatus_portiera_aleyrodidarum/genome/genome.fasta', checkIfExists: true) + ] + ] + input[1] = 'genome' + input[2] = 'bacteria_odb10' + input[3] = [] + input[4] = [] + input[5] = false + """ + } + } + + then { + assert process.success + + with(path(process.out.short_summaries_txt[0][1][0]).text) { + assert contains('BUSCO version') + assert contains('The lineage dataset is') + assert contains('BUSCO was run in mode') + assert contains('Complete BUSCOs') + assert contains('Missing BUSCOs') + assert contains('Dependencies and versions') + } + + with(path(process.out.short_summaries_txt[0][1][1]).text) { + assert contains('BUSCO version') + assert contains('The lineage dataset is') + assert contains('BUSCO was run in mode') + assert contains('Complete BUSCOs') + assert contains('Missing BUSCOs') + assert contains('Dependencies and versions') + } + + with(path(process.out.short_summaries_json[0][1][0]).text) { + assert contains('one_line_summary') + assert contains('mode') + assert contains('dataset') + } + + with(path(process.out.short_summaries_json[0][1][1]).text) { + assert contains('one_line_summary') + assert contains('mode') + assert contains('dataset') + } + + assert snapshot( + process.out.full_table[0][1], + process.out.missing_busco_list[0][1], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() + + with(file(process.out.seq_dir[0][1][0]).listFiles().collect { it.name }) { + assert contains('single_copy_busco_sequences.tar.gz') + assert contains('multi_copy_busco_sequences.tar.gz') + assert contains('fragmented_busco_sequences.tar.gz') + } + + with(file(process.out.seq_dir[0][1][1]).listFiles().collect { it.name }) { + assert contains('single_copy_busco_sequences.tar.gz') + assert contains('multi_copy_busco_sequences.tar.gz') + assert contains('fragmented_busco_sequences.tar.gz') + } + + with(path(process.out.log[0][1]).text) { + assert contains('DEBUG:busco.run_BUSCO') + assert contains('Results from dataset') + assert contains('how to cite BUSCO') + } + + assert process.out.single_copy_proteins == [] + assert process.out.translated_dir == [] + } + + } + + + test("test_busco_eukaryote_augustus") { + + config './nextflow.config' + + when { + params { + busco_args = '--tar --augustus' + } + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ] + input[1] = 'genome' + input[2] = 'eukaryota_odb10' + input[3] = [] + input[4] = [] + input[5] = false + """ + } + } + + then { + assert process.success + + assert snapshot( + process.out.batch_summary[0][1], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() + + with(path(process.out.log[0][1]).text) { + assert contains('DEBUG:busco.run_BUSCO') + assert contains('Augustus did not recognize any genes') + + } + + assert process.out.short_summaries_json == [] + assert process.out.short_summaries_txt == [] + assert process.out.missing_busco_list == [] + assert process.out.full_table == [] + assert process.out.single_copy_proteins == [] + assert process.out.translated_dir == [] + } + + } + + test("test_busco_protein") { + + config './nextflow.config' + + when { + params { + busco_args = '--tar' + } + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/prokaryotes/candidatus_portiera_aleyrodidarum/genome/proteome.fasta', checkIfExists: true) + ] + input[1] = 'proteins' + input[2] = 'bacteria_odb10' + input[3] = [] + input[4] = [] + input[5] = false + """ + } + } + + then { + assert process.success + + with(path(process.out.short_summaries_txt[0][1]).text) { + assert contains('BUSCO version') + assert contains('The lineage dataset is') + assert contains('BUSCO was run in mode') + assert contains('Complete BUSCOs') + assert contains('Missing BUSCOs') + assert contains('Dependencies and versions') + } + + with(path(process.out.short_summaries_json[0][1]).text) { + assert contains('one_line_summary') + assert contains('mode') + assert contains('dataset') + } + + assert snapshot( + process.out.batch_summary[0][1], + process.out.full_table[0][1], + process.out.missing_busco_list[0][1], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() + + with(file(process.out.seq_dir[0][1]).listFiles().collect { it.name }) { + assert contains('single_copy_busco_sequences.tar.gz') + assert contains('multi_copy_busco_sequences.tar.gz') + assert contains('fragmented_busco_sequences.tar.gz') + } + + with(path(process.out.log[0][1]).text) { + assert contains('DEBUG:busco.run_BUSCO') + assert contains('Results from dataset') + assert contains('how to cite BUSCO') + } + + assert process.out.single_copy_proteins == [] + assert process.out.translated_dir == [] + } + + } + + test("test_busco_transcriptome") { + + config './nextflow.config' + + when { + params { + busco_args = '--tar' + } + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/illumina/fasta/test1.contigs.fa.gz', checkIfExists: true) + ] + input[1] = 'transcriptome' + input[2] = 'bacteria_odb10' + input[3] = [] + input[4] = [] + input[5] = false + """ + } + } + + then { + assert process.success + + with(path(process.out.short_summaries_txt[0][1]).text) { + assert contains('BUSCO version') + assert contains('The lineage dataset is') + assert contains('BUSCO was run in mode') + assert contains('Complete BUSCOs') + assert contains('Missing BUSCOs') + assert contains('Dependencies and versions') + } + + with(path(process.out.short_summaries_json[0][1]).text) { + assert contains('one_line_summary') + assert contains('mode') + assert contains('dataset') + } + + assert snapshot( + process.out.batch_summary[0][1], + process.out.full_table[0][1], + process.out.missing_busco_list[0][1], + process.out.translated_dir[0][1], + process.out.single_copy_proteins[0][1], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() + + with(file(process.out.seq_dir[0][1]).listFiles().collect { it.name }) { + assert contains('single_copy_busco_sequences.tar.gz') + assert contains('multi_copy_busco_sequences.tar.gz') + assert contains('fragmented_busco_sequences.tar.gz') + } + + with(path(process.out.log[0][1]).text) { + assert contains('DEBUG:busco.run_BUSCO') + assert contains('Results from dataset') + assert contains('how to cite BUSCO') + } + } + + } + + test("test_busco_cleanup") { + + config './nextflow.config' + + when { + params { + busco_args = '--tar' + } + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ] + input[1] = 'genome' + input[2] = 'bacteria_odb10' + input[3] = [] + input[4] = [] + input[5] = true + """ + } + } + + then { + assert process.success + + assert snapshot( + process.out.batch_summary[0][1], + process.out.full_table[0][1], + process.out.missing_busco_list[0][1], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() + + with(path(process.out.log[0][1]).text) { + assert contains('DEBUG:busco.run_BUSCO') + assert contains('Results from dataset') + assert contains('how to cite BUSCO') + } + + assert path("${process.out.busco_dir[0][1]}/*/auto_lineage").exists() == false + assert path("${process.out.busco_dir[0][1]}/*/**/{miniprot,hmmer,.bbtools}_output").exists() == false + + assert process.out.single_copy_proteins == [] + assert process.out.translated_dir == [] + } + } + + test("minimal-stub") { + + options '-stub' + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ] + input[1] = 'genome' + input[2] = 'bacteria_odb10' + input[3] = [] + input[4] = [] + input[5] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.batch_summary, + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() } + ) + } + } +} diff --git a/modules/nf-core/busco/busco/tests/main.nf.test.snap b/modules/nf-core/busco/busco/tests/main.nf.test.snap new file mode 100644 index 00000000..ff72464f --- /dev/null +++ b/modules/nf-core/busco/busco/tests/main.nf.test.snap @@ -0,0 +1,182 @@ +{ + "minimal-stub": { + "content": [ + [ + [ + { + "id": "test" + }, + "test-bacteria_odb10-busco.batch_summary.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + { + "versions_busco": [ + [ + "BUSCO_BUSCO", + "busco", + "6.1.0" + ] + ] + } + ], + "timestamp": "2026-06-08T11:11:55.813665798", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "test_busco_eukaryote_augustus": { + "content": [ + "test-eukaryota_odb10-busco.batch_summary.txt:md5,3ea3bdc423a461dae514d816bdc61c89", + { + "versions_busco": [ + [ + "BUSCO_BUSCO", + "busco", + "6.1.0" + ] + ] + } + ], + "timestamp": "2026-06-08T11:10:25.880669484", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "test_busco_genome_single_fasta": { + "content": [ + "test-bacteria_odb10-busco.batch_summary.txt:md5,12e911830d66bab6dbf3523ac4392597", + "full_table.tsv:md5,327aa7603dca43e7c4adf85f89a85e8e", + "missing_busco_list.tsv:md5,268d346a92e1297999d96c98a6e7c260", + { + "versions_busco": [ + [ + "BUSCO_BUSCO", + "busco", + "6.1.0" + ] + ] + } + ], + "timestamp": "2026-06-08T11:08:58.703644026", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "test_busco_genome_multi_fasta": { + "content": [ + [ + "full_table.tsv:md5,223cff423706f07a121f53115bcd6d69", + "full_table.tsv:md5,327aa7603dca43e7c4adf85f89a85e8e" + ], + [ + "missing_busco_list.tsv:md5,9a8eb41928d1c21677b9d38abaf2e790", + "missing_busco_list.tsv:md5,268d346a92e1297999d96c98a6e7c260" + ], + { + "versions_busco": [ + [ + "BUSCO_BUSCO", + "busco", + "6.1.0" + ] + ] + } + ], + "timestamp": "2026-06-08T11:09:46.527087612", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "test_busco_cleanup": { + "content": [ + "test-bacteria_odb10-busco.batch_summary.txt:md5,12e911830d66bab6dbf3523ac4392597", + "full_table.tsv:md5,327aa7603dca43e7c4adf85f89a85e8e", + "missing_busco_list.tsv:md5,268d346a92e1297999d96c98a6e7c260", + { + "versions_busco": [ + [ + "BUSCO_BUSCO", + "busco", + "6.1.0" + ] + ] + } + ], + "timestamp": "2026-06-08T11:11:47.192817683", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "test_busco_transcriptome": { + "content": [ + "test-bacteria_odb10-busco.batch_summary.txt:md5,8734b3f379c4c0928e5dd4ea1873dc64", + "full_table.tsv:md5,e9ab16f5dfe319d30828186658c5d02a", + "missing_busco_list.tsv:md5,5d5bbb10940f6cf862c0f4c979980a21", + [ + "1024388at2.faa:md5,797d603d262a6595a112e25b73e878b0", + "1054741at2.faa:md5,cd4b928cba6b19b4437746ba507e7195", + "1093223at2.faa:md5,df9549708e5ffcfaee6a74dd70a0e5dc", + "1151822at2.faa:md5,12726afc1cdc40c13392e1596e93df3a", + "143460at2.faa:md5,d887431fd988a5556a523440f02d9594", + "1491686at2.faa:md5,d03362d19979b27306c192f1c74a84e5", + "1504821at2.faa:md5,4f5f6e5c57bac0092c1d85ded73d7e67", + "1574817at2.faa:md5,1153e55998c2929eacad2aed7d08d248", + "1592033at2.faa:md5,bb7a59e5f3a57ba12d10dabf4c77ab57", + "1623045at2.faa:md5,8fe38155feb1802beb97ef7714837bf5", + "1661836at2.faa:md5,6c6d592c2fbb0d7a4e5e1f47a15644f0", + "1674344at2.faa:md5,bb41b44e53565a54cadf0b780532fe08", + "1698718at2.faa:md5,f233860000028eb00329aa85236c71e5", + "1990650at2.faa:md5,34a2d29c5f8b6253159ddb7a43fa1829", + "223233at2.faa:md5,dec6705c7846c989296e73942f953cbc", + "402899at2.faa:md5,acc0f271f9a586d2ce1ee41669b22999", + "505485at2.faa:md5,aa0391f8fa5d9bd19b30d844d5a99845", + "665824at2.faa:md5,47f8ad43b6a6078206feb48c2e552793", + "776861at2.faa:md5,f8b90c13f7c6be828dea3bb920195e3d", + "874197at2.faa:md5,8d22a35a768debe6f376fc695d233a69", + "932854at2.faa:md5,2eff2de1ab83b22f3234a529a44e22bb", + "95696at2.faa:md5,247bfd1aef432f7b5456307768e9149c" + ], + "single_copy_proteins.faa:md5,73e2c5d6a9b0f01f2deea3cc5f21b764", + { + "versions_busco": [ + [ + "BUSCO_BUSCO", + "busco", + "6.1.0" + ] + ] + } + ], + "timestamp": "2026-06-08T11:11:06.934053195", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "test_busco_protein": { + "content": [ + "test-bacteria_odb10-busco.batch_summary.txt:md5,942dbb2d8ff26240860a794213db14a8", + "full_table.tsv:md5,6cea99feda083a56bf8eb6d9bd19f4be", + "missing_busco_list.tsv:md5,9a8eb41928d1c21677b9d38abaf2e790", + { + "versions_busco": [ + [ + "BUSCO_BUSCO", + "busco", + "6.1.0" + ] + ] + } + ], + "timestamp": "2026-06-08T11:10:44.297381698", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/busco/busco/tests/nextflow.config b/modules/nf-core/busco/busco/tests/nextflow.config new file mode 100644 index 00000000..db73a7ee --- /dev/null +++ b/modules/nf-core/busco/busco/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: 'BUSCO_BUSCO' { + ext.args = params.busco_args + } +} diff --git a/subworkflows/local/rna_detection/main.nf b/subworkflows/local/rna_detection/main.nf index 0cac5bb8..22b2a996 100644 --- a/subworkflows/local/rna_detection/main.nf +++ b/subworkflows/local/rna_detection/main.nf @@ -27,7 +27,7 @@ workflow RNA_DETECTION { main: BARRNAP( - fasta.map {id, fasta_file -> [id, fasta_file, "bac"]} + fasta.map {meta, fasta_file -> [meta, fasta_file, meta.domain]} ) TRNASCANSE( diff --git a/subworkflows/local/rna_detection/meta.yml b/subworkflows/local/rna_detection/meta.yml index 84902bab..6f7f06a3 100644 --- a/subworkflows/local/rna_detection/meta.yml +++ b/subworkflows/local/rna_detection/meta.yml @@ -3,6 +3,7 @@ name: "rna_detection" description: | Detects tRNA and rRNA genes in genome FASTA files using tRNAscan-SE and Barrnap, then evaluates whether the genome meets MIMAG RNA completeness standards. + Prediction mode and required rRNA genes depend on the genome's domain (meta.domain). keywords: - rna - trna @@ -14,33 +15,39 @@ keywords: components: - barrnap - trnascanse - - countrna + - count_rna input: - fasta: type: file description: | Channel containing genome FASTA files. + meta.domain must be one of 'bac', 'arc' or 'euk'. It sets the Barrnap kingdom, + the tRNAscan-SE search mode (-B/-A/-E, via conf/modules.config) and the rRNA genes + required by COUNT_RNA. Structure: [ val(meta), path(fasta) ] + e.g. [ [ id:'test', domain:'bac' ], genome.fasta ] pattern: "*.{fa,fasta,fna,fa.gz,fasta.gz,fna.gz}" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA - min_trna_count: type: integer description: | - Minimum number of distinct tRNA types required to pass the MIMAG standard (e.g. 18). + Minimum total number of tRNA genes for the 20 standard amino acids required + to pass the MIMAG standard (e.g. 18). - min_rrna_percentage: type: float description: | - Minimum percentage of the three rRNA genes (5S, 16S, 23S) required to pass - the MIMAG standard (e.g. 75.0). + Minimum percentage of expected gene length that must be recovered for each + required rRNA gene to count it as present (e.g. 80). + Required genes: 16S, 23S and 5S for 'bac'/'arc'; 18S, 28S, 5.8S and 5S for 'euk'. output: - rna_detected: type: file description: | - Channel containing per-genome TSV files with tRNA/rRNA counts and a - MIMAG pass/fail decision. + Channel containing per-genome TSV files with one line: genome ID and + RNA presence decision (True/False). Structure: [ val(meta), path(tsv) ] - pattern: "*.tsv" + pattern: "*_rna_decision.tsv" ontologies: - edam: "http://edamontology.org/format_3475" # TSV authors: diff --git a/subworkflows/local/rna_detection/tests/main.nf.test b/subworkflows/local/rna_detection/tests/main.nf.test new file mode 100644 index 00000000..dbe844c1 --- /dev/null +++ b/subworkflows/local/rna_detection/tests/main.nf.test @@ -0,0 +1,132 @@ +nextflow_workflow { + + name "Test Subworkflow RNA_DETECTION" + script "../main.nf" + workflow "RNA_DETECTION" + + tag "subworkflows" + tag "subworkflows_local" + tag "subworkflows/rna_detection" + tag "barrnap" + tag "trnascanse" + tag "count_rna" + + test("bacteroides_fragilis - bac") { + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_bac', domain:'bac' ], + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ]) + input[1] = 18 + input[2] = 80 + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.rna_detected).match() }, + { assert workflow.out.rna_detected.size() == 1 }, + // complete bacterial isolate genome - all rRNA genes and enough tRNAs are expected + { assert path(workflow.out.rna_detected[0][1]).text.contains("True") } + ) + } + + } + + test("homo_sapiens - euk") { + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_euk', domain:'euk' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = 18 + input[2] = 80 + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.rna_detected).match() }, + { assert workflow.out.rna_detected.size() == 1 }, + // small chromosome fragment - eukaryotic rRNA set is not expected to be complete + { assert path(workflow.out.rna_detected[0][1]).text.contains("False") } + ) + } + + } + + test("multiple genomes - mixed domains") { + + when { + workflow { + """ + input[0] = channel.of( + [ + [ id:'test_bac', domain:'bac' ], + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ], + [ + [ id:'test_euk', domain:'euk' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ] + ) + input[1] = 18 + input[2] = 80 + """ + } + } + + then { + assert workflow.success + // TRNASCANSE and BARRNAP outputs are joined by meta - each genome must get exactly one decision + def decisions = workflow.out.rna_detected + .collectEntries { meta, tsv -> [ (meta.id): path(tsv).text ] } + assertAll( + { assert snapshot(workflow.out.rna_detected.sort { it[0].id }).match() }, + { assert workflow.out.rna_detected.size() == 2 }, + { assert decisions.keySet() == ['test_bac', 'test_euk'] as Set }, + { assert decisions['test_bac'].contains("True") }, + { assert decisions['test_euk'].contains("False") } + ) + } + + } + + test("bacteroides_fragilis - bac - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_bac', domain:'bac' ], + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ]) + input[1] = 18 + input[2] = 80 + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.rna_detected).match() }, + { assert workflow.out.rna_detected.size() == 1 } + ) + } + + } + +} diff --git a/subworkflows/local/rna_detection/tests/main.nf.test.snap b/subworkflows/local/rna_detection/tests/main.nf.test.snap new file mode 100644 index 00000000..05bad786 --- /dev/null +++ b/subworkflows/local/rna_detection/tests/main.nf.test.snap @@ -0,0 +1,81 @@ +{ + "bacteroides_fragilis - bac - stub": { + "content": [ + [ + [ + { + "id": "test_bac", + "domain": "bac" + }, + "test_bac_rna_decision.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "timestamp": "2026-10-14T15:01:52.546789", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + }, + "homo_sapiens - euk": { + "content": [ + [ + [ + { + "id": "test_euk", + "domain": "euk" + }, + "test_euk_rna_decision.tsv:md5,70447fb76ec179475ad2f4eca8ef9892" + ] + ] + ], + "timestamp": "2026-10-14T14:55:50.441162", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + }, + "multiple genomes - mixed domains": { + "content": [ + [ + [ + { + "id": "test_bac", + "domain": "bac" + }, + "test_bac_rna_decision.tsv:md5,99228ffd59107b1168a98f5c69d4e3e3" + ], + [ + { + "id": "test_euk", + "domain": "euk" + }, + "test_euk_rna_decision.tsv:md5,70447fb76ec179475ad2f4eca8ef9892" + ] + ] + ], + "timestamp": "2026-10-14T16:46:52.104684", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + }, + "bacteroides_fragilis - bac": { + "content": [ + [ + [ + { + "id": "test_bac", + "domain": "bac" + }, + "test_bac_rna_decision.tsv:md5,99228ffd59107b1168a98f5c69d4e3e3" + ] + ] + ], + "timestamp": "2026-10-14T16:40:41.699153", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + } +} \ No newline at end of file diff --git a/workflows/genomesubmit.nf b/workflows/genomesubmit.nf index 37ce9555..71bc6d3e 100644 --- a/workflows/genomesubmit.nf +++ b/workflows/genomesubmit.nf @@ -110,8 +110,63 @@ workflow GENOMESUBMIT { } .mix(branched_coverage_results.genome_coverage_present) + // --------- Taxonomy + branched_taxonomy_results = fasta_updated_with_coverage + .branch { meta, _fasta -> + genome_taxonomy_input: !(meta.NCBI_lineage) + taxonomy_present: true // Everything else goes here + } + + // Change extension for all files required taxonomy to .fasta because CATPACK requires suffix as input + RENAME_FASTA_FOR_CATPACK ( + branched_taxonomy_results.genome_taxonomy_input + ) + + // build input structures for CAT_DB depending on what provided as input + def cat_db_input = cat_db + ? channel.of( [['id': 'CAT_DB'], file(cat_db)] ) + : channel.empty() + + cat_db_download_id = "nr" // NCBI non-redundant protein database identifier + def cat_db_id_input = cat_db + ? channel.empty() + : channel.of( [['id': 'CAT_DB_id'], cat_db_download_id] ) + + FASTA_CLASSIFY_CATPACK ( + RENAME_FASTA_FOR_CATPACK.out.renamed_fasta, // ch_bins + channel.empty(), // ch_contigs - empty because we classify bins, not contigs + cat_db_input, + cat_db_id_input, + false, // disable summary generation + '.fasta' // bin_suffix - the suffix of the renamed fasta files + ) + + fasta_updated_with_taxonomy = FASTA_CLASSIFY_CATPACK.out.bat_classification + .join(branched_taxonomy_results.genome_taxonomy_input) + .map { meta, taxa_tsv, fasta -> + def lines = taxa_tsv.readLines() + def updated_meta = meta.clone() + // support for empty taxonomy files required for -stub mode + updated_meta.NCBI_lineage = lines ? lines[1].split('\t')[3] : null + return [updated_meta, fasta] + } + .mix(branched_taxonomy_results.taxonomy_present) + + // --------- Split data to eukaryotes (euk) and prokaryotes (bac and arc) + domain_identification = fasta_updated_with_taxonomy + .map { meta, fasta -> + def lineage = meta.NCBI_lineage + def parts = lineage.tokenize(';').collect { p -> p.trim() } + def is_euk = lineage.contains('ukaryot') || parts.contains('2759') + def is_arc = lineage.contains('rchaea') || parts.contains('2157') + + [ meta + [domain: is_euk ? 'euk' : (is_arc ? 'arc' : 'bac')], fasta ] + } + + domain_identification.view() + // --------- For genomes without RNA_presence info, calculate rRNA and tRNA - branched_rna_results = fasta_updated_with_coverage + branched_rna_results = domain_identification .branch { meta, _fasta -> rna_prediction_input: meta.RNA_presence == null // it might be True/False rna_present: true // Everything else goes here @@ -167,51 +222,10 @@ workflow GENOMESUBMIT { } .mix(branched_stats_results.evaluation_present) - // --------- Taxonomy - branched_taxonomy_results = fasta_updated_with_stats - .branch { meta, _fasta -> - genome_taxonomy_input: !(meta.NCBI_lineage) - taxonomy_present: true // Everything else goes here - } - - // Change extension for all files required taxonomy to .fasta because CATPACK requires suffix as input - RENAME_FASTA_FOR_CATPACK ( - branched_taxonomy_results.genome_taxonomy_input - ) - - // build input structures for CAT_DB depending on what provided as input - def cat_db_input = cat_db - ? channel.of( [['id': 'CAT_DB'], file(cat_db)] ) - : channel.empty() - - cat_db_download_id = "nr" // NCBI non-redundant protein database identifier - def cat_db_id_input = cat_db - ? channel.empty() - : channel.of( [['id': 'CAT_DB_id'], cat_db_download_id] ) - - FASTA_CLASSIFY_CATPACK ( - RENAME_FASTA_FOR_CATPACK.out.renamed_fasta, // ch_bins - channel.empty(), // ch_contigs - empty because we classify bins, not contigs - cat_db_input, - cat_db_id_input, - false, // disable summary generation - '.fasta' // bin_suffix - the suffix of the renamed fasta files - ) - - fasta_updated_with_taxonomy = FASTA_CLASSIFY_CATPACK.out.bat_classification - .join(branched_taxonomy_results.genome_taxonomy_input) - .map { meta, taxa_tsv, fasta -> - def lines = taxa_tsv.readLines() - def updated_meta = meta.clone() - // support for empty taxonomy files required for -stub mode - updated_meta.NCBI_lineage = lines ? lines[1].split('\t')[3] : null - return [updated_meta, fasta] - } - .mix(branched_taxonomy_results.taxonomy_present) // --------- Combine metadata into TSV using module CREATE_GENOME_METADATA_TSV ( - fasta_updated_with_taxonomy + fasta_updated_with_stats ) // Collect all TSV rows into a single file From 5d912a64ddafe03a205371d2a14e3fa60da728c2 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Wed, 14 Oct 2026 20:07:50 +0100 Subject: [PATCH 02/24] rm eukcc --- conf/modules.config | 4 -- modules/local/eukcc/binlinks/environment.yml | 0 modules/local/eukcc/binlinks/main.nf | 76 -------------------- modules/local/eukcc/folder/environment.yml | 7 -- modules/local/eukcc/folder/main.nf | 70 ------------------ 5 files changed, 157 deletions(-) delete mode 100644 modules/local/eukcc/binlinks/environment.yml delete mode 100644 modules/local/eukcc/binlinks/main.nf delete mode 100644 modules/local/eukcc/folder/environment.yml delete mode 100644 modules/local/eukcc/folder/main.nf diff --git a/conf/modules.config b/conf/modules.config index d9525adf..55db510d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -95,10 +95,6 @@ process { ] } - withName: 'EUKCC_FOLDER' { - ext.args = '--improve_percent 10 --n_combine 1 --improve_ratio 5 --min_links 100 --suffix .fa' - } - withName: 'COUNT_RNA' { publishDir = [ enabled: false diff --git a/modules/local/eukcc/binlinks/environment.yml b/modules/local/eukcc/binlinks/environment.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/modules/local/eukcc/binlinks/main.nf b/modules/local/eukcc/binlinks/main.nf deleted file mode 100644 index 27418b60..00000000 --- a/modules/local/eukcc/binlinks/main.nf +++ /dev/null @@ -1,76 +0,0 @@ -process EUKCC_LINKTABLE { - - /* - This module aligns reads to the reference using specified arguments - and produces output in the form of FASTQ.GZ, BAM and BAM.BAI files. - It also runs: - - eukcc linktable - */ - - label 'process_medium' - tag "${meta.id}" - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://community.wave.seqera.io/library/eukcc:2.2.0--050b7bea3f69b4a8': - 'community.wave.seqera.io/library/bwa-mem2_eukcc_samtools:5bd64ce41bca11bf' }" - - input: - tuple val(meta), path(reads), path(ref_fasta), path(bins), path(depth) - - output: - tuple val(meta), path("*.links.csv"), emit: links_table - tuple val(meta), path("*.idxstats") , emit: idxstats - path "versions.yml" , emit: versions - - script: - def prefix = task.ext.prefix ?: "${meta.id}" - def samtools_args = task.ext.alignment_args - - """ - mkdir -p output - - echo " ---> index fasta" - bwa-mem2 index ${ref_fasta} - - echo " ---> mapping files to assembly" - bwa-mem2 mem -M \ - -t ${task.cpus} \ - ${ref_fasta} \ - ${reads} | \ - samtools view -@ ${task.cpus} ${samtools_args} - | \ - samtools sort -@ ${task.cpus} -O bam - -o output/${meta.id}_sorted.bam - - echo "samtools index sorted bam" - samtools index -@ ${task.cpus} output/${meta.id}_sorted.bam - - echo " ---> samtools idxstats sorted bam" - samtools idxstats --threads ${task.cpus} output/${meta.id}_sorted.bam > ${prefix}.idxstats - - echo "linktable" - mkdir -p bins - cp ${bins}/* bins/ - - export BINS=\$(ls bins | grep -v "unbinned" | wc -l) - if [ \$BINS -eq 0 ]; then - echo "Bins directory is empty" - touch ${meta.id}.links.csv - else - ggp_binlinks.py --ANI 99 \ - --within 1500 \ - --out ${meta.id}.links.csv \ - --debug \ - --bindir bins \ - --bam output/${meta.id}_sorted.bam - fi - - rm -rf output - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bwa-mem2: \$(bwa-mem2 version 2> /dev/null) - biopython: \$(python3 -c "import pkg_resources; print(pkg_resources.get_distribution('biopython').version)") - pysam: \$(python3 -c "import pkg_resources; print(pkg_resources.get_distribution('pysam').version)") - END_VERSIONS - """ -} \ No newline at end of file diff --git a/modules/local/eukcc/folder/environment.yml b/modules/local/eukcc/folder/environment.yml deleted file mode 100644 index 15d04b42..00000000 --- a/modules/local/eukcc/folder/environment.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json -channels: - - conda-forge - - bioconda -dependencies: - - "bioconda::eukcc=2.2.0" diff --git a/modules/local/eukcc/folder/main.nf b/modules/local/eukcc/folder/main.nf deleted file mode 100644 index 605f4272..00000000 --- a/modules/local/eukcc/folder/main.nf +++ /dev/null @@ -1,70 +0,0 @@ -process EUKCC_FOLDER { - tag "${meta.id}" - label 'process_medium' - label 'process_long' - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? - 'oras://community.wave.seqera.io/library/eukcc:2.2.0--050b7bea3f69b4a8': - 'community.wave.seqera.io/library/eukcc:2.2.0--212dfaba26f5edd2' }" - - input: - tuple val(meta), path(links), path(bins, stageAs: 'bins/*') - tuple val(meta2), path(db) - - output: - tuple val(meta), path("${prefix}_results/merged_bins"), emit: merged_bins - tuple val(meta), path("${prefix}.eukcc.csv") , emit: csv - tuple val(meta), path("${prefix}.merged_bins.csv") , emit: merged_csv - tuple val("${task.process}"), val('eukcc'), eval('eukcc -v 2>&1 | grep -oE "[0-9]+\\.[0-9]+\\.[0-9]+" | head -n1'), emit: versions_eukcc, topic: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - prefix = task.ext.prefix ?: "${meta.id}" - def links_arg = links ? "--links ${links}" : '' - """ - mkdir -p bins ${prefix}_results/merged_bins - - if [ -z "\$(ls -A bins)" ]; then - echo "No bins in input" >&2 - touch ${prefix}.eukcc.csv ${prefix}.merged_bins.csv - else - set +e - eukcc folder \\ - ${args} \\ - --threads ${task.cpus} \\ - ${links_arg} \\ - --db ${db} \\ - --out ${prefix}_results \\ - --prefix ${prefix}_merged. \\ - bins - exit_code=\$? - set -e - - case \$exit_code in - 0) - mv ${prefix}_results/eukcc.csv ${prefix}.eukcc.csv - mv ${prefix}_results/merged_bins.csv ${prefix}.merged_bins.csv - ;; - 204) - # EukCC exits with 204 when MetaEuk predicts zero proteins - echo "MetaEuk returned zero proteins" >&2 - touch ${prefix}.eukcc.csv ${prefix}.merged_bins.csv - ;; - *) - exit \$exit_code - ;; - esac - fi - """ - - stub: - prefix = task.ext.prefix ?: "${meta.id}" - """ - mkdir -p ${prefix}_results/merged_bins - touch ${prefix}.eukcc.csv ${prefix}.merged_bins.csv - """ -} From 8258791049808788b917cba836e45d2272868d13 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Thu, 15 Oct 2026 10:52:43 +0100 Subject: [PATCH 03/24] wip --- conf/modules.config | 19 ++++++++++++++ nextflow.config | 8 +++++- nextflow_schema.json | 26 ++++++++++++++++++++ subworkflows/local/genome_evaluation/main.nf | 3 +++ workflows/genomesubmit.nf | 4 +-- 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 55db510d..f3a5608e 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -105,6 +105,25 @@ process { // GENOME QUALITY ASSESSMENT SUBWORKFLOW // + withName: BUSCO_BUSCO { + tag = { "${meta.domain}-${meta.id}" } + ext.args = params.busco_db ? '--offline' : '' + publishDir = [ + [ + path: { "${params.outdir}/${params.mode}/${meta.id}/busco/${meta.domain}-${meta.id}" }, + mode: params.publish_dir_mode, + pattern: "*{.txt,.json,.log}", + ], + [ + path: { "${params.outdir}/${params.mode}/${meta.id}/busco" }, + mode: params.publish_dir_mode, + overwrite: false, + pattern: "busco_downloads/lineages/*", + enabled: params.save_busco_db, + ], + ] + } + withName: 'CHECKM2_PREDICT' { publishDir = [ path: { "${params.outdir}/${params.mode}/${meta.id}/checkm2" }, diff --git a/nextflow.config b/nextflow.config index d3911f83..a778182c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -25,9 +25,15 @@ params { rrna_limit = 80 trna_limit = 18 - // checkm2: completeness and contamination + // completeness and contamination + // -- checkm2 checkm2_db = null checkm2_db_download_id = 14897628 + // -- busco + busco_db = null + busco_db_lineage = 'auto' + save_busco_db = false + busco_clean = false // NCBI taxonomy cat_db = null diff --git a/nextflow_schema.json b/nextflow_schema.json index bbd9f5d5..cfc55a44 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -95,6 +95,32 @@ "description": "Zenodo ID for CheckM2 database download", "default": 14897628, "fa_icon": "fas fa-users-cog" + }, + "busco_db": { + "type": "string", + "description": "Download URL, local tar.gz archive, or local uncompressed directory for an *_odb10 or *_odb12 BUSCO lineage dataset.", + "help_text": "E.g. https://busco-data.ezlab.org/v5/data/lineages/bacteria_odb10.2024-01-08.tar.gz, `/path/to/bacteria_odb10.2024-01-08.tar.gz`.\n\nFor more details, check the [BUSCO section in the usage documentation](https://nf-co.re/mag/latest/docs/usage/#busco).", + "format": "path", + "exists": true + }, + "busco_db_lineage": { + "type": "string", + "description": "Name of the BUSCO *_odb10 or *_odb12 lineage to check against. Additionally supports 'auto', 'auto_prok' and 'auto_euk' for automatic lineage selection mode.", + "help_text": "Typically used in combination with `--busco_db`, corresponding to the lineage files supplied within the `--busco_db` file or directory.\n\nIf supplying without a `--busco_db`, will require an internet connection to work!", + "pattern": "(.*_odb(10|12))|auto(_prok|_euk)?$", + "default": "auto" + }, + "save_busco_db": { + "type": "boolean", + "description": "Save the used BUSCO lineage datasets provided via `--busco_db`.", + "help_text": "Useful to allow reproducibility, as BUSCO datasets are frequently updated and old versions do not always remain accessible.", + "default": false + }, + "busco_clean": { + "type": "boolean", + "description": "Enable clean-up of temporary files created during BUSCO runs.", + "help_text": "By default, BUSCO creates a large number of intermediate files every run. This may cause problems on some clusters which have file number limits in plate, particularly with large numbers of bins. Enabling this option cleans these files, reducing the total file count of the work directory.", + "default": false } } }, diff --git a/subworkflows/local/genome_evaluation/main.nf b/subworkflows/local/genome_evaluation/main.nf index 8b74a36a..e0b1c395 100644 --- a/subworkflows/local/genome_evaluation/main.nf +++ b/subworkflows/local/genome_evaluation/main.nf @@ -50,6 +50,9 @@ workflow GENOME_EVALUATION { ch_checkm2_db_ready, ) + + BUSCO_BUSCO(ch_bins, 'genome', params.busco_db_lineage, ch_busco_db, [], params.busco_clean) + emit: genome_evaluation = CHECKM2_PREDICT.out.checkm2_tsv // channel: [ val(meta), path(tsv) ] stats_versions = CHECKM2_PREDICT.out.versions_checkm2_predict diff --git a/workflows/genomesubmit.nf b/workflows/genomesubmit.nf index 71bc6d3e..50e156e0 100644 --- a/workflows/genomesubmit.nf +++ b/workflows/genomesubmit.nf @@ -152,7 +152,7 @@ workflow GENOMESUBMIT { } .mix(branched_taxonomy_results.taxonomy_present) - // --------- Split data to eukaryotes (euk) and prokaryotes (bac and arc) + // --------- Add meta.domain value for eukaryotes (euk) and prokaryotes (bac and arc) domain_identification = fasta_updated_with_taxonomy .map { meta, fasta -> def lineage = meta.NCBI_lineage @@ -163,8 +163,6 @@ workflow GENOMESUBMIT { [ meta + [domain: is_euk ? 'euk' : (is_arc ? 'arc' : 'bac')], fasta ] } - domain_identification.view() - // --------- For genomes without RNA_presence info, calculate rRNA and tRNA branched_rna_results = domain_identification .branch { meta, _fasta -> From 033c2e6faf744f3ce62ce3276a349c0d525508b3 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Thu, 15 Oct 2026 14:42:03 +0100 Subject: [PATCH 04/24] added busco to genome_evaluation --- main.nf | 5 +- nextflow.config | 2 +- nextflow_schema.json | 2 +- subworkflows/local/genome_evaluation/main.nf | 58 +++++++++++++++++--- workflows/genomesubmit.nf | 8 ++- 5 files changed, 62 insertions(+), 13 deletions(-) diff --git a/main.nf b/main.nf index 1c9223ab..95eebadc 100644 --- a/main.nf +++ b/main.nf @@ -60,7 +60,10 @@ workflow NFCORE_SEQSUBMIT { params.test_upload, params.webincli_mode, params.is_private, - params.release_date ? channel.value(params.release_date): channel.value(false) + params.release_date ? channel.value(params.release_date): channel.value(false), + params.busco_db_lineage, + params.busco_db, + params.busco_clean ) ch_multiqc_report = GENOMESUBMIT.out.multiqc_report } else if (params.mode == "metagenomic_assemblies") { diff --git a/nextflow.config b/nextflow.config index a778182c..f097960a 100644 --- a/nextflow.config +++ b/nextflow.config @@ -31,7 +31,7 @@ params { checkm2_db_download_id = 14897628 // -- busco busco_db = null - busco_db_lineage = 'auto' + busco_db_lineage = 'auto_euk' save_busco_db = false busco_clean = false diff --git a/nextflow_schema.json b/nextflow_schema.json index cfc55a44..bef7ec3d 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -108,7 +108,7 @@ "description": "Name of the BUSCO *_odb10 or *_odb12 lineage to check against. Additionally supports 'auto', 'auto_prok' and 'auto_euk' for automatic lineage selection mode.", "help_text": "Typically used in combination with `--busco_db`, corresponding to the lineage files supplied within the `--busco_db` file or directory.\n\nIf supplying without a `--busco_db`, will require an internet connection to work!", "pattern": "(.*_odb(10|12))|auto(_prok|_euk)?$", - "default": "auto" + "default": "auto_euk" }, "save_busco_db": { "type": "boolean", diff --git a/subworkflows/local/genome_evaluation/main.nf b/subworkflows/local/genome_evaluation/main.nf index e0b1c395..1705c741 100644 --- a/subworkflows/local/genome_evaluation/main.nf +++ b/subworkflows/local/genome_evaluation/main.nf @@ -8,8 +8,10 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +include { BUSCO_BUSCO } from '../../../modules/nf-core/busco/busco/main' include { CHECKM2_DATABASEDOWNLOAD } from '../../../modules/nf-core/checkm2/databasedownload/main' include { CHECKM2_PREDICT } from '../../../modules/nf-core/checkm2/predict/main' +include { UNTAR as BUSCO_UNTAR } from '../../../modules/nf-core/untar/main' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -23,13 +25,25 @@ workflow GENOME_EVALUATION { ch_fasta // channel: [ val(meta), path(fasta) ] ch_checkm2_db // val: path to local CheckM2 database or null to trigger automatic download ch_checkm2_db_download_id // val: CheckM2 database Zenodo download ID + busco_db_lineage // val: lineage for checking against, default: auto_euk + ch_busco_db // path(fasta) or [] + busco_clean // boolean: clean intermediate busco files main: - // - // Database preparation - // - ch_do_download = ch_fasta + // ------ split input to Prokaryotes and Eukaryotes + + domain_split_fasta = ch_fasta + .branch { meta, fasta -> + proks: meta.domain in ['arc', 'bac'] + euks: meta.domain == 'euk' + } + + // ------ Prokaryotes + + // Database preparation for checkm2 + // that step would be launched only if proks branch is not empty + ch_do_download = domain_split_fasta.proks .first() .map { _meta_fasta -> ch_checkm2_db_download_id } @@ -41,17 +55,43 @@ workflow GENOME_EVALUATION { ch_checkm2_db_ready = CHECKM2_DATABASEDOWNLOAD.out.database } - // - // Genome evaluation - // + // Genome evaluation with CheckM2 CHECKM2_PREDICT( - ch_fasta, + domain_split_fasta.proks, ch_checkm2_db_ready, ) + // ------ Eukaryotes + + // Prepare database object depending on type + // If directory, assumes sub structure of `busco_db/lineages/_odb(10|12)` + + if (ch_busco_db && ch_busco_db.extension in ['gz', 'tgz']) { + // Only untar if there is at least one eukaryotic genome + ch_busco_untar_in = domain_split_fasta.euks + .first() + .map { _meta, _fasta -> [[id: ch_busco_db.simpleName], ch_busco_db] } + BUSCO_UNTAR(ch_busco_untar_in) + ch_busco_db = BUSCO_UNTAR.out.untar.map { _meta, db -> db }.first() + } + else if (ch_busco_db && ch_busco_db.isDirectory()) { + ch_busco_db = ch_busco_db + } + else { + ch_busco_db = [] + } - BUSCO_BUSCO(ch_bins, 'genome', params.busco_db_lineage, ch_busco_db, [], params.busco_clean) + // Genome evaluation with BUSCO + + BUSCO_BUSCO ( + domain_split_fasta.euks, + 'genome', // busco mode (choice of: genome, proteins, or transcriptome) + busco_db_lineage, // busco lineages file - downloads if not set + ch_busco_db, + [], + busco_clean + ) emit: genome_evaluation = CHECKM2_PREDICT.out.checkm2_tsv // channel: [ val(meta), path(tsv) ] diff --git a/workflows/genomesubmit.nf b/workflows/genomesubmit.nf index 50e156e0..ecca8d87 100644 --- a/workflows/genomesubmit.nf +++ b/workflows/genomesubmit.nf @@ -52,6 +52,9 @@ workflow GENOMESUBMIT { webincli_mode // val: either 'validate' or 'submit' to specify WebinCLI mode of operation is_private // val: fetch metadata from private/public account release_date // val: keep submitted data private until given date + busco_db_lineage // val: name of the busco supported lineage + busco_db // val: download URL or local tar.gz archive/directory + busco_clean // boolean: clean intermediate busco files main: @@ -198,7 +201,10 @@ workflow GENOMESUBMIT { GENOME_EVALUATION ( branched_stats_results.genome_evaluation_input, checkm2_db, - checkm2_db_download_id + checkm2_db_download_id, + busco_db_lineage, + busco_db ? file(busco_db, checkIfExists: true) : [], //channel with busco database + busco_clean ) // Create a value channel with the version string From fae4014ad8f599794051b4be57f60f21a417f378 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Mon, 19 Oct 2026 16:16:03 +0100 Subject: [PATCH 05/24] added eukcc single --- modules/local/eukcc/single/main.nf | 53 ++++++++++++++++++++ nextflow.config | 3 ++ nextflow_schema.json | 14 ++++++ subworkflows/local/genome_evaluation/main.nf | 8 +++ 4 files changed, 78 insertions(+) create mode 100644 modules/local/eukcc/single/main.nf diff --git a/modules/local/eukcc/single/main.nf b/modules/local/eukcc/single/main.nf new file mode 100644 index 00000000..2a8adb76 --- /dev/null +++ b/modules/local/eukcc/single/main.nf @@ -0,0 +1,53 @@ +process EUKCC_SINGLE { + + container 'community.wave.seqera.io/library/python_metaeuk_pplacer_epa-ng_pruned:0b7ea587ebcad440' + tag "${meta.id}" + + input: + tuple val(meta), path(fasta) + tuple val(meta_db), path(eukcc_db) + + output: + tuple val(meta), path("*_eukcc_results/*eukcc.csv"), optional: true, emit: eukcc_csv + tuple val("${task.process}"), val('eukcc'), eval('eukcc -v 2>&1 | grep -oE "[0-9]+\\.[0-9]+\\.[0-9]+" | head -n1'), emit: versions_eukcc, topic: versions + tuple val("${task.process}"), val('metaeuk'), eval('metaeuk -h 2>&1 | grep "Version" | sed "s/.*Version: //"'), emit: versions_metaeuk, topic: versions + tuple val("${task.process}"), val('pplacer'), eval ('pplacer --version'), emit: versions_pplacer, topic: versions + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + # EukCC exit codes: + # 201 - no marker genes found, 204 - MetaEuk predicted zero proteins: not an error, genome has no estimate + # any other non-zero code (e.g. 1, 200, 202, 203, 222) is a real failure + set +e + eukcc single \\ + ${args} \\ + --db ${eukcc_db} \\ + --out ${prefix}_eukcc_results \\ + --threads ${task.cpus} \\ + ${fasta} + exit_code=\$? + set -e + + case \$exit_code in + 0) + ;; + 201|204) + echo "EukCC exited with code \$exit_code: no completeness estimate for ${prefix}" >&2 + ;; + *) + echo "EukCC failed with exit code \$exit_code" >&2 + exit \$exit_code + ;; + esac + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + printf 'genome,completeness,contamination,ncbi_lng\\n${meta.id},90.0,1.0,1-131567-2759-33154-4751\\n' > ${meta.id}_eukcc.csv + """ +} \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index f097960a..c7fd9673 100644 --- a/nextflow.config +++ b/nextflow.config @@ -26,6 +26,7 @@ params { trna_limit = 18 // completeness and contamination + eukaryotic_completeness_tool = 'eukcc' // -- checkm2 checkm2_db = null checkm2_db_download_id = 14897628 @@ -34,6 +35,8 @@ params { busco_db_lineage = 'auto_euk' save_busco_db = false busco_clean = false + // -- eukcc + eukcc_db = null // NCBI taxonomy cat_db = null diff --git a/nextflow_schema.json b/nextflow_schema.json index bef7ec3d..fe2902c3 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -121,6 +121,20 @@ "description": "Enable clean-up of temporary files created during BUSCO runs.", "help_text": "By default, BUSCO creates a large number of intermediate files every run. This may cause problems on some clusters which have file number limits in plate, particularly with large numbers of bins. Enabling this option cleans these files, reducing the total file count of the work directory.", "default": false + }, + "eukcc_db": { + "type": "string", + "description": "Path to EukCC database folder", + "help_text": "Folder with atabase downloaded from http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz and uncompressed.", + "format": "path", + "exists": true + }, + "eukaryotic_completeness_tool": { + "type": "string", + "description": "Name of the tool to compute completeness for eukaryotic MAGs/bins. Choice: eukcc or busco. Default: eukcc", + "help_text": "Completeness of eukaryotic MAGs/bins can be calculated using eukcc or busco.", + "enum": ["eukcc", "busco"], + "default": "eukcc" } } }, diff --git a/subworkflows/local/genome_evaluation/main.nf b/subworkflows/local/genome_evaluation/main.nf index 1705c741..28675ceb 100644 --- a/subworkflows/local/genome_evaluation/main.nf +++ b/subworkflows/local/genome_evaluation/main.nf @@ -7,6 +7,7 @@ IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +include { EUKCC_SINGLE } from '../../../modules/local/eukcc/single/main' include { BUSCO_BUSCO } from '../../../modules/nf-core/busco/busco/main' include { CHECKM2_DATABASEDOWNLOAD } from '../../../modules/nf-core/checkm2/databasedownload/main' @@ -93,6 +94,13 @@ workflow GENOME_EVALUATION { busco_clean ) + eukcc_database = channel.value([[id: 'eukcc_db'], file(params.eukcc_db, checkIfExists: true)]) + EUKCC_SINGLE ( + domain_split_fasta.euks, + eukcc_database + ) + + emit: genome_evaluation = CHECKM2_PREDICT.out.checkm2_tsv // channel: [ val(meta), path(tsv) ] stats_versions = CHECKM2_PREDICT.out.versions_checkm2_predict From 65e2f7ac50525cd5f120724e82d8473b4552ab36 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Mon, 19 Oct 2026 16:27:40 +0100 Subject: [PATCH 06/24] added fasta uncompress for stupid eukcc --- conf/containers_conda_lock_files_amd64.config | 2 +- conf/containers_docker_amd64.config | 2 +- .../containers_singularity_https_amd64.config | 2 +- conf/containers_singularity_oras_amd64.config | 2 +- modules.json | 5 + modules/local/eukcc/single/main.nf | 2 +- modules/nf-core/gunzip/environment.yml | 12 + modules/nf-core/gunzip/main.nf | 47 ++++ modules/nf-core/gunzip/meta.yml | 68 ++++++ modules/nf-core/gunzip/tests/main.nf.test | 175 +++++++++++++++ .../nf-core/gunzip/tests/main.nf.test.snap | 207 ++++++++++++++++++ modules/nf-core/gunzip/tests/nextflow.config | 5 + subworkflows/local/genome_evaluation/main.nf | 6 +- 13 files changed, 529 insertions(+), 6 deletions(-) create mode 100644 modules/nf-core/gunzip/environment.yml create mode 100644 modules/nf-core/gunzip/main.nf create mode 100644 modules/nf-core/gunzip/meta.yml create mode 100644 modules/nf-core/gunzip/tests/main.nf.test create mode 100644 modules/nf-core/gunzip/tests/main.nf.test.snap create mode 100644 modules/nf-core/gunzip/tests/nextflow.config diff --git a/conf/containers_conda_lock_files_amd64.config b/conf/containers_conda_lock_files_amd64.config index 50044143..efe310c7 100644 --- a/conf/containers_conda_lock_files_amd64.config +++ b/conf/containers_conda_lock_files_amd64.config @@ -1,2 +1,2 @@ -process { withName: 'BUSCO/DOWNLOAD' { container = 'modules/nf-core/busco/download/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt' } } +process { withName: 'BUSCO_BUSCO' { container = 'modules/nf-core/busco/busco/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt' } } process { withName: 'MULTIQC' { container = 'modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt' } } diff --git a/conf/containers_docker_amd64.config b/conf/containers_docker_amd64.config index 6b811cfc..7668fe46 100644 --- a/conf/containers_docker_amd64.config +++ b/conf/containers_docker_amd64.config @@ -1,2 +1,2 @@ -process { withName: 'BUSCO/DOWNLOAD' { container = 'community.wave.seqera.io/library/busco:6.1.0--6d1f7006d91892b3' } } +process { withName: 'BUSCO_BUSCO' { container = 'community.wave.seqera.io/library/busco:6.1.0--6d1f7006d91892b3' } } process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc' } } diff --git a/conf/containers_singularity_https_amd64.config b/conf/containers_singularity_https_amd64.config index 7ede98e1..32547a00 100644 --- a/conf/containers_singularity_https_amd64.config +++ b/conf/containers_singularity_https_amd64.config @@ -1,2 +1,2 @@ -process { withName: 'BUSCO/DOWNLOAD' { container = 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/96/963bad66c10646cf0adb1967cc462ad04d02789ddbfae4fbb94182291dbddf8c/data' } } +process { withName: 'BUSCO_BUSCO' { container = 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/96/963bad66c10646cf0adb1967cc462ad04d02789ddbfae4fbb94182291dbddf8c/data' } } process { withName: 'MULTIQC' { container = 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c8/c8e346f4f6080eadf1253505e6ff09ef004454fc18e8d672006fd7b222cc412e/data' } } diff --git a/conf/containers_singularity_oras_amd64.config b/conf/containers_singularity_oras_amd64.config index a44f53d6..c40dcf68 100644 --- a/conf/containers_singularity_oras_amd64.config +++ b/conf/containers_singularity_oras_amd64.config @@ -1,2 +1,2 @@ -process { withName: 'BUSCO/DOWNLOAD' { container = 'oras://community.wave.seqera.io/library/busco:6.1.0--c7528d5825eb19b5' } } +process { withName: 'BUSCO_BUSCO' { container = 'oras://community.wave.seqera.io/library/busco:6.1.0--c7528d5825eb19b5' } } process { withName: 'MULTIQC' { container = 'oras://community.wave.seqera.io/library/multiqc:1.35--c680f2aea25ccec2' } } diff --git a/modules.json b/modules.json index 4f12033e..f1308bd3 100644 --- a/modules.json +++ b/modules.json @@ -81,6 +81,11 @@ "installed_by": ["modules"], "patch": "modules/nf-core/find/concatenate/find-concatenate.diff" }, + "gunzip": { + "branch": "master", + "git_sha": "0902eac3012baaf4f9ab6513c8c55acc9353c96c", + "installed_by": ["modules"] + }, "multiqc": { "branch": "master", "git_sha": "98403d15b0e50edae1f3fec5eae5e24982f1fade", diff --git a/modules/local/eukcc/single/main.nf b/modules/local/eukcc/single/main.nf index 2a8adb76..b864963f 100644 --- a/modules/local/eukcc/single/main.nf +++ b/modules/local/eukcc/single/main.nf @@ -50,4 +50,4 @@ process EUKCC_SINGLE { """ printf 'genome,completeness,contamination,ncbi_lng\\n${meta.id},90.0,1.0,1-131567-2759-33154-4751\\n' > ${meta.id}_eukcc.csv """ -} \ No newline at end of file +} diff --git a/modules/nf-core/gunzip/environment.yml b/modules/nf-core/gunzip/environment.yml new file mode 100644 index 00000000..9b926b1f --- /dev/null +++ b/modules/nf-core/gunzip/environment.yml @@ -0,0 +1,12 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - conda-forge::coreutils=9.5 + - conda-forge::grep=3.11 + - conda-forge::gzip=1.13 + - conda-forge::lbzip2=2.5 + - conda-forge::sed=4.8 + - conda-forge::tar=1.34 diff --git a/modules/nf-core/gunzip/main.nf b/modules/nf-core/gunzip/main.nf new file mode 100644 index 00000000..6edffc59 --- /dev/null +++ b/modules/nf-core/gunzip/main.nf @@ -0,0 +1,47 @@ +process GUNZIP { + tag "${archive}" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/52/52ccce28d2ab928ab862e25aae26314d69c8e38bd41ca9431c67ef05221348aa/data' + : 'community.wave.seqera.io/library/coreutils_grep_gzip_lbzip2_pruned:838ba80435a629f8'}" + + input: + tuple val(meta), path(archive) + + output: + tuple val(meta), path("${gunzip}"), emit: gunzip + tuple val("${task.process}"), val('gunzip'), eval('gunzip --version 2>&1 | head -1 | sed "s/^.*(gzip) //; s/ Copyright.*//"'), topic: versions, emit: versions_gunzip + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def nameWithoutGz = archive.extension == 'gz' ? archive.baseName : archive.name + def extension = file(nameWithoutGz).extension + def name = file(nameWithoutGz).baseName + def prefix = task.ext.prefix ?: name + gunzip = prefix + ".${extension}" + """ + # Not calling gunzip itself because it creates files + # with the original group ownership rather than the + # default one for that user / the work directory + gzip \\ + -cd \\ + ${args} \\ + ${archive} \\ + > ${gunzip} + """ + + stub: + def nameWithoutGz = archive.extension == 'gz' ? archive.baseName : archive.name + def extension = file(nameWithoutGz).extension + def name = file(nameWithoutGz).baseName + def prefix = task.ext.prefix ?: name + gunzip = prefix + ".${extension}" + """ + touch ${gunzip} + """ +} diff --git a/modules/nf-core/gunzip/meta.yml b/modules/nf-core/gunzip/meta.yml new file mode 100644 index 00000000..bba6b3ba --- /dev/null +++ b/modules/nf-core/gunzip/meta.yml @@ -0,0 +1,68 @@ +name: gunzip +description: Compresses and decompresses files. +keywords: + - gunzip + - compression + - decompression +tools: + - gunzip: + description: | + gzip is a file format and a software application used for file compression and decompression. + documentation: https://www.gnu.org/software/gzip/manual/gzip.html + licence: ["GPL-3.0-or-later"] + identifier: "" +input: + - - meta: + type: map + description: | + Optional groovy Map containing meta information + e.g. [ id:'test', single_end:false ] + - archive: + type: file + description: File to be compressed/uncompressed + pattern: "*.*" + ontologies: [] +output: + gunzip: + - - meta: + type: file + description: Compressed/uncompressed file + pattern: "*.*" + ontologies: [] + - ${gunzip}: + type: file + description: Compressed/uncompressed file + pattern: "*.*" + ontologies: [] + versions_gunzip: + - - ${task.process}: + type: string + description: The process the versions were collected from + - gunzip: + type: string + description: The tool name + - gunzip --version 2>&1 | head -1 | sed "s/^.*(gzip) //; s/ Copyright.*//": + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - gunzip: + type: string + description: The tool name + - gunzip --version 2>&1 | head -1 | sed "s/^.*(gzip) //; s/ Copyright.*//": + type: eval + description: The expression to obtain the version of the tool + +authors: + - "@joseespinosa" + - "@drpatelh" + - "@jfy133" +maintainers: + - "@joseespinosa" + - "@drpatelh" + - "@jfy133" + - "@gallvp" diff --git a/modules/nf-core/gunzip/tests/main.nf.test b/modules/nf-core/gunzip/tests/main.nf.test new file mode 100644 index 00000000..33cb75ae --- /dev/null +++ b/modules/nf-core/gunzip/tests/main.nf.test @@ -0,0 +1,175 @@ +nextflow_process { + + name "Test Process GUNZIP" + script "../main.nf" + process "GUNZIP" + tag "gunzip" + tag "modules_nfcore" + tag "modules" + + test("Should run without failures") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("Should run without failures - prefix") { + + config './nextflow.config' + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [ id: 'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("Should run without failures - stub") { + + options '-stub' + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("Should decompress file with extension appearing multiple times in filename") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true).copyTo('test.fa.v1.fa.gz') + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert file(process.out.gunzip[0][1]).name == 'test.fa.v1.fa' } + ) + } + + } + + test("Should decompress file with extension appearing multiple times in filename - prefix") { + + config './nextflow.config' + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [ id: 'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true).copyTo('test.fa.v1.fa.gz') + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("Should run without failures - prefix - stub") { + + options '-stub' + config './nextflow.config' + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [ id: 'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/gunzip/tests/main.nf.test.snap b/modules/nf-core/gunzip/tests/main.nf.test.snap new file mode 100644 index 00000000..980e95a2 --- /dev/null +++ b/modules/nf-core/gunzip/tests/main.nf.test.snap @@ -0,0 +1,207 @@ +{ + "Should decompress file with extension appearing multiple times in filename - prefix": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.xyz.fa:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "1": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ], + "gunzip": [ + [ + { + "id": "test" + }, + "test.xyz.fa:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "versions_gunzip": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ] + } + ], + "timestamp": "2026-04-15T15:20:52.59447", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "Should run without failures - prefix - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.xyz.fastq:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ], + "gunzip": [ + [ + { + "id": "test" + }, + "test.xyz.fastq:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_gunzip": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ] + } + ], + "timestamp": "2026-01-19T17:21:56.633550769", + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + } + }, + "Should run without failures - stub": { + "content": [ + { + "0": [ + [ + [ + + ], + "test_1.fastq:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ], + "gunzip": [ + [ + [ + + ], + "test_1.fastq:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_gunzip": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ] + } + ], + "timestamp": "2026-01-19T17:21:51.435621199", + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + } + }, + "Should run without failures": { + "content": [ + { + "0": [ + [ + [ + + ], + "test_1.fastq:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "1": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ], + "gunzip": [ + [ + [ + + ], + "test_1.fastq:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "versions_gunzip": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ] + } + ], + "timestamp": "2026-01-19T17:21:40.613975821", + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + } + }, + "Should run without failures - prefix": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.xyz.fastq:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "1": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ], + "gunzip": [ + [ + { + "id": "test" + }, + "test.xyz.fastq:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "versions_gunzip": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ] + } + ], + "timestamp": "2026-01-19T17:21:46.086880414", + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/gunzip/tests/nextflow.config b/modules/nf-core/gunzip/tests/nextflow.config new file mode 100644 index 00000000..dec77642 --- /dev/null +++ b/modules/nf-core/gunzip/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: GUNZIP { + ext.prefix = { "${meta.id}.xyz" } + } +} diff --git a/subworkflows/local/genome_evaluation/main.nf b/subworkflows/local/genome_evaluation/main.nf index 28675ceb..9cfb29a6 100644 --- a/subworkflows/local/genome_evaluation/main.nf +++ b/subworkflows/local/genome_evaluation/main.nf @@ -13,6 +13,7 @@ include { BUSCO_BUSCO } from '../../../modules/nf-core/busco/busco/ include { CHECKM2_DATABASEDOWNLOAD } from '../../../modules/nf-core/checkm2/databasedownload/main' include { CHECKM2_PREDICT } from '../../../modules/nf-core/checkm2/predict/main' include { UNTAR as BUSCO_UNTAR } from '../../../modules/nf-core/untar/main' +include { GUNZIP as GUNZIP_FASTA } from '../../../modules/nf-core/gunzip/main' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -95,8 +96,11 @@ workflow GENOME_EVALUATION { ) eukcc_database = channel.value([[id: 'eukcc_db'], file(params.eukcc_db, checkIfExists: true)]) + + GUNZIP_FASTA ( domain_split_fasta.euks ) + EUKCC_SINGLE ( - domain_split_fasta.euks, + GUNZIP_FASTA.out.gunzip, eukcc_database ) From f785c584636bf5374295092aac9c7908bbad074d Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Mon, 19 Oct 2026 17:41:51 +0100 Subject: [PATCH 07/24] add stats distribution to main workflow --- conf/modules.config | 2 +- main.nf | 4 +- modules/local/eukcc/single/main.nf | 15 +- nextflow_schema.json | 4 +- subworkflows/local/genome_evaluation/main.nf | 149 ++++++++++++++----- workflows/genomesubmit.nf | 66 ++++---- 6 files changed, 160 insertions(+), 80 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index f3a5608e..7a279c9d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -68,7 +68,7 @@ process { ] } - withName: 'RENAME_FASTA_FOR_CATPACK|CAT_DB_UNTAR' { + withName: 'RENAME_FASTA_FOR_CATPACK|CAT_DB_UNTAR|DB_UNTAR' { publishDir = [ enabled: false ] diff --git a/main.nf b/main.nf index 95eebadc..54ae7d63 100644 --- a/main.nf +++ b/main.nf @@ -63,7 +63,9 @@ workflow NFCORE_SEQSUBMIT { params.release_date ? channel.value(params.release_date): channel.value(false), params.busco_db_lineage, params.busco_db, - params.busco_clean + params.busco_clean, + params.eukaryotic_completeness_tool, + params.eukcc_db ) ch_multiqc_report = GENOMESUBMIT.out.multiqc_report } else if (params.mode == "metagenomic_assemblies") { diff --git a/modules/local/eukcc/single/main.nf b/modules/local/eukcc/single/main.nf index b864963f..68413b0e 100644 --- a/modules/local/eukcc/single/main.nf +++ b/modules/local/eukcc/single/main.nf @@ -8,14 +8,14 @@ process EUKCC_SINGLE { tuple val(meta_db), path(eukcc_db) output: - tuple val(meta), path("*_eukcc_results/*eukcc.csv"), optional: true, emit: eukcc_csv + tuple val(meta), path("${prefix}_eukcc_results/eukcc.tsv"), emit: eukcc_tsv tuple val("${task.process}"), val('eukcc'), eval('eukcc -v 2>&1 | grep -oE "[0-9]+\\.[0-9]+\\.[0-9]+" | head -n1'), emit: versions_eukcc, topic: versions tuple val("${task.process}"), val('metaeuk'), eval('metaeuk -h 2>&1 | grep "Version" | sed "s/.*Version: //"'), emit: versions_metaeuk, topic: versions tuple val("${task.process}"), val('pplacer'), eval ('pplacer --version'), emit: versions_pplacer, topic: versions script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" """ # EukCC exit codes: @@ -35,7 +35,10 @@ process EUKCC_SINGLE { 0) ;; 201|204) + # write header-only table so the genome is kept downstream with empty completeness/contamination echo "EukCC exited with code \$exit_code: no completeness estimate for ${prefix}" >&2 + mkdir -p ${prefix}_eukcc_results + printf 'fasta\\tcompleteness\\tcontamination\\tncbi_lng\\n' > ${prefix}_eukcc_results/eukcc.tsv ;; *) echo "EukCC failed with exit code \$exit_code" >&2 @@ -45,9 +48,9 @@ process EUKCC_SINGLE { """ stub: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ - printf 'genome,completeness,contamination,ncbi_lng\\n${meta.id},90.0,1.0,1-131567-2759-33154-4751\\n' > ${meta.id}_eukcc.csv + mkdir -p ${prefix}_eukcc_results + printf 'fasta\\tcompleteness\\tcontamination\\tncbi_lng\\n${fasta}\\t90.0\\t1.0\\t1-131567-2759-33154-4751\\n' > ${prefix}_eukcc_results/eukcc.tsv """ } diff --git a/nextflow_schema.json b/nextflow_schema.json index fe2902c3..f44688bf 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -124,8 +124,8 @@ }, "eukcc_db": { "type": "string", - "description": "Path to EukCC database folder", - "help_text": "Folder with atabase downloaded from http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz and uncompressed.", + "description": "Path to EukCC database folder or .tar.gz/.tgz archive (local path or URL).", + "help_text": "EukCC database, e.g. http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz. Can be given as an uncompressed folder, or as a .tar.gz/.tgz archive (local path or URL) that will be extracted by the pipeline. Required if there are eukaryotic genomes. To avoid downloading it in every run, download and extract it once and provide the folder.", "format": "path", "exists": true }, diff --git a/subworkflows/local/genome_evaluation/main.nf b/subworkflows/local/genome_evaluation/main.nf index 9cfb29a6..d10d4ce3 100644 --- a/subworkflows/local/genome_evaluation/main.nf +++ b/subworkflows/local/genome_evaluation/main.nf @@ -12,7 +12,7 @@ include { EUKCC_SINGLE } from '../../../modules/local/eukcc/single/m include { BUSCO_BUSCO } from '../../../modules/nf-core/busco/busco/main' include { CHECKM2_DATABASEDOWNLOAD } from '../../../modules/nf-core/checkm2/databasedownload/main' include { CHECKM2_PREDICT } from '../../../modules/nf-core/checkm2/predict/main' -include { UNTAR as BUSCO_UNTAR } from '../../../modules/nf-core/untar/main' +include { UNTAR as DB_UNTAR } from '../../../modules/nf-core/untar/main' include { GUNZIP as GUNZIP_FASTA } from '../../../modules/nf-core/gunzip/main' /* @@ -24,12 +24,14 @@ include { GUNZIP as GUNZIP_FASTA } from '../../../modules/nf-core/gunzip/main' workflow GENOME_EVALUATION { take: - ch_fasta // channel: [ val(meta), path(fasta) ] - ch_checkm2_db // val: path to local CheckM2 database or null to trigger automatic download - ch_checkm2_db_download_id // val: CheckM2 database Zenodo download ID - busco_db_lineage // val: lineage for checking against, default: auto_euk - ch_busco_db // path(fasta) or [] - busco_clean // boolean: clean intermediate busco files + ch_fasta // channel: [ val(meta), path(fasta) ] + ch_checkm2_db // val: path to local CheckM2 database or null to trigger automatic download + ch_checkm2_db_download_id // val: CheckM2 database Zenodo download ID + busco_db_lineage // val: lineage for checking against, default: auto_euk + busco_db // val: BUSCO database - local directory or .tar.gz/.tgz archive (path or URL), or null to download + busco_clean // boolean: clean intermediate busco files + eukaryotic_completeness_tool // val: busco or eukcc + eukcc_db // val: EukCC database - local directory or .tar.gz/.tgz archive (path or URL) main: @@ -51,7 +53,7 @@ workflow GENOME_EVALUATION { // Download and prepare db from scratch if no pre-built db provided if (ch_checkm2_db) { - ch_checkm2_db_ready = channel.value([[id: 'checkm2_db'], file(params.checkm2_db, checkIfExists: true)]) + ch_checkm2_db_ready = channel.value([[id: 'checkm2_db'], file(ch_checkm2_db, checkIfExists: true)]) } else { CHECKM2_DATABASEDOWNLOAD(ch_do_download) ch_checkm2_db_ready = CHECKM2_DATABASEDOWNLOAD.out.database @@ -66,36 +68,48 @@ workflow GENOME_EVALUATION { // ------ Eukaryotes - // Prepare database object depending on type - // If directory, assumes sub structure of `busco_db/lineages/_odb(10|12)` + // Databases for eukaryotes can be given as a directory or as a .tar.gz/.tgz archive (local path or URL). + // Archives are extracted with a single DB_UNTAR step, only if there is at least one eukaryotic genome. + // BUSCO database directory is expected to have the structure `/lineages/_odb(10|12)` + def busco_db_file = (eukaryotic_completeness_tool == 'busco' && busco_db) ? file(busco_db, checkIfExists: true) : null + def eukcc_db_file = eukcc_db ? file(eukcc_db, checkIfExists: true) : null - if (ch_busco_db && ch_busco_db.extension in ['gz', 'tgz']) { - // Only untar if there is at least one eukaryotic genome - ch_busco_untar_in = domain_split_fasta.euks - .first() - .map { _meta, _fasta -> [[id: ch_busco_db.simpleName], ch_busco_db] } - BUSCO_UNTAR(ch_busco_untar_in) - ch_busco_db = BUSCO_UNTAR.out.untar.map { _meta, db -> db }.first() - } - else if (ch_busco_db && ch_busco_db.isDirectory()) { - ch_busco_db = ch_busco_db - } - else { - ch_busco_db = [] - } + ch_db_archives = domain_split_fasta.euks + .first() + .flatMap { _meta, _fasta -> + [ + [[id: 'busco_db'], busco_db_file], + [[id: 'eukcc_db'], eukcc_db_file] + ].findAll { _db_meta, db -> isArchive(db) } + } - // Genome evaluation with BUSCO + DB_UNTAR ( ch_db_archives ) - BUSCO_BUSCO ( - domain_split_fasta.euks, - 'genome', // busco mode (choice of: genome, proteins, or transcriptome) - busco_db_lineage, // busco lineages file - downloads if not set - ch_busco_db, - [], - busco_clean - ) + if (eukaryotic_completeness_tool == 'busco') { + // Without a database BUSCO downloads the lineages itself + def ch_busco_db = busco_db_file + ? prepareDatabase(busco_db_file, 'busco_db', DB_UNTAR.out.untar).map { _db_meta, db -> db } + : [] + + // Genome evaluation with BUSCO + + BUSCO_BUSCO ( + domain_split_fasta.euks, + 'genome', // busco mode (choice of: genome, proteins, or transcriptome) + busco_db_lineage, // busco lineages file - downloads if not set + ch_busco_db, + [], + busco_clean + ) + } - eukcc_database = channel.value([[id: 'eukcc_db'], file(params.eukcc_db, checkIfExists: true)]) + // Run EukCC for completeness and contamination of eukaryotes + // Database is required only when there is at least one eukaryotic genome + def eukcc_database = eukcc_db_file + ? prepareDatabase(eukcc_db_file, 'eukcc_db', DB_UNTAR.out.untar) + : domain_split_fasta.euks.first().map { _meta, _fasta -> + error("Eukaryotic genomes were found, but --eukcc_db is not provided. Please provide the EukCC database.") + } GUNZIP_FASTA ( domain_split_fasta.euks ) @@ -104,9 +118,72 @@ workflow GENOME_EVALUATION { eukcc_database ) + // ------ Combine completeness and contamination from both tools into one channel + + // Software name with version, e.g. checkm2_v1.0.2, assigned per tool + def checkm2_software = CHECKM2_PREDICT.out.versions_checkm2_predict + .map { _process_name, tool_name, version -> "${tool_name}_v${version}" } + .first() + def eukcc_software = EUKCC_SINGLE.out.versions_eukcc + .map { _process_name, tool_name, version -> "${tool_name}_v${version}" } + .first() + + ch_prok_stats = CHECKM2_PREDICT.out.checkm2_tsv + .combine(checkm2_software) + .map { meta, table, software -> parseStatsTable(meta, table, software) } + + ch_euk_stats = EUKCC_SINGLE.out.eukcc_tsv + .combine(eukcc_software) + .map { meta, table, software -> parseStatsTable(meta, table, software) } emit: - genome_evaluation = CHECKM2_PREDICT.out.checkm2_tsv // channel: [ val(meta), path(tsv) ] - stats_versions = CHECKM2_PREDICT.out.versions_checkm2_predict + stats = ch_prok_stats.mix(ch_euk_stats) // channel: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] + +} +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + FUNCTIONS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +// +// True if the database is a compressed tar archive that has to be extracted before use +// +def isArchive(db) { + return db && (db.name.endsWith('.tar.gz') || db.name.endsWith('.tgz')) +} + +// +// Return a value channel [ val(meta), path(db_dir) ] with a ready-to-use database: +// - archive (.tar.gz/.tgz, local or URL): the matching DB_UNTAR output, selected by meta.id +// - directory: used as is +// Anything else (single uncompressed file, remote directory) is an error +// +def prepareDatabase(db, db_id, ch_untarred) { + if (isArchive(db)) { + return ch_untarred + .filter { db_meta, _dir -> db_meta.id == db_id } + .first() + } + if (db.isDirectory()) { + return channel.value([[id: db_id], db]) + } + error("Database '${db}' for ${db_id} must be a local directory or a .tar.gz/.tgz archive (local path or URL)") +} + +// +// Read completeness and contamination from a CheckM2 quality_report.tsv or EukCC eukcc.tsv. +// Both are tab-separated with a header and genome name, completeness, contamination as first three columns. +// Empty or header-only tables (-stub mode, EukCC exit codes 201/204) give null values. +// +def parseStatsTable(meta, table, software) { + def lines = table.readLines() + def values = lines.size() > 1 ? lines[1].split('\t') : null + return [ + meta, + values ? values[1] : null, + values ? values[2] : null, + software + ] } diff --git a/workflows/genomesubmit.nf b/workflows/genomesubmit.nf index ecca8d87..013af24c 100644 --- a/workflows/genomesubmit.nf +++ b/workflows/genomesubmit.nf @@ -33,28 +33,30 @@ include { methodsDescriptionText } from '../subworkflows/local/ut workflow GENOMESUBMIT { take: - ch_samplesheet // channel: samplesheet read in from --input + ch_samplesheet // channel: samplesheet read in from --input multiqc_config multiqc_logo multiqc_methods_description outdir - mags_or_bins_flag // val: submission mode (mags or bins) - submission_study // val: accession of the study to submit to (optional) - study_metadata // val: path to study metadata file for study creation (used if no submission_study provided) - trna_limit // val: tRNA count threshold - rrna_limit // val: rRNA length percentage threshold - checkm2_db // val: path to CheckM2 database - checkm2_db_download_id // val: CheckM2 database download ID - cat_db // val: path to CAT database - centre_name // val: submission centre name - upload_tpa // val: upload as TPA (Third Party Annotation) - test_upload // val: true for test upload mode - webincli_mode // val: either 'validate' or 'submit' to specify WebinCLI mode of operation - is_private // val: fetch metadata from private/public account - release_date // val: keep submitted data private until given date - busco_db_lineage // val: name of the busco supported lineage - busco_db // val: download URL or local tar.gz archive/directory - busco_clean // boolean: clean intermediate busco files + mags_or_bins_flag // val: submission mode (mags or bins) + submission_study // val: accession of the study to submit to (optional) + study_metadata // val: path to study metadata file for study creation (used if no submission_study provided) + trna_limit // val: tRNA count threshold + rrna_limit // val: rRNA length percentage threshold + checkm2_db // val: path to CheckM2 database + checkm2_db_download_id // val: CheckM2 database download ID + cat_db // val: path to CAT database + centre_name // val: submission centre name + upload_tpa // val: upload as TPA (Third Party Annotation) + test_upload // val: true for test upload mode + webincli_mode // val: either 'validate' or 'submit' to specify WebinCLI mode of operation + is_private // val: fetch metadata from private/public account + release_date // val: keep submitted data private until given date + busco_db_lineage // val: name of the busco supported lineage + busco_db // val: download URL or local tar.gz archive/directory + busco_clean // boolean: clean intermediate busco files + eukaryotic_completeness_tool // val: busco or eukcc + eukcc_db // val: EukCC database - local directory or .tar.gz/.tgz archive (path or URL) main: @@ -203,25 +205,21 @@ workflow GENOMESUBMIT { checkm2_db, checkm2_db_download_id, busco_db_lineage, - busco_db ? file(busco_db, checkIfExists: true) : [], //channel with busco database - busco_clean + busco_db, + busco_clean, + eukaryotic_completeness_tool, + eukcc_db ) - // Create a value channel with the version string - def stats_version_ch = GENOME_EVALUATION.out.stats_versions - .map { _process_name, tool_name, version_output -> return "${tool_name}_v${version_output}" - }.first() - - fasta_updated_with_stats = GENOME_EVALUATION.out.genome_evaluation + // Update metadata with completeness and contamination from CheckM2 (prokaryotes) or EukCC (eukaryotes) + fasta_updated_with_stats = GENOME_EVALUATION.out.stats .join(branched_stats_results.genome_evaluation_input) - .combine(stats_version_ch) - .map { meta, stats_tsv, fasta, stats_version -> - def lines = stats_tsv.readLines() - // support for empty checkm files required for -stub mode - def updated_meta = meta.clone() - updated_meta.completeness = lines ? lines[1].split('\t')[1] : null - updated_meta.contamination = lines ? lines[1].split('\t')[2] : null - updated_meta.stats_generation_software = stats_version + .map { meta, completeness, contamination, stats_software, fasta -> + def updated_meta = meta + [ + completeness: completeness, + contamination: contamination, + stats_generation_software: stats_software + ] return [updated_meta, fasta] } .mix(branched_stats_results.evaluation_present) From 04765a976277fbff5a6ea492dd0787005a637655 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Tue, 20 Oct 2026 11:13:54 +0100 Subject: [PATCH 08/24] added subwf tests, added busco/eukcc logic, updated docs --- CITATIONS.md | 18 ++ conf/containers_docker_arm64.config | 1 + conf/modules.config | 14 + conf/test_mag_no_rna_presence.conf | 3 +- docs/methods.md | 79 ++++-- docs/output.md | 9 +- docs/usage.md | 43 ++- modules/local/eukcc/single/environment.yml | 13 + modules/local/eukcc/single/main.nf | 3 +- modules/local/eukcc/single/meta.yml | 129 +++++++++ modules/nf-core/busco/busco/main.nf | 3 +- subworkflows/local/genome_evaluation/main.nf | 92 ++++++- .../genome_evaluation/tests/main.nf.test | 253 ++++++++++++++++++ .../genome_evaluation/tests/main.nf.test.snap | 124 +++++++++ .../utils_nfcore_seqsubmit_pipeline/main.nf | 12 +- 15 files changed, 745 insertions(+), 51 deletions(-) create mode 100644 modules/local/eukcc/single/environment.yml create mode 100644 modules/local/eukcc/single/meta.yml create mode 100644 subworkflows/local/genome_evaluation/tests/main.nf.test create mode 100644 subworkflows/local/genome_evaluation/tests/main.nf.test.snap diff --git a/CITATIONS.md b/CITATIONS.md index 495f4220..37967619 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -22,6 +22,24 @@ > Chklovski A, Parks DH, Woodcroft BJ, Tyson GW. CheckM2: a rapid, scalable and accurate tool for assessing microbial genome quality using machine learning. Nat Methods. 2023;20(8):1203-1212. doi: 10.1038/s41592-023-01940-w. PubMed PMID: 37500759; PubMed Central PMCID: not available. +- [EukCC](https://github.com/EBI-Metagenomics/EukCC) + +> Saary P, Mitchell AL, Finn RD. Estimating the quality of eukaryotic genomes recovered from metagenomic analysis with EukCC. Genome Biol. 2020;21(1):244. doi: 10.1186/s13059-020-02155-4. PubMed PMID: 32912302; PubMed Central PMCID: PMC7488429. + +- [MetaEuk](https://github.com/soedinglab/metaeuk) + +> Levy Karin E, Mirdita M, Söding J. MetaEuk-sensitive, high-throughput gene discovery, and annotation for large-scale eukaryotic metagenomics. Microbiome. 2020;8(1):48. doi: 10.1186/s40168-020-00808-x. PubMed PMID: 32245390; PubMed Central PMCID: PMC7126354. + +- [pplacer](https://matsen.fhcrc.org/pplacer/) + +> Matsen FA, Kodner RB, Armbrust EV. pplacer: linear time maximum-likelihood and Bayesian phylogenetic placement of sequences onto a fixed reference tree. BMC Bioinformatics. 2010;11:538. doi: 10.1186/1471-2105-11-538. PubMed PMID: 21034504; PubMed Central PMCID: PMC3098090. + +- [BUSCO](https://busco.ezlab.org) + +> Manni M, Berkeley MR, Seppey M, Simão FA, Zdobnov EM. BUSCO Update: Novel and Streamlined Workflows along with Broader and Deeper Phylogenetic Coverage for Scoring of Eukaryotic, Prokaryotic, and Viral Genomes. Mol Biol Evol. 2021;38(10):4647-4654. doi: 10.1093/molbev/msab199. PubMed PMID: 34320186; PubMed Central PMCID: PMC8476166. + +> Tegenfeldt F, Kuznetsov D, Manni M, Berkeley M, Zdobnov EM, Kriventseva EV. OrthoDB and BUSCO update: annotation of orthologs with wider sampling of genomes. Nucleic Acids Res. 2025;53(D1):D516-D522. doi: 10.1093/nar/gkae987. PubMed PMID: 39535043. + - [CAT and BAT](https://doi.org/10.1186/s13059-019-1817-x) > von Meijenfeldt FAB, Arkhipova K, Cambuy DD, Coutinho FH, Dutilh BE. Robust taxonomic classification of uncharted microbial sequences and bins with CAT and BAT. Genome Biol. 2019;20(1):217. doi: 10.1186/s13059-019-1817-x. PubMed PMID: 31640809; PubMed Central PMCID: PMC6805573. diff --git a/conf/containers_docker_arm64.config b/conf/containers_docker_arm64.config index 369f743a..11a7ab95 100644 --- a/conf/containers_docker_arm64.config +++ b/conf/containers_docker_arm64.config @@ -1 +1,2 @@ +process { withName: 'FALINT' { container = 'community.wave.seqera.io/library/fa-lint:1.2.0--9dec293ee366e2bd' } } process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--5c84a5000a226ab5' } } diff --git a/conf/modules.config b/conf/modules.config index 2f08f47d..1bb9b531 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -124,6 +124,20 @@ process { ] } + withName: 'EUKCC_SINGLE' { + publishDir = [ + path: { "${params.outdir}/${params.mode}/${meta.id}/eukcc" }, + mode: params.publish_dir_mode, + pattern: "*_eukcc_results/eukcc.tsv", + ] + } + + withName: 'GUNZIP_FASTA' { + publishDir = [ + enabled: false + ] + } + withName: 'CHECKM2_PREDICT' { publishDir = [ path: { "${params.outdir}/${params.mode}/${meta.id}/checkm2" }, diff --git a/conf/test_mag_no_rna_presence.conf b/conf/test_mag_no_rna_presence.conf index 1577455b..43c8ed78 100644 --- a/conf/test_mag_no_rna_presence.conf +++ b/conf/test_mag_no_rna_presence.conf @@ -23,7 +23,8 @@ params { config_profile_description = 'Single-case MAG test with missing RNA_presence value' // Input data - input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_rna_presence.csv' + //input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_rna_presence.csv' + input = '/Users/kates/Desktop/EBI/MGnify/pipelines/seqsubmit/conf/mag_no_rna_presence.csv' mode = "mags" submission_study = "PRJEB98843" diff --git a/docs/methods.md b/docs/methods.md index 1504fa1e..3462b7a1 100644 --- a/docs/methods.md +++ b/docs/methods.md @@ -42,10 +42,12 @@ The `GENOMESUBMIT` workflow: 1. Reads the samplesheet and associated genome FASTA files. 2. Validates genome FASTA files. -3. Reuses provided or calculates missing values for tRNA and rRNA genes presence, coverage, taxonomy, and genome quality metrics. -4. Collects genome metadata into the tabular format required by `genome_uploader`. -5. Generates submission manifests for ENA. -6. Performs submission to ENA. +3. Reuses provided or calculates missing values for coverage and taxonomy. +4. Assigns the domain of each genome (bacteria, archaea or eukaryote) from its taxonomy. +5. Reuses provided or calculates missing values for tRNA and rRNA genes presence and genome quality metrics, using domain-specific tools and settings. +6. Collects genome metadata into the tabular format required by `genome_uploader`. +7. Generates submission manifests for ENA. +8. Performs submission to ENA. ### Genome FASTA validation @@ -53,6 +55,30 @@ Genome FASTA files are validated with the `fa-lint` before downstream processing Only FASTA files that pass validation are retained for downstream processing and submission. +### Genome coverage calculation + +Entries that already contain `genome_coverage` are passed through unchanged. For entries where coverage is missing, the workflow joins validated FASTA files with their associated read files and runs `coverm genome` through the `COVERM_GENOME` module (single-end or paired-end mode is selected from sample metadata). + +Genome coverage values from `coverm genome` output TSV are parsed and merged into submission metadata. + +### Taxonomy assignment + +If `NCBI_lineage` is already present in the input samplesheet, the value is retained. If it is missing, the workflow runs taxonomy classification using the `CAT_pack` tool. + +Before classification, input FASTA files are normalized to a `.fasta` suffix by `RENAME_FASTA_FOR_CATPACK`. Classification is then run in bin mode (`CAT_pack bins`, followed by `CAT_pack add_names`). + +Database input is taken from `--cat_db` when provided; otherwise the workflow builds CAT_pack database from NCBI non-redundant protein database (`nr`). See [CAT_pack documentation](https://github.com/MGXlab/CAT_pack#downloading-preconstructed-database-files). There are two options available: `nr` - NCBI non-redundant protein database and `gtdb` (Genome Taxonomy Database (GTDB) proteins). We use NCBI proteins because ENA supports only NCBI format of taxonomy for submission. The resulting classification table is parsed, and the lineage field is written to `NCBI_lineage`. + +### Domain assignment + +After taxonomy assignment, the workflow decides the domain of each genome from `NCBI_lineage`, which is either provided in the samplesheet or assigned by `CAT_pack`: + +- `euk` (eukaryote) if the lineage contains `Eukaryota` or the NCBI taxonomy ID `2759` +- `arc` (archaea) if the lineage contains `Archaea` or the NCBI taxonomy ID `2157` +- `bac` (bacteria) otherwise + +The domain defines which tools and settings are used for tRNA and rRNA genes detection and for completeness and contamination assessment. + ### tRNA and rRNA genes detection The workflow only runs tRNA and rRNA genes detection for entries where the `RNA_presence` column is empty. If a value is already supplied in the samplesheet, that value is passed through unchanged. @@ -65,11 +91,16 @@ tRNA and rRNA genes detection is implemented through the `RNA_DETECTION` subwork - `tRNAscan-SE` for tRNA prediction - the custom `count_rna.py` script for the final decision +All three steps use the domain assigned to the genome (see [Domain assignment](#domain-assignment)). + #### rRNA detection -`barrnap` is run in bacterial mode (`"bac"`). +`barrnap` is run with `--kingdom` matching the domain of the genome: `bac`, `arc` or `euk`. + +The custom parser then scans the GFF output and keeps only the rRNA subunits required for the domain: -The custom parser then scans the GFF output and keeps only the following rRNA subunits: `16S_rRNA`, `23S_rRNA`, `5S_rRNA`. +- bacteria and archaea: `16S_rRNA`, `23S_rRNA`, `5S_rRNA` +- eukaryotes: `18S_rRNA`, `28S_rRNA`, `5_8S_rRNA`, `5S_rRNA` For each detected feature, the recovered length is calculated as: @@ -82,6 +113,9 @@ The recovered proportion of each subunit is then estimated relative to the expec - `16S_rRNA`: 1450 bp - `23S_rRNA`: 2800 bp - `5S_rRNA`: 115 bp +- `18S_rRNA`: 1800 bp +- `28S_rRNA`: 4500 bp +- `5_8S_rRNA`: 155 bp $$ \text{recovery percent} = \frac{\text{recovered length}}{\text{expected length}} \times 100 @@ -93,7 +127,7 @@ A subunit is considered present when its best recovered percentage is greater th #### tRNA detection -`tRNAscan-SE` produces a statistics report that is parsed by `count_rna.py`. +`tRNAscan-SE` is run in the search mode matching the domain of the genome: `-B` (bacteria), `-A` (archaea) or `-E` (eukaryotes). It produces a statistics report that is parsed by `count_rna.py`. The parser sums the counts assigned to the 20 standard amino-acid isotypes: @@ -108,29 +142,36 @@ The total number of predicted tRNAs is compared against `params.trna_limit`. The The final decision stored in `RNA_presence` is: -- `True` when at least 18 tRNAs are detected and all three required rRNA subunits pass the recovery threshold +- `True` when at least 18 tRNAs are detected and all rRNA subunits required for the domain pass the recovery threshold - `False` otherwise The final `True`/`False` decision is then merged back into the submission metadata. -### Genome coverage calculation +### Completeness and contamination assessment -Entries that already contain `genome_coverage` are passed through unchanged. For entries where coverage is missing, the workflow joins validated FASTA files with their associated read files and runs `coverm genome` through the `COVERM_GENOME` module (single-end or paired-end mode is selected from sample metadata). +Completeness and contamination are evaluated together in a shared genome quality step implemented in the `GENOME_EVALUATION` subworkflow. -Genome coverage values from `coverm genome` output TSV are parsed and merged into submission metadata. +The workflow checks three samplesheet fields: `completeness`, `contamination`, and `stats_generation_software`. If all three are already present, those values are reused. If any of them is missing, the genome is analysed with a tool selected by its domain. -### Taxonomy assignment +#### Prokaryotes (bacteria and archaea) -If `NCBI_lineage` is already present in the input samplesheet, the value is retained. If it is missing, the workflow runs taxonomy classification using the `CAT_pack` tool. +Prokaryotic genomes are analysed with `CheckM2 predict`. If `--checkm2_db` is supplied and exists, that database is used directly. Otherwise, the workflow downloads a CheckM2 database from Zenodo (using `--checkm2_db_download_id`) and then runs prediction. The database is downloaded only if there is at least one prokaryotic genome to analyse. -Before classification, input FASTA files are normalized to a `.fasta` suffix by `RENAME_FASTA_FOR_CATPACK`. Classification is then run in bin mode (`CAT_pack bins`, followed by `CAT_pack add_names`). +Completeness and contamination are extracted from the generated quality report (`quality_report.tsv`). -Database input is taken from `--cat_db` when provided; otherwise the workflow builds CAT_pack database from NCBI non-redundant protein database (`nr`). See [CAT_pack documentation](https://github.com/MGXlab/CAT_pack#downloading-preconstructed-database-files). There are two options available: `nr` - NCBI non-redundant protein database and `gtdb` (Genome Taxonomy Database (GTDB) proteins). We use NCBI proteins because ENA supports only NCBI format of taxonomy for submission. The resulting classification table is parsed, and the lineage field is written to `NCBI_lineage`. +#### Eukaryotes -### Completeness and contamination assessment +Eukaryotic genomes are analysed with [EukCC](https://github.com/EBI-Metagenomics/EukCC) and, optionally, [BUSCO](https://busco.ezlab.org). The tool used for completeness is set by `--eukaryotic_completeness_tool` (`eukcc` by default). Contamination is always calculated by EukCC. + +- `eukcc`: `eukcc single` is run on the uncompressed genome and both completeness and contamination are taken from `eukcc.tsv`. +- `busco`: `BUSCO` is run in `genome` mode with the lineage set by `--busco_db_lineage` (`auto_euk` by default). Completeness is taken from `results` → `Complete percentage` of the BUSCO short summary JSON. With automatic lineage selection, the summary of the selected specific lineage is used. Contamination is taken from EukCC. + +If `contamination` is already present in the samplesheet, it is kept. With `busco`, EukCC is then skipped for that genome, as only completeness has to be calculated. With `eukcc`, EukCC still runs to calculate completeness. + +The EukCC database (`--eukcc_db`) and BUSCO lineage dataset (`--busco_db`) can be given as a folder or as a `.tar.gz`/`.tgz` archive (local path or URL). Archives are extracted by the pipeline, only if there is at least one eukaryotic genome that needs the tool. If `--busco_db` is not provided, BUSCO downloads the lineage dataset itself. -Completeness and contamination are evaluated together in a shared genome quality step. +EukCC exit codes `201` (no marker genes found) and `204` (MetaEuk predicted zero proteins) are not treated as errors: the genome is kept, and its completeness and contamination stay empty. Any other non-zero exit code fails the run. If BUSCO finds no genes and writes no short summary, completeness stays empty. -The workflow checks three samplesheet fields: `completeness`, `contamination`, and `stats_generation_software`. If all three are already present, those values are reused. If any of them is missing, the genome is analysed with `CheckM2 predict`. If `--checkm2_db` is supplied and exists, that database is used directly. Otherwise, the workflow downloads a CheckM2 database from Zenodo (using the configured database ID) and then runs prediction. +#### `stats_generation_software` -For records that run `CheckM2`, completeness and contamination are extracted from the generated quality report (`quality_report.tsv`) and used `CheckM2` version is recorded as `stats_generation_software`. +The tools whose results are used are recorded in `stats_generation_software` as `_v`, separated by `;`, for example `checkm2_v1.1.0`, `eukcc_v2.2.0` or `busco_v6.1.0;eukcc_v2.2.0`. If `stats_generation_software` is already present in the samplesheet, the tools launched by the pipeline are appended to it, e.g. `CustomTool_v1.0;busco_v6.1.0`. diff --git a/docs/output.md b/docs/output.md index 50a28c12..073efa31 100644 --- a/docs/output.md +++ b/docs/output.md @@ -21,13 +21,16 @@ When `--mode mags` or `--mode bins` is used, results are written under `mags/` o - `upload/genomes_accessions.tsv`: accessions assigned to submitted genomes. - `upload/genomes_metadata.tsv`: tabular metadata gathered for submission. - `upload/manifests/`: manifests generated by `genome_uploader`. - - `databases/checkm2/`: downloaded CheckM2 database file (when downloaded during the run). + - `databases/checkm2/`: downloaded CheckM2 database file (when downloaded during the run, only if prokaryotic genomes are present). - `databases/cat_pack/`: prepared CAT_pack database directories (when generated during the run). - `/coverage/`: `coverm genome` output for samples where `genome_coverage` had to be computed. - - `/rna/barrnap/`: `barrnap` output GFF for samples where `RNA_presence` had to be inferred. + - `/rna/barrnap/`: `barrnap` output GFF for samples where `RNA_presence` had to be inferred (run with the kingdom matching the genome domain). - `/rna/trnascanse/`: `tRNAscan-SE` outputs for the same RNA inference step. - `/taxonomy/`: CAT/BAT taxonomic classification for samples where `NCBI_lineage` was missing. - - `/checkm2/`: CheckM2 reports for samples where completeness/contamination metadata had to be computed. + - `/checkm2/`: CheckM2 report (`_checkm2_report.tsv`) for prokaryotic (bacteria and archaea) samples where completeness/contamination metadata had to be computed. + - `/eukcc/`: EukCC results (`_eukcc_results/eukcc.tsv`) for eukaryotic samples where completeness/contamination metadata had to be computed. Not created with `--eukaryotic_completeness_tool busco` if `contamination` was provided in the samplesheet. + - `/busco/-/`: BUSCO short summaries (`.txt`, `.json`), batch summary and log for eukaryotic samples, only with `--eukaryotic_completeness_tool busco`. + - `/busco/busco_downloads/lineages/`: BUSCO lineage datasets used in the run, only with `--save_busco_db`. - `/upload/webin_cli/`: Webin-CLI wrapper output TSV with accessions for submitted genomes. diff --git a/docs/usage.md b/docs/usage.md index efd25471..a580c4f7 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -308,7 +308,7 @@ mag_001,data/mag_001.fasta.gz,SRR24458089,,,SPAdes 3.15.5,MetaBAT2 2.15,default, | `assembly_software` | Yes | Tool name and version that were used to generate the source metagenomic assembly, e.g. MEGAHIT_v1.0, SPAdes_v4.0.0, metaSPAdes_v3.15.0. | | `binning_software` | Yes | Tool name and version that was used to bin data, e.g. MetaBAT2_v1.0, VAMB_2.0, MaxBin2_v1, CONCOCT_v3.0, SemiBin2_v1, COMEBin_v2.3.4, etc. | | `binning_parameters` | Yes | Arguments used to bin data different from default, e.g. -min_contig_length 1000, otherwise use 'default'. | -| `stats_generation_software` | No | Tool, including version, that was used to calculate completeness and contamination, e.g. CheckM2_v1.0.0. | +| `stats_generation_software` | No | Tool, including version, that was used to calculate completeness and contamination, e.g. CheckM2_v1.0.0. Several tools are separated by `;`, e.g. busco_v6.1.0;eukcc_v2.2.0. If the pipeline runs additional tools for this genome, they are appended to the provided value. | | `completeness` | No | MAG/bin completeness score: the 0<= ratio <= 100 of observed single-copy marker genes to total single-copy marker genes in chosen marker gene set (%). ENA docs: https://ena-docs.readthedocs.io/en/latest/faq/metagenomes.html#how-is-the-quality-of-a-metagenomic-assembly-defined. | | `contamination` | No | MAG/bin contamination score: the 0<= ratio <= 100 of observed single-copy marker genes in ≥2 copies to total single-copy marker genes in chosen marker gene set (%). ENA docs: https://ena-docs.readthedocs.io/en/latest/faq/metagenomes.html#how-is-the-quality-of-a-metagenomic-assembly-defined. | | `genome_coverage` | Conditional | Estimated average sequencing depth (>0) across the genome. If the value is missing, it is computed automatically during pipeline execution when reads are provided. | @@ -317,7 +317,7 @@ mag_001,data/mag_001.fasta.gz,SRR24458089,,,SPAdes 3.15.5,MetaBAT2 2.15,default, | `broad_environment` | Yes | Broad ecological context of the sample, for example 'marine biome', 'desert biome'. It is recommended to use subclasses of EnvO 'biome' class (http://purl.obolibrary.org/obo/ENVO_00000428). Documentation: https://github.com/EnvironmentOntology/envo/wiki/Using-ENVO-with-MIxS. | | `local_environment` | Yes | Local environmental context of the sample, for example 'tropical dry broadleaf forest biome', 'marine abyssal zone biome'. It is recommended to use EnvO terms which are of smaller spatial grain than your entry for "broad-scale environmental context". Documentation: https://github.com/EnvironmentOntology/envo/wiki/Using-ENVO-with-MIxS. | | `environmental_medium` | Yes | Material surrounding and in contact with the sample, for example 'mucus', 'lake water'. It is recommended to use subclasses of EnvO 'environmental material' class (http://purl.obolibrary.org/obo/ENVO_00010483). Documentation: https://github.com/EnvironmentOntology/envo/wiki/Using-ENVO-with-MIxS. | -| `RNA_presence` | No | Presence or absence of the 23S, 16S, and 5S rRNA genes and at least 18 tRNAs. This is used for MISAG/MIMAG assembly quality classification. Options: true or false. | +| `RNA_presence` | No | Presence or absence of the 23S, 16S, and 5S rRNA genes (prokaryotes) or the 28S, 18S, 5.8S and 5S rRNA genes (eukaryotes) and at least 18 tRNAs. This is used for MISAG/MIMAG assembly quality classification. Options: true or false. | | `NCBI_lineage` | No | Full NCBI lineage - format: x;y;z. For example, the lineage for E. coli can be: 'Bacteria;Pseudomonadati;Pseudomonadota;Gammaproteobacteria;Enterobacterales;Enterobacteriaceae;Escherichia' or '2;1224;1236;91347;543;561;562'. For more info check https://www.ncbi.nlm.nih.gov/datasets/docs/v2/data-processing/taxonomy-processing/taxonomy/. | > [!NOTE] @@ -325,9 +325,9 @@ mag_001,data/mag_001.fasta.gz,SRR24458089,,,SPAdes 3.15.5,MetaBAT2 2.15,default, If `genome_coverage`, `stats_generation_software`, `completeness`, `contamination`, `RNA_presence`, or `NCBI_lineage` are missing, the workflow can calculate or infer them when the required inputs are available. See the [Methods documentation](docs/methods.md) for more information on how metadata statistics are obtained. -### Preparing the CheckM2 and CAT_pack databases +### Preparing the CheckM2, EukCC, BUSCO and CAT_pack databases -`mags` and `bins` submission modes use CheckM2 and CAT_pack tools that require specialized databases for completeness/contamination assessment and taxonomy assignment. +`mags` and `bins` submission modes use CheckM2 (prokaryotes), EukCC and optionally BUSCO (eukaryotes) and CAT_pack tools that require specialized databases for completeness/contamination assessment and taxonomy assignment. You can either provide pre-existing databases or let the pipeline prepare them during execution. @@ -337,10 +337,16 @@ In particular, the CAT_pack database is extremely large and may take a long time - CheckM2: - provide the path to a local database with `--checkm2_db`, otherwise the pipeline downloads the version specified with `--checkm2_db_download_id` (by default Zenodo accession `14897628`). +- EukCC (required only if eukaryotic genomes are present and their completeness/contamination has to be calculated): + - provide the database with `--eukcc_db` as an uncompressed folder or as a `.tar.gz`/`.tgz` archive (local path or URL, e.g. `http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz`). Archives are extracted by the pipeline in every run, so we recommend downloading and extracting the database once and providing the folder. + +- BUSCO (used only with `--eukaryotic_completeness_tool busco`): + - provide a lineage dataset with `--busco_db` as a local folder or as a `.tar.gz`/`.tgz` archive (local path or URL), otherwise BUSCO downloads the lineage set by `--busco_db_lineage` during the run (requires an internet connection). A folder is expected to have the structure `/lineages/_odb(10|12)`. + - CAT_pack: - provide the path to a local database (containing `tax/` and `db/` folders or a `tar.gz` archive) with `--cat_db`, otherwise the pipeline builds CAT_pack DB from NCBI non-redundant protein database (`nr`). -See the [CAT_pack documentation](https://github.com/MGXlab/CAT_pack) and [CheckM2 documentation](https://github.com/chklovski/CheckM2) for more details on usage and creation of databases. +See the [CAT_pack documentation](https://github.com/MGXlab/CAT_pack), [CheckM2 documentation](https://github.com/chklovski/CheckM2), [EukCC documentation](https://eukcc.readthedocs.io) and [BUSCO documentation](https://busco.ezlab.org/busco_userguide.html) for more details on usage and creation of databases. Databases created/downloaded by the pipeline are published under: `/databases/`. In subsequent pipeline runs you can reuse them using `--cat_db /databases/cat_pack/` and `--checkm2_db /databases/checkm2/`. @@ -349,11 +355,17 @@ Databases created/downloaded by the pipeline are published under: In addition to the [common parameters](#running-the-pipeline): -| Parameter | Required | Description | -| -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--upload_tpa` | No | Mark assemblies as [third party assemblies (TPA)](#third-party-assemblies-tpa) when required. Default: `false`. | -| `--checkm2_db` | No | Path to a pre-downloaded CheckM2 database. If omitted, downloads the version set by `--checkm2_db_download_id`. Default: `14897628` (Zenodo accession). | -| `--cat_db` | No | Path to a local CAT_pack database. If omitted, builds CAT_pack DB from NCBI non-redundant protein database (`nr`). | +| Parameter | Required | Description | +| -------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--upload_tpa` | No | Mark assemblies as [third party assemblies (TPA)](#third-party-assemblies-tpa) when required. Default: `false`. | +| `--checkm2_db` | No | Path to a pre-downloaded CheckM2 database. If omitted, downloads the version set by `--checkm2_db_download_id`. Default: `14897628` (Zenodo accession). | +| `--cat_db` | No | Path to a local CAT_pack database. If omitted, builds CAT_pack DB from NCBI non-redundant protein database (`nr`). | +| `--eukaryotic_completeness_tool` | No | Tool to calculate completeness of eukaryotic MAGs/bins: `eukcc` or `busco`. Contamination is always calculated by EukCC. Default: `eukcc`. | +| `--eukcc_db` | Conditional | EukCC database folder or `.tar.gz`/`.tgz` archive (local path or URL). Required if eukaryotic genomes without completeness/contamination are present. | +| `--busco_db` | No | BUSCO lineage dataset folder or `.tar.gz`/`.tgz` archive (local path or URL). Used only with `--eukaryotic_completeness_tool busco`. If omitted, BUSCO downloads the lineage set by `--busco_db_lineage`. | +| `--busco_db_lineage` | No | BUSCO `*_odb10`/`*_odb12` lineage to check against, or `auto`, `auto_prok`, `auto_euk` for automatic lineage selection. Default: `auto_euk`. | +| `--save_busco_db` | No | Save BUSCO lineage datasets used in the run to the output directory. Default: `false`. | +| `--busco_clean` | No | Remove BUSCO intermediate files to reduce the number of files in the work directory. Default: `false`. | Example `mags` mode upload to TEST server, run command with docker: @@ -375,7 +387,14 @@ nextflow run nf-core/seqsubmit \ - **Co-assemblies**: MAGs/bins generated from co-assemblies are not supported. The pipeline currently expects each MAG/bin to be derived from an assembly generated from a single run. Tracked in [issue #61](https://github.com/nf-core/seqsubmit/issues/61). -- **Eukaryotic and viral bins/MAGs**: Submitting eukaryotic or viral genomes that require additional metadata generation is not supported. For such genomes tRNA and rRNA prediction, quality assessment (completeness/contamination estimation) and taxonomy assignment are not implemented. If all the required metadata (`completeness`, `contamination`, `stats_generation_software`, `RNA_presence` and `NCBI_lineage`) is already provided in the samplesheet, eukaryotic and viral bins/MAGs can still be submitted normally. Tracked in [issue #40](https://github.com/nf-core/seqsubmit/issues/40) (eukaryotic) and [issue #63](https://github.com/nf-core/seqsubmit/issues/63) (viral). +- **Viral bins/MAGs**: Submitting viral genomes that require additional metadata generation is not supported. For such genomes tRNA and rRNA prediction, quality assessment (completeness/contamination estimation) and taxonomy assignment are not implemented. If all the required metadata (`completeness`, `contamination`, `stats_generation_software`, `RNA_presence` and `NCBI_lineage`) is already provided in the samplesheet, viral bins/MAGs can still be submitted normally. Tracked in [issue #63](https://github.com/nf-core/seqsubmit/issues/63). + +- **Domain assignment**: the domain of each genome (bacteria, archaea or eukaryote) is decided from `NCBI_lineage` (provided in the samplesheet or assigned by CAT_pack). Genomes whose lineage does not contain Eukaryota/`2759` or Archaea/`2157` are processed as bacteria, so a missing or incorrect lineage leads to prokaryotic tools being used for that genome. + +- **Eukaryotic bins/MAGs**: + - EukCC database (`--eukcc_db`) has to be provided, it is not downloaded automatically. + - BUSCO is used only for completeness, contamination is always taken from EukCC (or from the samplesheet). + - If EukCC finds no marker genes or MetaEuk predicts no proteins for a genome, completeness and contamination stay empty for that genome. The same happens for completeness when BUSCO finds no genes. - **Submission of a MAG/bin without submitting the assembly or raw reads**: If a MAG/bin cannot be traced back to an assembly accession or a reads accession — i.e. only a sample accession is available — it cannot currently be submitted, since the pipeline relies on that lineage to build the required metadata. Tracked in [issue #87](https://github.com/nf-core/seqsubmit/issues/87). @@ -385,7 +404,7 @@ nextflow run nf-core/seqsubmit \ ## Scalability -Some processes in this pipeline are resource intensive — in particular coverage calculation (CoverM), quality assessment (CheckM2), and taxonomic classification of MAGs/bins (BAT). For real-world data, these steps should be run on an HPC cluster or another compute environment with sufficient CPU, memory, and job scheduling capacity, rather than on a single local machine. +Some processes in this pipeline are resource intensive — in particular coverage calculation (CoverM), quality assessment (CheckM2, EukCC, BUSCO), and taxonomic classification of MAGs/bins (BAT). For real-world data, these steps should be run on an HPC cluster or another compute environment with sufficient CPU, memory, and job scheduling capacity, rather than on a single local machine. Depending on the resources available on your machine or cluster, you will likely need to adapt the Nextflow configuration to limit the maximum number of concurrently running jobs and other resource settings using [resourceLimits](https://nf-co.re/docs/developing/institutional-profiles/configuration#resource-limits) in a custom config, so that the pipeline does not try to claim more resources than are actually available. See the [nf-core configuration documentation](https://nf-co.re/docs/usage/getting_started/configuration) for guidance on writing a custom config for your infrastructure. diff --git a/modules/local/eukcc/single/environment.yml b/modules/local/eukcc/single/environment.yml new file mode 100644 index 00000000..f35538cd --- /dev/null +++ b/modules/local/eukcc/single/environment.yml @@ -0,0 +1,13 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + # versions match the container community.wave.seqera.io/library/python_metaeuk_pplacer_epa-ng_pruned:0b7ea587ebcad440 + - bioconda::epa-ng=0.3.8 + - bioconda::eukcc=2.2.0 + - bioconda::hmmer=3.3 + - bioconda::metaeuk=4.a0f584d + - bioconda::pplacer=1.1.alpha19 + - conda-forge::python=3.8.12 diff --git a/modules/local/eukcc/single/main.nf b/modules/local/eukcc/single/main.nf index 68413b0e..5f9d7282 100644 --- a/modules/local/eukcc/single/main.nf +++ b/modules/local/eukcc/single/main.nf @@ -1,7 +1,8 @@ process EUKCC_SINGLE { + tag "${meta.id}" + conda "${moduleDir}/environment.yml" container 'community.wave.seqera.io/library/python_metaeuk_pplacer_epa-ng_pruned:0b7ea587ebcad440' - tag "${meta.id}" input: tuple val(meta), path(fasta) diff --git a/modules/local/eukcc/single/meta.yml b/modules/local/eukcc/single/meta.yml new file mode 100644 index 00000000..662cb635 --- /dev/null +++ b/modules/local/eukcc/single/meta.yml @@ -0,0 +1,129 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "eukcc_single" +description: Estimate completeness and contamination of a single eukaryotic genome or MAG with EukCC +keywords: + - eukaryotes + - mag + - metagenome + - quality + - completeness + - contamination +tools: + - "eukcc": + description: "EukCC - completeness and contamination estimation for eukaryotic genomes using marker genes" + homepage: "https://github.com/EBI-Metagenomics/EukCC" + documentation: "https://eukcc.readthedocs.io" + doi: "10.1186/s13059-020-02155-4" + licence: ["GPL v3"] + identifier: "" + - "metaeuk": + description: "MetaEuk - gene discovery and annotation of eukaryotic contigs, used by EukCC to predict proteins" + homepage: "https://github.com/soedinglab/metaeuk" + doi: "10.1186/s40168-020-00808-x" + licence: ["GPL v3"] + identifier: biotools:MetaEuk + - "pplacer": + description: "pplacer - phylogenetic placement of sequences on a reference tree, used by EukCC to select the lineage marker set" + homepage: "https://matsen.fhcrc.org/pplacer/" + doi: "10.1186/1471-2105-11-538" + licence: ["GPL v3"] + identifier: biotools:pplacer +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', domain:'euk' ]` + - fasta: + type: file + description: Uncompressed nucleotide FASTA file of the genome + pattern: "*.{fasta,fna,fa}" + ontologies: + - edam: http://edamontology.org/format_1929 # FASTA + - - meta_db: + type: map + description: | + Groovy Map containing database information + e.g. `[ id:'eukcc_db' ]` + - eukcc_db: + type: directory + description: Uncompressed EukCC database directory (e.g. eukcc2_db_ver_1.1) +output: + eukcc_tsv: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', domain:'euk' ]` + - ${prefix}_eukcc_results/eukcc.tsv: + type: file + description: | + Tab-separated table with columns fasta, completeness, contamination, ncbi_lng. + Contains only the header if EukCC exited with code 201 (no marker genes found) + or 204 (MetaEuk predicted zero proteins). + pattern: "*_eukcc_results/eukcc.tsv" + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + versions_eukcc: + - - ${task.process}: + type: string + description: The name of the process + - eukcc: + type: string + description: The name of the tool + - 'eukcc -v 2>&1 | grep -oE "[0-9]+\\.[0-9]+\\.[0-9]+" | head -n1': + type: eval + description: The expression to obtain the version of the tool + versions_metaeuk: + - - ${task.process}: + type: string + description: The name of the process + - metaeuk: + type: string + description: The name of the tool + - 'metaeuk -h 2>&1 | grep "Version" | sed "s/.*Version: //"': + type: eval + description: The expression to obtain the version of the tool + versions_pplacer: + - - ${task.process}: + type: string + description: The name of the process + - pplacer: + type: string + description: The name of the tool + - "pplacer --version": + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - eukcc: + type: string + description: The name of the tool + - 'eukcc -v 2>&1 | grep -oE "[0-9]+\\.[0-9]+\\.[0-9]+" | head -n1': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - metaeuk: + type: string + description: The name of the tool + - 'metaeuk -h 2>&1 | grep "Version" | sed "s/.*Version: //"': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - pplacer: + type: string + description: The name of the tool + - "pplacer --version": + type: eval + description: The expression to obtain the version of the tool +authors: + - "@KateSakharova" +maintainers: + - "@KateSakharova" diff --git a/modules/nf-core/busco/busco/main.nf b/modules/nf-core/busco/busco/main.nf index 2cd01c63..81d2e4eb 100644 --- a/modules/nf-core/busco/busco/main.nf +++ b/modules/nf-core/busco/busco/main.nf @@ -67,7 +67,8 @@ process BUSCO_BUSCO { export BUSCO_BBTOOLS_MEMORY=${bbtools_memory} # Fix Augustus for Apptainer - ENV_AUGUSTUS=/opt/conda/etc/conda/activate.d/augustus.sh + #ENV_AUGUSTUS=/opt/conda/etc/conda/activate.d/augustus.sh + ENV_AUGUSTUS=/opt/wave/.pixi/envs/default/etc/conda/activate.d/augustus.sh set +u if [ -z "\${AUGUSTUS_CONFIG_PATH}" ] && [ -f "\${ENV_AUGUSTUS}" ]; then source "\${ENV_AUGUSTUS}" diff --git a/subworkflows/local/genome_evaluation/main.nf b/subworkflows/local/genome_evaluation/main.nf index d10d4ce3..9a0d2222 100644 --- a/subworkflows/local/genome_evaluation/main.nf +++ b/subworkflows/local/genome_evaluation/main.nf @@ -68,20 +68,31 @@ workflow GENOME_EVALUATION { // ------ Eukaryotes + // Contamination can only be calculated by EukCC. If contamination is already given in the samplesheet + // and BUSCO calculates completeness, EukCC is skipped for that genome. + // Without BUSCO, EukCC runs as usual for completeness and contamination from the samplesheet is kept. + euks_split = domain_split_fasta.euks + .branch { meta, _fasta -> + busco_only: eukaryotic_completeness_tool == 'busco' && meta.contamination != null + eukcc: true + } + // Databases for eukaryotes can be given as a directory or as a .tar.gz/.tgz archive (local path or URL). - // Archives are extracted with a single DB_UNTAR step, only if there is at least one eukaryotic genome. + // Archives are extracted with a single DB_UNTAR step, only if there is at least one genome that needs the tool. // BUSCO database directory is expected to have the structure `/lineages/_odb(10|12)` def busco_db_file = (eukaryotic_completeness_tool == 'busco' && busco_db) ? file(busco_db, checkIfExists: true) : null def eukcc_db_file = eukcc_db ? file(eukcc_db, checkIfExists: true) : null ch_db_archives = domain_split_fasta.euks .first() - .flatMap { _meta, _fasta -> - [ - [[id: 'busco_db'], busco_db_file], - [[id: 'eukcc_db'], eukcc_db_file] - ].findAll { _db_meta, db -> isArchive(db) } - } + .filter { _meta, _fasta -> isArchive(busco_db_file) } + .map { _meta, _fasta -> [[id: 'busco_db'], busco_db_file] } + .mix( + euks_split.eukcc + .first() + .filter { _meta, _fasta -> isArchive(eukcc_db_file) } + .map { _meta, _fasta -> [[id: 'eukcc_db'], eukcc_db_file] } + ) DB_UNTAR ( ch_db_archives ) @@ -104,21 +115,23 @@ workflow GENOME_EVALUATION { } // Run EukCC for completeness and contamination of eukaryotes - // Database is required only when there is at least one eukaryotic genome + // Database is required only when there is at least one eukaryotic genome to run EukCC on def eukcc_database = eukcc_db_file ? prepareDatabase(eukcc_db_file, 'eukcc_db', DB_UNTAR.out.untar) - : domain_split_fasta.euks.first().map { _meta, _fasta -> + : euks_split.eukcc.first().map { _meta, _fasta -> error("Eukaryotic genomes were found, but --eukcc_db is not provided. Please provide the EukCC database.") } - GUNZIP_FASTA ( domain_split_fasta.euks ) + GUNZIP_FASTA ( euks_split.eukcc ) EUKCC_SINGLE ( GUNZIP_FASTA.out.gunzip, eukcc_database ) - // ------ Combine completeness and contamination from both tools into one channel + // ------ Combine completeness and contamination from all tools into one channel + // Tools are listed in stats_generation_software separated by ';'. + // If stats_generation_software is given in the samplesheet, launched tools are appended to it. // Software name with version, e.g. checkm2_v1.0.2, assigned per tool def checkm2_software = CHECKM2_PREDICT.out.versions_checkm2_predict @@ -131,10 +144,44 @@ workflow GENOME_EVALUATION { ch_prok_stats = CHECKM2_PREDICT.out.checkm2_tsv .combine(checkm2_software) .map { meta, table, software -> parseStatsTable(meta, table, software) } + .map { meta, completeness, contamination, software -> + [ meta, completeness, contamination, mergeSoftware(meta.stats_generation_software, [software]) ] + } - ch_euk_stats = EUKCC_SINGLE.out.eukcc_tsv + // [ meta, completeness, contamination, software ], contamination from the samplesheet is kept if present + ch_eukcc_stats = EUKCC_SINGLE.out.eukcc_tsv .combine(eukcc_software) .map { meta, table, software -> parseStatsTable(meta, table, software) } + .map { meta, completeness, contamination, software -> + [ meta, completeness, meta.contamination != null ? meta.contamination : contamination, software ] + } + + if (eukaryotic_completeness_tool == 'busco') { + // With BUSCO activated, completeness is taken from BUSCO and contamination from EukCC or samplesheet + def busco_software = BUSCO_BUSCO.out.versions_busco + .map { _process_name, tool_name, version -> "${tool_name}_v${version}" } + .first() + def ch_busco_completeness = BUSCO_BUSCO.out.short_summaries_json + .map { meta, summaries -> [ meta, parseBuscoCompleteness(summaries) ] } + + // BUSCO short summary is optional (no genes found) and EukCC is skipped for busco_only genomes - + // remainder keeps every eukaryotic genome, missing results are null + ch_euk_stats = domain_split_fasta.euks + .map { meta, _fasta -> [ meta, true ] } + .join(ch_busco_completeness, remainder: true) + .join(ch_eukcc_stats.map { meta, completeness, contamination, software -> [ meta, [completeness, contamination, software] ] }, remainder: true) + .combine(busco_software) + .map { meta, _is_euk, busco_completeness, eukcc_stats, busco_sw -> + def contamination = eukcc_stats ? eukcc_stats[1] : meta.contamination + def tools = [ busco_sw, eukcc_stats ? eukcc_stats[2] : null ] + [ meta, busco_completeness, contamination, mergeSoftware(meta.stats_generation_software, tools) ] + } + } else { + ch_euk_stats = ch_eukcc_stats + .map { meta, completeness, contamination, software -> + [ meta, completeness, contamination, mergeSoftware(meta.stats_generation_software, [software]) ] + } + } emit: stats = ch_prok_stats.mix(ch_euk_stats) // channel: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] @@ -187,3 +234,24 @@ def parseStatsTable(meta, table, software) { software ] } + +// +// Read completeness ([results][Complete percentage]) from BUSCO short_summary json. +// With auto-lineage BUSCO writes a generic and a specific summary - the specific lineage is preferred. +// +def parseBuscoCompleteness(summaries) { + def summary_files = summaries instanceof List ? summaries : [summaries] + def summary = summary_files.find { json -> json.name.startsWith('short_summary.specific.') } ?: summary_files[0] + def completeness = new groovy.json.JsonSlurper().parseText(summary.text)?.results?.get('Complete percentage') + return completeness != null ? completeness.toString() : null +} + +// +// Join software names with ';', appending launched tools to the software given in the samplesheet. +// Duplicates and empty values are removed, e.g. "CheckM2_v1.0.0;eukcc_v2.2.0" +// +def mergeSoftware(existing, tools) { + def existing_tools = existing ? existing.toString().tokenize(';').collect { tool -> tool.trim() } : [] + def merged = (existing_tools + tools.findAll { tool -> tool }.collect { tool -> tool.toString() }).unique() + return merged ? merged.join(';') : null +} diff --git a/subworkflows/local/genome_evaluation/tests/main.nf.test b/subworkflows/local/genome_evaluation/tests/main.nf.test new file mode 100644 index 00000000..6387367f --- /dev/null +++ b/subworkflows/local/genome_evaluation/tests/main.nf.test @@ -0,0 +1,253 @@ +nextflow_workflow { + + name "Test Subworkflow GENOME_EVALUATION" + script "../main.nf" + workflow "GENOME_EVALUATION" + + tag "subworkflows" + tag "subworkflows_local" + tag "subworkflows/genome_evaluation" + tag "checkm2" + tag "checkm2/predict" + tag "checkm2/databasedownload" + tag "busco" + tag "busco/busco" + tag "eukcc" + tag "untar" + tag "gunzip" + + test("mixed domains - eukcc - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of( + [ + [ id:'test_bac', domain:'bac' ], + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ], + [ + [ id:'test_euk', domain:'euk' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ] + ) + input[1] = null // checkm2_db - triggers CHECKM2_DATABASEDOWNLOAD + input[2] = 14897628 // checkm2_db_download_id + input[3] = 'auto_euk' // busco_db_lineage + input[4] = null // busco_db + input[5] = true // busco_clean + input[6] = 'eukcc' // eukaryotic_completeness_tool + input[7] = params.modules_testdata_base_path + 'genomics/sarscov2/genome/db/kraken2.tar.gz' // eukcc_db - any archive works in stub mode + """ + } + } + + then { + assert workflow.success + def stats = workflow.out.stats.collectEntries { meta, completeness, contamination, software -> [ (meta.id): [completeness, contamination, software] ] } + assertAll( + { assert snapshot(workflow.out.stats.sort { it[0].id }).match() }, + { assert workflow.out.stats.size() == 2 }, + // CheckM2 stub writes an empty report - no values; EukCC stub writes one row + { assert stats['test_bac'][0] == null }, + { assert stats['test_bac'][2].startsWith('checkm2_v') }, + { assert stats['test_euk'][0] == '90.0' }, // fake values assigned by eukcc in -stub + { assert stats['test_euk'][1] == '1.0' }, // fake values assigned by eukcc in -stub + { assert stats['test_euk'][2].startsWith('eukcc_v') } + ) + } + + } + + test("prokaryotes only - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of( + [ + [ id:'test_bac', domain:'bac' ], + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ], + [ + [ id:'test_arc', domain:'arc' ], + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ] + ) + input[1] = null + input[2] = 14897628 + input[3] = 'auto_euk' + input[4] = null + input[5] = true + input[6] = 'eukcc' + input[7] = null // eukcc_db is not required without eukaryotes + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.stats.sort { it[0].id }).match() }, + { assert workflow.out.stats.size() == 2 }, + { assert workflow.out.stats.every { it[3].startsWith('checkm2_v') } }, + // CheckM2 database is downloaded once for all prokaryotes + { assert workflow.trace.tasks().count { it.name.contains('CHECKM2_DATABASEDOWNLOAD') } == 1 }, + // no eukaryotes - eukaryotic steps must not run + { assert !workflow.trace.tasks().any { it.name =~ /EUKCC|BUSCO|DB_UNTAR|GUNZIP_FASTA/ } } + ) + } + + } + + test("eukaryote - busco - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_euk', domain:'euk' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = null + input[2] = 14897628 + input[3] = 'auto_euk' + input[4] = null // busco_db - BUSCO downloads lineages itself + input[5] = true + input[6] = 'busco' + input[7] = params.modules_testdata_base_path + 'genomics/sarscov2/genome/db/kraken2.tar.gz' + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.stats).match() }, + { assert workflow.out.stats.size() == 1 }, + // completeness is taken from BUSCO - stub writes no short summary json, so it is empty + { assert workflow.out.stats[0][1] == null }, + // contamination is always taken from EukCC + { assert workflow.out.stats[0][2] == '1.0' }, + { assert workflow.out.stats[0][3] ==~ /busco_v[^;]+;eukcc_v[^;]+/ }, + // no prokaryotes - CheckM2 database must not be downloaded + { assert !workflow.trace.tasks().any { it.name.contains('CHECKM2') } }, + { assert workflow.trace.tasks().any { it.name.contains('BUSCO_BUSCO') } } + ) + } + + } + + test("eukaryote with contamination - busco - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_euk', domain:'euk', contamination:2.5, stats_generation_software:'CustomTool_v1.0' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = null + input[2] = 14897628 + input[3] = 'auto_euk' + input[4] = null + input[5] = true + input[6] = 'busco' + input[7] = null // eukcc_db is not required - EukCC is skipped + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.stats).match() }, + { assert workflow.out.stats.size() == 1 }, + // completeness from BUSCO (stub - empty), contamination kept from samplesheet + { assert workflow.out.stats[0][1] == null }, + { assert workflow.out.stats[0][2] == 2.5 }, + // BUSCO is appended to the software given in samplesheet, EukCC is not listed + { assert workflow.out.stats[0][3] ==~ /CustomTool_v1\.0;busco_v[^;]+/ }, + { assert !workflow.trace.tasks().any { it.name =~ /EUKCC|GUNZIP_FASTA|DB_UNTAR/ } }, + { assert workflow.trace.tasks().any { it.name.contains('BUSCO_BUSCO') } } + ) + } + + } + + test("eukaryote with contamination - eukcc - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_euk', domain:'euk', contamination:2.5, stats_generation_software:'CustomTool_v1.0' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = null + input[2] = 14897628 + input[3] = 'auto_euk' + input[4] = null + input[5] = true + input[6] = 'eukcc' + input[7] = params.modules_testdata_base_path + 'genomics/sarscov2/genome/db/kraken2.tar.gz' + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.stats).match() }, + { assert workflow.out.stats.size() == 1 }, + // completeness from EukCC, contamination kept from samplesheet + { assert workflow.out.stats[0][1] == '90.0' }, + { assert workflow.out.stats[0][2] == 2.5 }, + { assert workflow.out.stats[0][3] ==~ /CustomTool_v1\.0;eukcc_v[^;]+/ }, + { assert workflow.trace.tasks().any { it.name.contains('EUKCC_SINGLE') } } + ) + } + + } + + test("eukaryote - no eukcc_db - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_euk', domain:'euk' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = null + input[2] = 14897628 + input[3] = 'auto_euk' + input[4] = null + input[5] = true + input[6] = 'eukcc' + input[7] = null // eukcc_db missing while eukaryotes are present + """ + } + } + + then { + assert workflow.failed + assert workflow.stdout.any { it.contains('--eukcc_db is not provided') } || + workflow.stderr.any { it.contains('--eukcc_db is not provided') } + } + + } + +} diff --git a/subworkflows/local/genome_evaluation/tests/main.nf.test.snap b/subworkflows/local/genome_evaluation/tests/main.nf.test.snap new file mode 100644 index 00000000..7bb94311 --- /dev/null +++ b/subworkflows/local/genome_evaluation/tests/main.nf.test.snap @@ -0,0 +1,124 @@ +{ + "eukaryote - busco - stub": { + "content": [ + [ + [ + { + "id": "test_euk", + "domain": "euk" + }, + null, + "1.0", + "busco_v6.1.0;eukcc_v2.2.0" + ] + ] + ], + "timestamp": "2026-10-20T10:38:25.344278", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + }, + "prokaryotes only - stub": { + "content": [ + [ + [ + { + "id": "test_arc", + "domain": "arc" + }, + null, + null, + "checkm2_v1.1.0" + ], + [ + { + "id": "test_bac", + "domain": "bac" + }, + null, + null, + "checkm2_v1.1.0" + ] + ] + ], + "timestamp": "2026-10-20T10:01:14.903614", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + }, + "eukaryote with contamination - eukcc - stub": { + "content": [ + [ + [ + { + "id": "test_euk", + "domain": "euk", + "contamination": 2.5, + "stats_generation_software": "CustomTool_v1.0" + }, + "90.0", + 2.5, + "CustomTool_v1.0;eukcc_v2.2.0" + ] + ] + ], + "timestamp": "2026-10-20T10:38:53.012231", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + }, + "mixed domains - eukcc - stub": { + "content": [ + [ + [ + { + "id": "test_bac", + "domain": "bac" + }, + null, + null, + "checkm2_v1.1.0" + ], + [ + { + "id": "test_euk", + "domain": "euk" + }, + "90.0", + "1.0", + "eukcc_v2.2.0" + ] + ] + ], + "timestamp": "2026-10-20T09:53:08.084333", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + }, + "eukaryote with contamination - busco - stub": { + "content": [ + [ + [ + { + "id": "test_euk", + "domain": "euk", + "contamination": 2.5, + "stats_generation_software": "CustomTool_v1.0" + }, + null, + 2.5, + "CustomTool_v1.0;busco_v6.1.0" + ] + ] + ], + "timestamp": "2026-10-20T10:38:42.005927", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + } +} \ No newline at end of file diff --git a/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf b/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf index d4e930e3..24e7854c 100644 --- a/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf @@ -209,7 +209,10 @@ def toolCitationText() { ].join(' ').trim() def stats_tools = [ - params.mode == "bins" || params.mode == "mags" ? "Completeness and contamination metrics was performed by CheckM2 (Chklovski et al. 2023)." : "", + params.mode == "bins" || params.mode == "mags" ? "Completeness and contamination metrics for prokaryotic genomes were calculated by CheckM2 (Chklovski et al. 2023)." : "", + params.mode == "bins" || params.mode == "mags" ? "Contamination metrics for eukaryotic genomes were calculated by EukCC (Saary et al. 2020), which uses MetaEuk (Levy Karin et al. 2020) and pplacer (Matsen et al. 2010)." : "", + (params.mode == "bins" || params.mode == "mags") && params.eukaryotic_completeness_tool == "busco" ? "Completeness metrics for eukaryotic genomes were calculated by BUSCO (Manni et al. 2021; Tegenfeldt et al. 2025)." : "", + (params.mode == "bins" || params.mode == "mags") && params.eukaryotic_completeness_tool != "busco" ? "Completeness metrics for eukaryotic genomes were calculated by EukCC (Saary et al. 2020)." : "", params.mode == "metagenomic_assemblies" ? "Coverage calculation for metagenomic assemblies was done by CoverM contig (Aroney et el. 2025)." : "", params.mode == "bins" || params.mode == "mags" ? "Coverage calculation for bins/MAGs was done by CoverM genome (Aroney et el. 2025)." : "" ].join(' ').trim() @@ -219,7 +222,7 @@ def toolCitationText() { ].join(' ').trim() def rna_tools = [ - params.mode == "bins" || params.mode == "mags" ? "Bacterial ribosomal RNA prediction was performed by barrnap (Seemann T. 2013)." : "", + params.mode == "bins" || params.mode == "mags" ? "Ribosomal RNA prediction was performed by barrnap (Seemann T. 2013)." : "", params.mode == "bins" || params.mode == "mags" ? "Transfer RNA genes were detected by tRNAscan-SE (Chan et al. 2021)." : "" ].join(' ').trim() @@ -246,6 +249,11 @@ def toolBibliographyText() { '
  • Edwards, R. (2023). linsalrob/py_fasta_validator: Compressy. doi: 10.5281/zenodo.5002710
  • ', '
  • Chklovski, A., Parks, D. H., Woodcroft, B. J., & Tyson, G. W. (2023). CheckM2: a rapid, scalable and accurate tool for assessing microbial genome quality using machine learning. Nature Methods, 20(8), 1203-1212. doi: 10.1038/s41592-023-01940-w
  • ', '
  • Aroney, S. T., Newell, R. J., Nissen, J. N., Camargo, A. P., Tyson, G. W., & Woodcroft, B. J. (2025). CoverM: read alignment statistics for metagenomics. Bioinformatics, 41(4), btaf147. doi: 10.1093/bioinformatics/btaf147
  • ', + '
  • Saary, P., Mitchell, A. L., & Finn, R. D. (2020). Estimating the quality of eukaryotic genomes recovered from metagenomic analysis with EukCC. Genome Biology, 21(1), 244. doi: 10.1186/s13059-020-02155-4
  • ', + '
  • Levy Karin, E., Mirdita, M., & Söding, J. (2020). MetaEuk—sensitive, high-throughput gene discovery, and annotation for large-scale eukaryotic metagenomics. Microbiome, 8(1), 48. doi: 10.1186/s40168-020-00808-x
  • ', + '
  • Matsen, F. A., Kodner, R. B., & Armbrust, E. V. (2010). pplacer: linear time maximum-likelihood and Bayesian phylogenetic placement of sequences onto a fixed reference tree. BMC Bioinformatics, 11, 538. doi: 10.1186/1471-2105-11-538
  • ', + params.eukaryotic_completeness_tool == "busco" ? '
  • Manni, M., Berkeley, M. R., Seppey, M., Simão, F. A., & Zdobnov, E. M. (2021). BUSCO Update: Novel and Streamlined Workflows along with Broader and Deeper Phylogenetic Coverage for Scoring of Eukaryotic, Prokaryotic, and Viral Genomes. Molecular Biology and Evolution, 38(10), 4647-4654. doi: 10.1093/molbev/msab199
  • ' : "", + params.eukaryotic_completeness_tool == "busco" ? '
  • Tegenfeldt, F., Kuznetsov, D., Manni, M., Berkeley, M., Zdobnov, E. M., & Kriventseva, E. V. (2025). OrthoDB and BUSCO update: annotation of orthologs with wider sampling of genomes. Nucleic Acids Research, 53(D1), D516-D522. doi: 10.1093/nar/gkae987
  • ' : "", '
  • Von Meijenfeldt, F. B., Arkhipova, K., Cambuy, D. D., Coutinho, F. H., & Dutilh, B. E. (2019). Robust taxonomic classification of uncharted microbial sequences and bins with CAT and BAT. Genome biology, 20(1), 217. doi: 10.1038/s41467-024-47155-1
  • ', '
  • Seemann, T. (2014). barrnap: Bacterial ribosomal RNA predictor. barrnap: Bacterial ribosomal RNA predictor. vicbioinformatics.com
  • ', '
  • Chan, P. P., Lin, B. Y., Mak, A. J., & Lowe, T. M. (2021). tRNAscan-SE 2.0: improved detection and functional classification of transfer RNA genes. Nucleic acids research, 49(16), 9077-9096. doi: 10.1093/nar/gkab688
  • ', From e541c4803fc5a12576a3314d0fef8fb8d12ed41b Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Tue, 20 Oct 2026 11:28:51 +0100 Subject: [PATCH 09/24] add patch for busco --- conf/containers_docker_arm64.config | 1 - modules.json | 8 ++----- modules/nf-core/busco/busco/busco-busco.diff | 22 ++++++++++++++++++++ nextflow.config | 2 +- 4 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 modules/nf-core/busco/busco/busco-busco.diff diff --git a/conf/containers_docker_arm64.config b/conf/containers_docker_arm64.config index 11a7ab95..369f743a 100644 --- a/conf/containers_docker_arm64.config +++ b/conf/containers_docker_arm64.config @@ -1,2 +1 @@ -process { withName: 'FALINT' { container = 'community.wave.seqera.io/library/fa-lint:1.2.0--9dec293ee366e2bd' } } process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--5c84a5000a226ab5' } } diff --git a/modules.json b/modules.json index f1308bd3..dc27d29d 100644 --- a/modules.json +++ b/modules.json @@ -13,12 +13,8 @@ "busco/busco": { "branch": "master", "git_sha": "3927a974459b80b8e24d73e00da029e8c7335c4d", - "installed_by": ["modules"] - }, - "busco/download": { - "branch": "master", - "git_sha": "3927a974459b80b8e24d73e00da029e8c7335c4d", - "installed_by": ["modules"] + "installed_by": ["modules"], + "patch": "modules/nf-core/busco/busco/busco-busco.diff" }, "catpack/addnames": { "branch": "master", diff --git a/modules/nf-core/busco/busco/busco-busco.diff b/modules/nf-core/busco/busco/busco-busco.diff new file mode 100644 index 00000000..58a9a795 --- /dev/null +++ b/modules/nf-core/busco/busco/busco-busco.diff @@ -0,0 +1,22 @@ +Changes in component 'nf-core/busco/busco' +'modules/nf-core/busco/busco/environment.yml' is unchanged +'modules/nf-core/busco/busco/meta.yml' is unchanged +Changes in 'busco/busco/main.nf': +--- modules/nf-core/busco/busco/main.nf ++++ modules/nf-core/busco/busco/main.nf +@@ -67,7 +67,8 @@ + export BUSCO_BBTOOLS_MEMORY=${bbtools_memory} + + # Fix Augustus for Apptainer +- ENV_AUGUSTUS=/opt/conda/etc/conda/activate.d/augustus.sh ++ #ENV_AUGUSTUS=/opt/conda/etc/conda/activate.d/augustus.sh ++ ENV_AUGUSTUS=/opt/wave/.pixi/envs/default/etc/conda/activate.d/augustus.sh + set +u + if [ -z "\${AUGUSTUS_CONFIG_PATH}" ] && [ -f "\${ENV_AUGUSTUS}" ]; then + source "\${ENV_AUGUSTUS}" + +'modules/nf-core/busco/busco/tests/main.nf.test.snap' is unchanged +'modules/nf-core/busco/busco/tests/nextflow.config' is unchanged +'modules/nf-core/busco/busco/tests/main.nf.test' is unchanged +'modules/nf-core/busco/busco/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt' is unchanged +************************************************************ diff --git a/nextflow.config b/nextflow.config index c7fd9673..3a0f19f3 100644 --- a/nextflow.config +++ b/nextflow.config @@ -36,7 +36,7 @@ params { save_busco_db = false busco_clean = false // -- eukcc - eukcc_db = null + eukcc_db = 'http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz' // NCBI taxonomy cat_db = null From 9b96c39a891b751ef35c26f86c48b19b3ab763af Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Wed, 21 Oct 2026 18:56:19 +0100 Subject: [PATCH 10/24] split genome_evaluation into proks and euks, added some tests (not finished yet) --- conf/containers_conda_lock_files_amd64.config | 2 +- conf/containers_conda_lock_files_arm64.config | 2 +- conf/containers_docker_amd64.config | 2 +- conf/containers_docker_arm64.config | 1 + conf/test_mag_no_quality_euk.conf | 46 +++++ conf/test_mag_no_rna_presence.conf | 2 +- docs/methods.md | 2 +- modules/local/eukcc/single/environment.yml | 2 +- modules/local/eukcc/single/main.nf | 6 +- nextflow.config | 5 +- nextflow_schema.json | 39 ++-- ro-crate-metadata.json | 2 +- subworkflows/local/genome_evaluation/meta.yml | 55 ------ .../main.nf | 93 ++-------- .../local/genome_evaluation_euks/meta.yml | 64 +++++++ .../tests/main.nf.test | 173 +++++++----------- .../tests/main.nf.test.snap | 48 +---- .../local/genome_evaluation_proks/main.nf | 71 +++++++ .../local/genome_evaluation_proks/meta.yml | 46 +++++ .../tests/main.nf.test | 106 +++++++++++ .../tests/main.nf.test.snap | 52 ++++++ .../utils_nfcore_seqsubmit_pipeline/main.nf | 26 +++ tests/mag_no_rna_presence.nf.test | 14 ++ workflows/genomesubmit.nf | 29 ++- 24 files changed, 571 insertions(+), 317 deletions(-) create mode 100644 conf/test_mag_no_quality_euk.conf delete mode 100644 subworkflows/local/genome_evaluation/meta.yml rename subworkflows/local/{genome_evaluation => genome_evaluation_euks}/main.nf (70%) create mode 100644 subworkflows/local/genome_evaluation_euks/meta.yml rename subworkflows/local/{genome_evaluation => genome_evaluation_euks}/tests/main.nf.test (52%) rename subworkflows/local/{genome_evaluation => genome_evaluation_euks}/tests/main.nf.test.snap (62%) create mode 100644 subworkflows/local/genome_evaluation_proks/main.nf create mode 100644 subworkflows/local/genome_evaluation_proks/meta.yml create mode 100644 subworkflows/local/genome_evaluation_proks/tests/main.nf.test create mode 100644 subworkflows/local/genome_evaluation_proks/tests/main.nf.test.snap diff --git a/conf/containers_conda_lock_files_amd64.config b/conf/containers_conda_lock_files_amd64.config index efe310c7..4dc7cf67 100644 --- a/conf/containers_conda_lock_files_amd64.config +++ b/conf/containers_conda_lock_files_amd64.config @@ -1,2 +1,2 @@ process { withName: 'BUSCO_BUSCO' { container = 'modules/nf-core/busco/busco/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt' } } -process { withName: 'MULTIQC' { container = 'modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt' } } +process { withName: 'MULTIQC' { conda = 'modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt' } } \ No newline at end of file diff --git a/conf/containers_conda_lock_files_arm64.config b/conf/containers_conda_lock_files_arm64.config index 6864e0b1..707b0e4d 100644 --- a/conf/containers_conda_lock_files_arm64.config +++ b/conf/containers_conda_lock_files_arm64.config @@ -1 +1 @@ -process { withName: 'MULTIQC' { container = 'modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt' } } +process { withName: 'MULTIQC' { conda = 'modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt' } } \ No newline at end of file diff --git a/conf/containers_docker_amd64.config b/conf/containers_docker_amd64.config index 7668fe46..8d2bb8d5 100644 --- a/conf/containers_docker_amd64.config +++ b/conf/containers_docker_amd64.config @@ -1,2 +1,2 @@ process { withName: 'BUSCO_BUSCO' { container = 'community.wave.seqera.io/library/busco:6.1.0--6d1f7006d91892b3' } } -process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc' } } +process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc' } } \ No newline at end of file diff --git a/conf/containers_docker_arm64.config b/conf/containers_docker_arm64.config index 369f743a..11a7ab95 100644 --- a/conf/containers_docker_arm64.config +++ b/conf/containers_docker_arm64.config @@ -1 +1,2 @@ +process { withName: 'FALINT' { container = 'community.wave.seqera.io/library/fa-lint:1.2.0--9dec293ee366e2bd' } } process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--5c84a5000a226ab5' } } diff --git a/conf/test_mag_no_quality_euk.conf b/conf/test_mag_no_quality_euk.conf new file mode 100644 index 00000000..194dc7a7 --- /dev/null +++ b/conf/test_mag_no_quality_euk.conf @@ -0,0 +1,46 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for running minimal tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines input files and everything required to run a fast and simple pipeline test. + + Use as follows: + nextflow run nf-core/seqsubmit -profile test, --outdir + +---------------------------------------------------------------------------------------- +*/ + +process { + resourceLimits = [ + cpus: 2, + memory: '12.GB', + time: '1.h' + ] + + withName: 'EUKCC_SINGLE' { + ext.args = '--clade fungi --simple' + } + + withName: 'REGISTERSTUDY|SUBMIT|ENA_WEBIN_CLI_WRAPPER' { + ext.when = false + } +} + +params { + config_profile_name = 'Test --mode mags no_quality profile' + config_profile_description = 'Single-case eukaryotic MAG test with missing completeness and contamination values' + + // Input data + //input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_quality.csv' + input = 'https://raw.githubusercontent.com/KateSakharova/test-datasets/refs/heads/feature/add-euks/samplesheets/mag_no_quality_euk.csv' + + mode = "mags" + submission_study = "TEST_STUDY" + centre_name = "TEST_CENTER" + + test_upload = true + + // Using fungi DB only from EukCC + eukcc_db = 'https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz' + +} diff --git a/conf/test_mag_no_rna_presence.conf b/conf/test_mag_no_rna_presence.conf index 43c8ed78..bc58f017 100644 --- a/conf/test_mag_no_rna_presence.conf +++ b/conf/test_mag_no_rna_presence.conf @@ -24,7 +24,7 @@ params { // Input data //input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_rna_presence.csv' - input = '/Users/kates/Desktop/EBI/MGnify/pipelines/seqsubmit/conf/mag_no_rna_presence.csv' + input = 'https://raw.githubusercontent.com/KateSakharova/test-datasets/refs/heads/feature/add-euks/samplesheets/mag_no_rna_presence.csv' mode = "mags" submission_study = "PRJEB98843" diff --git a/docs/methods.md b/docs/methods.md index 3462b7a1..d56fc25a 100644 --- a/docs/methods.md +++ b/docs/methods.md @@ -149,7 +149,7 @@ The final `True`/`False` decision is then merged back into the submission metada ### Completeness and contamination assessment -Completeness and contamination are evaluated together in a shared genome quality step implemented in the `GENOME_EVALUATION` subworkflow. +Completeness and contamination are evaluated in a genome quality step split by domain: prokaryotic genomes go to the `GENOME_EVALUATION_PROKS` subworkflow and eukaryotic genomes to the `GENOME_EVALUATION_EUKS` subworkflow. The workflow checks three samplesheet fields: `completeness`, `contamination`, and `stats_generation_software`. If all three are already present, those values are reused. If any of them is missing, the genome is analysed with a tool selected by its domain. diff --git a/modules/local/eukcc/single/environment.yml b/modules/local/eukcc/single/environment.yml index f35538cd..67914348 100644 --- a/modules/local/eukcc/single/environment.yml +++ b/modules/local/eukcc/single/environment.yml @@ -4,7 +4,7 @@ channels: - conda-forge - bioconda dependencies: - # versions match the container community.wave.seqera.io/library/python_metaeuk_pplacer_epa-ng_pruned:0b7ea587ebcad440 + # versions match the container quay.io/biocontainers/eukcc:2.2.0--pyhdfd78af_0 - bioconda::epa-ng=0.3.8 - bioconda::eukcc=2.2.0 - bioconda::hmmer=3.3 diff --git a/modules/local/eukcc/single/main.nf b/modules/local/eukcc/single/main.nf index 5f9d7282..4512e30c 100644 --- a/modules/local/eukcc/single/main.nf +++ b/modules/local/eukcc/single/main.nf @@ -1,8 +1,10 @@ process EUKCC_SINGLE { + tag "${meta.id}" + label 'process_high' conda "${moduleDir}/environment.yml" - container 'community.wave.seqera.io/library/python_metaeuk_pplacer_epa-ng_pruned:0b7ea587ebcad440' + container 'quay.io/biocontainers/eukcc:2.2.0--pyhdfd78af_0' input: tuple val(meta), path(fasta) @@ -12,7 +14,7 @@ process EUKCC_SINGLE { tuple val(meta), path("${prefix}_eukcc_results/eukcc.tsv"), emit: eukcc_tsv tuple val("${task.process}"), val('eukcc'), eval('eukcc -v 2>&1 | grep -oE "[0-9]+\\.[0-9]+\\.[0-9]+" | head -n1'), emit: versions_eukcc, topic: versions tuple val("${task.process}"), val('metaeuk'), eval('metaeuk -h 2>&1 | grep "Version" | sed "s/.*Version: //"'), emit: versions_metaeuk, topic: versions - tuple val("${task.process}"), val('pplacer'), eval ('pplacer --version'), emit: versions_pplacer, topic: versions + tuple val("${task.process}"), val('pplacer'), eval('pplacer --version'), emit: versions_pplacer, topic: versions script: def args = task.ext.args ?: '' diff --git a/nextflow.config b/nextflow.config index 3a0f19f3..1d10e6ea 100644 --- a/nextflow.config +++ b/nextflow.config @@ -26,16 +26,18 @@ params { trna_limit = 18 // completeness and contamination - eukaryotic_completeness_tool = 'eukcc' + // --- prokaryotes // -- checkm2 checkm2_db = null checkm2_db_download_id = 14897628 + // --- eukaryotes // -- busco busco_db = null busco_db_lineage = 'auto_euk' save_busco_db = false busco_clean = false // -- eukcc + eukaryotic_completeness_tool = 'eukcc' eukcc_db = 'http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz' // NCBI taxonomy @@ -255,6 +257,7 @@ profiles { test_mag_no_coverage_single_reads { includeConfig 'conf/test_mag_no_coverage_single_reads.conf' } test_mag_no_coverage_paired_reads { includeConfig 'conf/test_mag_no_coverage_paired_reads.conf' } test_mag_no_quality { includeConfig 'conf/test_mag_no_quality.conf' } + test_mag_no_quality_euk { includeConfig 'conf/test_mag_no_quality_euk.conf' } test_mag_one_contig { includeConfig 'conf/test_mag_one_contig.conf' } test_mag_no_rna_presence { includeConfig 'conf/test_mag_no_rna_presence.conf' } test_mag_no_taxonomy { includeConfig 'conf/test_mag_no_taxonomy.conf' } diff --git a/nextflow_schema.json b/nextflow_schema.json index f44688bf..15f1a867 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -78,12 +78,12 @@ } } }, - "genome_evaluation_options": { - "title": "Evaluation options", + "genome_evaluation_options_proks": { + "title": "Prokaryotic genome evaluation options", "type": "object", "fa_icon": "fas fa-university", - "description": "Parameters used to run Checkm2", - "help_text": "These options are used to run Checkm2 that will calculate completeness and contamination of genome if those were not provided as input", + "description": "Parameters used to run CheckM2 on prokaryotic genomes", + "help_text": "These options are used to run CheckM2, which calculates completeness and contamination of prokaryotic (bacterial and archaeal) genomes if those values were not provided in the samplesheet.", "properties": { "checkm2_db": { "format": "file-path", @@ -95,17 +95,26 @@ "description": "Zenodo ID for CheckM2 database download", "default": 14897628, "fa_icon": "fas fa-users-cog" - }, + } + } + }, + "genome_evaluation_options_euks": { + "title": "Eukaryotic genome evaluation options", + "type": "object", + "fa_icon": "fas fa-university", + "description": "Parameters used to run EukCC and BUSCO on eukaryotic genomes", + "help_text": "These options are used to calculate completeness and contamination of eukaryotic genomes if those values were not provided in the samplesheet. By default, EukCC calculates both completeness and contamination. With `--eukaryotic_completeness_tool busco`, completeness is calculated by BUSCO, and contamination is calculated by EukCC (or taken from the samplesheet if provided).", + "properties": { "busco_db": { "type": "string", - "description": "Download URL, local tar.gz archive, or local uncompressed directory for an *_odb10 or *_odb12 BUSCO lineage dataset.", - "help_text": "E.g. https://busco-data.ezlab.org/v5/data/lineages/bacteria_odb10.2024-01-08.tar.gz, `/path/to/bacteria_odb10.2024-01-08.tar.gz`.\n\nFor more details, check the [BUSCO section in the usage documentation](https://nf-co.re/mag/latest/docs/usage/#busco).", + "description": "Download URL, local tar.gz archive, or local uncompressed directory for an *_odb10 or *_odb12 BUSCO lineage dataset. Used only with `--eukaryotic_completeness_tool busco`.", + "help_text": "Download BUSCO database in tar.gz archive, e.g. https://busco-data.ezlab.org/v5/data/lineages/eukaryota_odb10.2024-01-08.tar.gz, `/path/to/eukaryota_odb10.2024-01-08.tar.gz`.\n\nFor more details, check the [BUSCO section in the usage documentation](https://nf-co.re/mag/latest/docs/usage/#busco).", "format": "path", "exists": true }, "busco_db_lineage": { "type": "string", - "description": "Name of the BUSCO *_odb10 or *_odb12 lineage to check against. Additionally supports 'auto', 'auto_prok' and 'auto_euk' for automatic lineage selection mode.", + "description": "Name of the BUSCO *_odb10 or *_odb12 lineage to check eukaryotic genomes against. Additionally supports 'auto', 'auto_prok' and 'auto_euk' for automatic lineage selection mode. Used only with `--eukaryotic_completeness_tool busco`.", "help_text": "Typically used in combination with `--busco_db`, corresponding to the lineage files supplied within the `--busco_db` file or directory.\n\nIf supplying without a `--busco_db`, will require an internet connection to work!", "pattern": "(.*_odb(10|12))|auto(_prok|_euk)?$", "default": "auto_euk" @@ -124,15 +133,16 @@ }, "eukcc_db": { "type": "string", - "description": "Path to EukCC database folder or .tar.gz/.tgz archive (local path or URL).", + "description": "Path to EukCC database folder or .tar.gz/.tgz archive (local path or URL), used for eukaryotic genomes.", "help_text": "EukCC database, e.g. http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz. Can be given as an uncompressed folder, or as a .tar.gz/.tgz archive (local path or URL) that will be extracted by the pipeline. Required if there are eukaryotic genomes. To avoid downloading it in every run, download and extract it once and provide the folder.", "format": "path", - "exists": true + "exists": true, + "default": "http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz" }, "eukaryotic_completeness_tool": { "type": "string", - "description": "Name of the tool to compute completeness for eukaryotic MAGs/bins. Choice: eukcc or busco. Default: eukcc", - "help_text": "Completeness of eukaryotic MAGs/bins can be calculated using eukcc or busco.", + "description": "Tool used to calculate completeness of eukaryotic MAGs/bins: eukcc or busco.", + "help_text": "Contamination of eukaryotic MAGs/bins is always calculated by EukCC (unless provided in the samplesheet). Completeness is calculated by EukCC by default, or by BUSCO if `busco` is selected.", "enum": ["eukcc", "busco"], "default": "eukcc" } @@ -375,7 +385,10 @@ "$ref": "#/$defs/rna_detection_options" }, { - "$ref": "#/$defs/genome_evaluation_options" + "$ref": "#/$defs/genome_evaluation_options_proks" + }, + { + "$ref": "#/$defs/genome_evaluation_options_euks" }, { "$ref": "#/$defs/taxonomy_assignment_options" diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index 2e5a831e..59c9d61c 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -23,7 +23,7 @@ "@type": "Dataset", "creativeWorkStatus": "Stable", "datePublished": "2026-09-01T12:58:45+00:00", - "description": "

    \n \n \n \"nf-core/seqsubmit\"\n \n

    \n\n[![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/seqsubmit)\n[![GitHub Actions CI Status](https://github.com/nf-core/seqsubmit/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/seqsubmit/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/seqsubmit/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/seqsubmit/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/seqsubmit/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.4-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-4.1.0-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/4.1.0)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/seqsubmit)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23seqsubmit-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/seqsubmit)[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40nf__core-1185fe?labelColor=000000&logo=bluesky)](https://bsky.app/profile/nf-co.re)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n![seqsubmit workflow diagram](docs/images/seqsubmit_schema.png)\n\n**nf-core/seqsubmit** is a Nextflow pipeline for submitting sequence data to [ENA](https://www.ebi.ac.uk/ena/browser/home).\nThe pipeline currently supports the following submission modes, each routed to a dedicated workflow:\n\n- `reads` \u2014 raw sequencing reads submission via the `READSUBMIT` workflow (pink)\n- `metagenomic_assemblies` \u2014 assembly submission via the `ASSEMBLYSUBMIT` workflow (green)\n- `mags` \u2014 metagenome-assembled genomes (MAGs) submission via the `GENOMESUBMIT` workflow (blue)\n- `bins` \u2014 bins submission via the `GENOMESUBMIT` workflow (blue)\n\n\n\nEach workflow has its own samplesheet structure, prerequisites, and limitations \u2014 they are briefly described below. See the [usage documentation](https://nf-co.re/seqsubmit/usage) for more detailed explanations.\n\n## Requirements\n\n- [Nextflow](https://www.nextflow.io/) `>=25.04.0`\n- A Webin account registered at \n\n Set your Webin credentials as Nextflow secrets:\n\n ```bash\n nextflow secrets set ENA_WEBIN \"Webin-XXX\"\n nextflow secrets set ENA_WEBIN_PASSWORD \"XXX\"\n ```\n\n Make sure to replace the values above with your own credentials.\n\n- Provide either a study accession or a study registration metadata file for the study the submission will be associated with. See the [Submission study](docs/usage.md#submission-study) section of the usage documentation for details.\n\n- Depending on the chosen mode, samples, reads, or metagenomic assemblies must be pre-submitted to ENA to obtain the corresponding accessions, which you then reference in your submission. Refer to the relevant mode section in the [usage documentation](https://nf-co.re/seqsubmit/usage) for details.\n\n## Input samplesheets\n\n### `reads` mode\n\nExample:\n\n```csv\nid,sample_accession,fastq_1,fastq_2,platform,instrument,library_source,library_selection,library_strategy,insert_size,library_name,description\nillumina_run_001,SAMEA1234567,data/reads_R1.fastq.gz,data/reads_R2.fastq.gz,ILLUMINA,Illumina HiSeq 2000,GENOMIC,RANDOM,WGS,500,HiSeq_library_001,Illumina sequencing of sample XYZ\n```\n\nSee the [`reads` mode section](docs/usage.md#samplesheet-input) of the usage documentation for more details.\n\n### `metagenomic_assemblies` mode\n\nExample:\n\n```csv\nid,fasta,fastq_1,fastq_2,coverage,run_accession,assembler,assembler_version\nassembly_1,data/contigs_1.fasta.gz,data/reads_1.fastq.gz,data/reads_2.fastq.gz,,ERR011322,SPAdes,3.15.5\nassembly_2,data/contigs_2.fasta.gz,,,42.7,ERR011323,MEGAHIT,1.2.9\n```\n\nSee the [`metagenomic_assemblies` mode section](docs/usage.md#samplesheet-input-1) of the usage documentation for more details.\n\n### `mags` and `bins` modes\n\nExample:\n\n```csv\nid,fasta,accession,fastq_1,fastq_2,assembly_software,binning_software,binning_parameters,stats_generation_software,completeness,contamination,genome_coverage,metagenome,co-assembly,broad_environment,local_environment,environmental_medium,RNA_presence,NCBI_lineage\nlachnospira_eligens,data/bin_lachnospira_eligens.fa.gz,SRR24458089,,,spades_v3.15.5,metabat2_v2.6,default,CheckM2_v1.0.1,61.0,0.21,32.07,sediment metagenome,false,marine,cable_bacteria,marine_sediment,false,d__Bacteria;p__Proteobacteria;s__unclassified_Proteobacteria\n```\n\nSee the [`mags` and `bins` modes section](docs/usage.md#samplesheet-input-2) of the usage documentation for the full list of required and optional columns.\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/get_started/environment_setup/overview) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/get_started/run-your-first-pipeline) with `-profile test` before running the workflow on actual data.\n\n### Running the pipeline\n\nEach mode also has its own additional parameters and example commands \u2014 see the [usage documentation](https://nf-co.re/seqsubmit/usage) for details. General command template:\n\n```bash\nnextflow run nf-core/seqsubmit \\\n -profile \\\n --mode \\\n --input \\\n --centre_name \\\n --submission_study \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/running/run-pipelines#using-parameter-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/seqsubmit/usage) and the [parameter documentation](https://nf-co.re/seqsubmit/parameters).\n\n## Pipeline output\n\nKey output locations in `--outdir`:\n\n- `reads/`: per-sample submission receipts and accessions\n- `metagenomic_assemblies/`: assembly metadata CSVs and per-sample coverage files\n- `mags/` or `bins/`: genome metadata, manifests, and per-sample submission support files\n- `multiqc/`: MultiQC summary report\n- `pipeline_info/`: execution reports, trace, DAG, and software versions\n\nFor full details, see the [output documentation](https://nf-co.re/seqsubmit/output).\n\n## Credits\n\nnf-core/seqsubmit was originally written by [Martin Beracochea](https://github.com/mberacochea), [Ekaterina Sakharova](https://github.com/KateSakharova), [Sofia Ochkalova](https://github.com/ochkalova) and [Tim Rozday](https://github.com/timrozday-mgnify).\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n[Evangelos Karatzas](https://github.com/vagkaratzas)\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](docs/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#seqsubmit` channel](https://nfcore.slack.com/channels/seqsubmit) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\n\n\nIf you use this pipeline please make sure to cite all used software.\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/main/LICENSE).\n\n> **MGnify: the microbiome sequence data analysis resource in 2023**\n>\n> Richardson L, Allen B, Baldi G, Beracochea M, Bileschi ML, Burdett T, et al.\n>\n> Vol. 51, Nucleic Acids Research. Oxford University Press (OUP); 2022. p. D753\u20139. Available from: http://dx.doi.org/10.1093/nar/gkac1080\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "description": "

    \n \n \n \"nf-core/seqsubmit\"\n \n

    \n\n[![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/seqsubmit)\n[![GitHub Actions CI Status](https://github.com/nf-core/seqsubmit/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/seqsubmit/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/seqsubmit/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/seqsubmit/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/seqsubmit/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.4-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-4.1.0-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/4.1.0)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/seqsubmit)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23seqsubmit-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/seqsubmit)[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40nf__core-1185fe?labelColor=000000&logo=bluesky)](https://bsky.app/profile/nf-co.re)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n![seqsubmit workflow diagram](docs/images/seqsubmit_schema.png)\n\n**nf-core/seqsubmit** is a Nextflow pipeline for submitting sequence data to [ENA](https://www.ebi.ac.uk/ena/browser/home).\nThe pipeline currently supports the following submission modes, each routed to a dedicated workflow:\n\n- `reads` \u2014 raw sequencing reads submission via the `READSUBMIT` workflow (pink)\n- `metagenomic_assemblies` \u2014 assembly submission via the `ASSEMBLYSUBMIT` workflow (green)\n- `mags` \u2014 metagenome-assembled genomes (MAGs) submission via the `GENOMESUBMIT` workflow (blue)\n- `bins` \u2014 bins submission via the `GENOMESUBMIT` workflow (blue)\n\n\n\nEach workflow has its own samplesheet structure, prerequisites, and limitations \u2014 they are briefly described below. See the [usage documentation](https://nf-co.re/seqsubmit/usage) for more detailed explanations.\n\n## Requirements\n\n- [Nextflow](https://www.nextflow.io/) `>=25.04.0`\n- A Webin account registered at \n\n Set your Webin credentials as Nextflow secrets:\n\n ```bash\n nextflow secrets set ENA_WEBIN \"Webin-XXX\"\n nextflow secrets set ENA_WEBIN_PASSWORD \"XXX\"\n ```\n\n Make sure to replace the values above with your own credentials.\n\n- Provide either a study accession or a study registration metadata file for the study the submission will be associated with. See the [Submission study](docs/usage.md#submission-study) section of the usage documentation for details.\n\n- Depending on the chosen mode, samples, reads, or metagenomic assemblies must be pre-submitted to ENA to obtain the corresponding accessions, which you then reference in your submission. Refer to the relevant mode section in the [usage documentation](https://nf-co.re/seqsubmit/usage) for details.\n\n## Input samplesheets\n\n### `reads` mode\n\nExample:\n\n```csv\nid,sample_accession,fastq_1,fastq_2,platform,instrument,library_source,library_selection,library_strategy,insert_size,library_name,description\nillumina_run_001,SAMEA1234567,data/reads_R1.fastq.gz,data/reads_R2.fastq.gz,ILLUMINA,Illumina HiSeq 2000,GENOMIC,RANDOM,WGS,500,HiSeq_library_001,Illumina sequencing of sample XYZ\n```\n\nSee the [`reads` mode section](docs/usage.md#samplesheet-input) of the usage documentation for more details.\n\n### `metagenomic_assemblies` mode\n\nExample:\n\n```csv\nid,fasta,fastq_1,fastq_2,coverage,run_accession,assembler,assembler_version,assembly_type\nassembly_1,data/contigs_1.fasta.gz,data/reads_1.fastq.gz,data/reads_2.fastq.gz,,ERR011322,SPAdes,3.15.5,metagenome\nassembly_2,data/contigs_2.fasta.gz,,,42.7,ERR011323,MEGAHIT,1.2.9,metatranscriptome\n```\n\nSee the [`metagenomic_assemblies` mode section](docs/usage.md#samplesheet-input-1) of the usage documentation for more details.\n\n### `mags` and `bins` modes\n\nExample:\n\n```csv\nid,fasta,accession,fastq_1,fastq_2,assembly_software,binning_software,binning_parameters,stats_generation_software,completeness,contamination,genome_coverage,metagenome,co-assembly,broad_environment,local_environment,environmental_medium,RNA_presence,NCBI_lineage\nlachnospira_eligens,data/bin_lachnospira_eligens.fa.gz,SRR24458089,,,spades_v3.15.5,metabat2_v2.6,default,CheckM2_v1.0.1,61.0,0.21,32.07,sediment metagenome,false,marine,cable_bacteria,marine_sediment,false,d__Bacteria;p__Proteobacteria;s__unclassified_Proteobacteria\n```\n\nSee the [`mags` and `bins` modes section](docs/usage.md#samplesheet-input-2) of the usage documentation for the full list of required and optional columns.\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/get_started/environment_setup/overview) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/get_started/run-your-first-pipeline) with `-profile test` before running the workflow on actual data.\n\n### Running the pipeline\n\nEach mode also has its own additional parameters and example commands \u2014 see the [usage documentation](https://nf-co.re/seqsubmit/usage) for details. General command template:\n\n```bash\nnextflow run nf-core/seqsubmit \\\n -profile \\\n --mode \\\n --input \\\n --centre_name \\\n --submission_study \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/running/run-pipelines#using-parameter-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/seqsubmit/usage) and the [parameter documentation](https://nf-co.re/seqsubmit/parameters).\n\n## Pipeline output\n\nKey output locations in `--outdir`:\n\n- `reads/`: per-sample submission receipts and accessions\n- `metagenomic_assemblies/`: assembly metadata CSVs and per-sample coverage files\n- `mags/` or `bins/`: genome metadata, manifests, and per-sample submission support files\n- `multiqc/`: MultiQC summary report\n- `pipeline_info/`: execution reports, trace, DAG, and software versions\n\nFor full details, see the [output documentation](https://nf-co.re/seqsubmit/output).\n\n## Credits\n\nnf-core/seqsubmit was originally written by [Martin Beracochea](https://github.com/mberacochea), [Ekaterina Sakharova](https://github.com/KateSakharova), [Sofia Ochkalova](https://github.com/ochkalova) and [Tim Rozday](https://github.com/timrozday-mgnify).\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n[Evangelos Karatzas](https://github.com/vagkaratzas)\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](docs/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#seqsubmit` channel](https://nfcore.slack.com/channels/seqsubmit) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\n\n\nIf you use this pipeline please make sure to cite all used software.\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/main/LICENSE).\n\n> **MGnify: the microbiome sequence data analysis resource in 2023**\n>\n> Richardson L, Allen B, Baldi G, Beracochea M, Bileschi ML, Burdett T, et al.\n>\n> Vol. 51, Nucleic Acids Research. Oxford University Press (OUP); 2022. p. D753\u20139. Available from: http://dx.doi.org/10.1093/nar/gkac1080\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" diff --git a/subworkflows/local/genome_evaluation/meta.yml b/subworkflows/local/genome_evaluation/meta.yml deleted file mode 100644 index 33af059b..00000000 --- a/subworkflows/local/genome_evaluation/meta.yml +++ /dev/null @@ -1,55 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json -name: "genome_evaluation" -description: | - Estimates genome completeness and contamination using CheckM2. - Downloads the CheckM2 database automatically when no pre-built database is provided. -keywords: - - genome - - completeness - - contamination - - checkm2 - - metagenomics - - MAGs - - bins -components: - - checkm2/databasedownload - - checkm2/predict -input: - - ch_fasta: - type: file - description: | - Channel containing genome FASTA files to evaluate. - Structure: [ val(meta), path(fasta) ] - pattern: "*.{fa,fasta,fna,fa.gz,fasta.gz,fna.gz}" - ontologies: - - edam: "http://edamontology.org/format_1929" # FASTA - - ch_checkm2_db: - type: directory - description: | - Channel containing a pre-built CheckM2 database directory. - Provide channel.empty() to trigger automatic download via ch_checkm2_db_download_id. - Structure: [ val(meta), path(db) ] - - ch_checkm2_db_download_id: - type: string - description: | - Channel containing the Zenodo record ID used to download the CheckM2 database - via CHECKM2_DATABASEDOWNLOAD (e.g. '1234567'). - Only used when ch_checkm2_db is channel.empty(). - Structure: [ val(meta), val(db_id) ] -output: - - genome_evaluation: - type: file - description: | - Channel containing per-genome CheckM2 quality summary TSV files. - Structure: [ val(meta), path(tsv) ] - pattern: "*.tsv" - ontologies: - - edam: "http://edamontology.org/format_3475" # TSV - - stats_versions: - type: file - description: | - Channel containing software versions from CheckM2. - Structure: versions -authors: - - "@KateSakharova" - - "@ochkalova" diff --git a/subworkflows/local/genome_evaluation/main.nf b/subworkflows/local/genome_evaluation_euks/main.nf similarity index 70% rename from subworkflows/local/genome_evaluation/main.nf rename to subworkflows/local/genome_evaluation_euks/main.nf index 9a0d2222..0879c1d1 100644 --- a/subworkflows/local/genome_evaluation/main.nf +++ b/subworkflows/local/genome_evaluation_euks/main.nf @@ -1,5 +1,5 @@ // -// Subworkflow that calculates completeness and contamination for genome +// Subworkflow that calculates completeness and contamination for eukaryotic genomes // /* @@ -10,23 +10,21 @@ include { EUKCC_SINGLE } from '../../../modules/local/eukcc/single/main' include { BUSCO_BUSCO } from '../../../modules/nf-core/busco/busco/main' -include { CHECKM2_DATABASEDOWNLOAD } from '../../../modules/nf-core/checkm2/databasedownload/main' -include { CHECKM2_PREDICT } from '../../../modules/nf-core/checkm2/predict/main' include { UNTAR as DB_UNTAR } from '../../../modules/nf-core/untar/main' include { GUNZIP as GUNZIP_FASTA } from '../../../modules/nf-core/gunzip/main' +include { parseStatsTable; mergeSoftware } from '../utils_nfcore_seqsubmit_pipeline' + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SUBWORKFLOW ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -workflow GENOME_EVALUATION { +workflow GENOME_EVALUATION_EUKS { take: - ch_fasta // channel: [ val(meta), path(fasta) ] - ch_checkm2_db // val: path to local CheckM2 database or null to trigger automatic download - ch_checkm2_db_download_id // val: CheckM2 database Zenodo download ID + ch_fasta // channel: [ val(meta), path(fasta) ] - eukaryotic genomes only busco_db_lineage // val: lineage for checking against, default: auto_euk busco_db // val: BUSCO database - local directory or .tar.gz/.tgz archive (path or URL), or null to download busco_clean // boolean: clean intermediate busco files @@ -35,43 +33,10 @@ workflow GENOME_EVALUATION { main: - // ------ split input to Prokaryotes and Eukaryotes - - domain_split_fasta = ch_fasta - .branch { meta, fasta -> - proks: meta.domain in ['arc', 'bac'] - euks: meta.domain == 'euk' - } - - // ------ Prokaryotes - - // Database preparation for checkm2 - // that step would be launched only if proks branch is not empty - ch_do_download = domain_split_fasta.proks - .first() - .map { _meta_fasta -> ch_checkm2_db_download_id } - - // Download and prepare db from scratch if no pre-built db provided - if (ch_checkm2_db) { - ch_checkm2_db_ready = channel.value([[id: 'checkm2_db'], file(ch_checkm2_db, checkIfExists: true)]) - } else { - CHECKM2_DATABASEDOWNLOAD(ch_do_download) - ch_checkm2_db_ready = CHECKM2_DATABASEDOWNLOAD.out.database - } - - // Genome evaluation with CheckM2 - - CHECKM2_PREDICT( - domain_split_fasta.proks, - ch_checkm2_db_ready, - ) - - // ------ Eukaryotes - // Contamination can only be calculated by EukCC. If contamination is already given in the samplesheet // and BUSCO calculates completeness, EukCC is skipped for that genome. // Without BUSCO, EukCC runs as usual for completeness and contamination from the samplesheet is kept. - euks_split = domain_split_fasta.euks + euks_split = ch_fasta .branch { meta, _fasta -> busco_only: eukaryotic_completeness_tool == 'busco' && meta.contamination != null eukcc: true @@ -83,7 +48,7 @@ workflow GENOME_EVALUATION { def busco_db_file = (eukaryotic_completeness_tool == 'busco' && busco_db) ? file(busco_db, checkIfExists: true) : null def eukcc_db_file = eukcc_db ? file(eukcc_db, checkIfExists: true) : null - ch_db_archives = domain_split_fasta.euks + ch_db_archives = ch_fasta .first() .filter { _meta, _fasta -> isArchive(busco_db_file) } .map { _meta, _fasta -> [[id: 'busco_db'], busco_db_file] } @@ -105,7 +70,7 @@ workflow GENOME_EVALUATION { // Genome evaluation with BUSCO BUSCO_BUSCO ( - domain_split_fasta.euks, + ch_fasta, 'genome', // busco mode (choice of: genome, proteins, or transcriptome) busco_db_lineage, // busco lineages file - downloads if not set ch_busco_db, @@ -133,21 +98,11 @@ workflow GENOME_EVALUATION { // Tools are listed in stats_generation_software separated by ';'. // If stats_generation_software is given in the samplesheet, launched tools are appended to it. - // Software name with version, e.g. checkm2_v1.0.2, assigned per tool - def checkm2_software = CHECKM2_PREDICT.out.versions_checkm2_predict - .map { _process_name, tool_name, version -> "${tool_name}_v${version}" } - .first() + // Software name with version, e.g. eukcc_v2.2.0, assigned per tool def eukcc_software = EUKCC_SINGLE.out.versions_eukcc .map { _process_name, tool_name, version -> "${tool_name}_v${version}" } .first() - ch_prok_stats = CHECKM2_PREDICT.out.checkm2_tsv - .combine(checkm2_software) - .map { meta, table, software -> parseStatsTable(meta, table, software) } - .map { meta, completeness, contamination, software -> - [ meta, completeness, contamination, mergeSoftware(meta.stats_generation_software, [software]) ] - } - // [ meta, completeness, contamination, software ], contamination from the samplesheet is kept if present ch_eukcc_stats = EUKCC_SINGLE.out.eukcc_tsv .combine(eukcc_software) @@ -166,7 +121,7 @@ workflow GENOME_EVALUATION { // BUSCO short summary is optional (no genes found) and EukCC is skipped for busco_only genomes - // remainder keeps every eukaryotic genome, missing results are null - ch_euk_stats = domain_split_fasta.euks + ch_euk_stats = ch_fasta .map { meta, _fasta -> [ meta, true ] } .join(ch_busco_completeness, remainder: true) .join(ch_eukcc_stats.map { meta, completeness, contamination, software -> [ meta, [completeness, contamination, software] ] }, remainder: true) @@ -184,7 +139,7 @@ workflow GENOME_EVALUATION { } emit: - stats = ch_prok_stats.mix(ch_euk_stats) // channel: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] + stats = ch_euk_stats // channel: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] } @@ -219,22 +174,6 @@ def prepareDatabase(db, db_id, ch_untarred) { error("Database '${db}' for ${db_id} must be a local directory or a .tar.gz/.tgz archive (local path or URL)") } -// -// Read completeness and contamination from a CheckM2 quality_report.tsv or EukCC eukcc.tsv. -// Both are tab-separated with a header and genome name, completeness, contamination as first three columns. -// Empty or header-only tables (-stub mode, EukCC exit codes 201/204) give null values. -// -def parseStatsTable(meta, table, software) { - def lines = table.readLines() - def values = lines.size() > 1 ? lines[1].split('\t') : null - return [ - meta, - values ? values[1] : null, - values ? values[2] : null, - software - ] -} - // // Read completeness ([results][Complete percentage]) from BUSCO short_summary json. // With auto-lineage BUSCO writes a generic and a specific summary - the specific lineage is preferred. @@ -245,13 +184,3 @@ def parseBuscoCompleteness(summaries) { def completeness = new groovy.json.JsonSlurper().parseText(summary.text)?.results?.get('Complete percentage') return completeness != null ? completeness.toString() : null } - -// -// Join software names with ';', appending launched tools to the software given in the samplesheet. -// Duplicates and empty values are removed, e.g. "CheckM2_v1.0.0;eukcc_v2.2.0" -// -def mergeSoftware(existing, tools) { - def existing_tools = existing ? existing.toString().tokenize(';').collect { tool -> tool.trim() } : [] - def merged = (existing_tools + tools.findAll { tool -> tool }.collect { tool -> tool.toString() }).unique() - return merged ? merged.join(';') : null -} diff --git a/subworkflows/local/genome_evaluation_euks/meta.yml b/subworkflows/local/genome_evaluation_euks/meta.yml new file mode 100644 index 00000000..cd85fee9 --- /dev/null +++ b/subworkflows/local/genome_evaluation_euks/meta.yml @@ -0,0 +1,64 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "genome_evaluation_euks" +description: | + Estimates completeness and contamination of eukaryotic genomes. + Contamination is calculated by EukCC (or kept from the samplesheet). + Completeness is calculated by EukCC (default) or BUSCO, selected by eukaryotic_completeness_tool. + Databases can be given as a directory or as a .tar.gz/.tgz archive that is extracted by the subworkflow. +keywords: + - genome + - completeness + - contamination + - eukcc + - busco + - eukaryotes + - metagenomics + - MAGs + - bins +components: + - busco/busco + - untar + - gunzip + - eukcc/single +input: + - ch_fasta: + type: file + description: | + Channel containing eukaryotic genome FASTA files to evaluate. + Structure: [ val(meta), path(fasta) ] + pattern: "*.{fa,fasta,fna,fa.gz,fasta.gz,fna.gz}" + ontologies: + - edam: "http://edamontology.org/format_1929" # FASTA + - busco_db_lineage: + type: string + description: | + BUSCO lineage to check against, e.g. 'auto_euk' or '_odb(10|12)'. + Only used when eukaryotic_completeness_tool is 'busco'. + - busco_db: + type: directory + description: | + BUSCO database as a local directory or .tar.gz/.tgz archive (local path or URL), + expected structure `/lineages/_odb(10|12)`. + Provide null to let BUSCO download the lineage itself. + - busco_clean: + type: boolean + description: Clean intermediate BUSCO files. + - eukaryotic_completeness_tool: + type: string + description: Tool used to calculate completeness of eukaryotic genomes. + enum: ["eukcc", "busco"] + - eukcc_db: + type: directory + description: | + EukCC database as a local directory or .tar.gz/.tgz archive (local path or URL). + Required if at least one genome has to be evaluated with EukCC. +output: + - stats: + type: list + description: | + Channel containing completeness, contamination and software used per genome. + stats_generation_software lists the tools separated by ';', appended to the value given in the samplesheet. + Structure: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] +authors: + - "@KateSakharova" + - "@ochkalova" diff --git a/subworkflows/local/genome_evaluation/tests/main.nf.test b/subworkflows/local/genome_evaluation_euks/tests/main.nf.test similarity index 52% rename from subworkflows/local/genome_evaluation/tests/main.nf.test rename to subworkflows/local/genome_evaluation_euks/tests/main.nf.test index 6387367f..935e81a4 100644 --- a/subworkflows/local/genome_evaluation/tests/main.nf.test +++ b/subworkflows/local/genome_evaluation_euks/tests/main.nf.test @@ -1,90 +1,34 @@ nextflow_workflow { - name "Test Subworkflow GENOME_EVALUATION" + name "Test Subworkflow GENOME_EVALUATION_EUKS" script "../main.nf" - workflow "GENOME_EVALUATION" + workflow "GENOME_EVALUATION_EUKS" tag "subworkflows" tag "subworkflows_local" - tag "subworkflows/genome_evaluation" - tag "checkm2" - tag "checkm2/predict" - tag "checkm2/databasedownload" + tag "subworkflows/genome_evaluation_euks" tag "busco" tag "busco/busco" tag "eukcc" tag "untar" tag "gunzip" - test("mixed domains - eukcc - stub") { + test("eukaryote - eukcc - stub") { options "-stub" when { workflow { """ - input[0] = channel.of( - [ - [ id:'test_bac', domain:'bac' ], - file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) - ], - [ - [ id:'test_euk', domain:'euk' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) - ] - ) - input[1] = null // checkm2_db - triggers CHECKM2_DATABASEDOWNLOAD - input[2] = 14897628 // checkm2_db_download_id - input[3] = 'auto_euk' // busco_db_lineage - input[4] = null // busco_db - input[5] = true // busco_clean - input[6] = 'eukcc' // eukaryotic_completeness_tool - input[7] = params.modules_testdata_base_path + 'genomics/sarscov2/genome/db/kraken2.tar.gz' // eukcc_db - any archive works in stub mode - """ - } - } - - then { - assert workflow.success - def stats = workflow.out.stats.collectEntries { meta, completeness, contamination, software -> [ (meta.id): [completeness, contamination, software] ] } - assertAll( - { assert snapshot(workflow.out.stats.sort { it[0].id }).match() }, - { assert workflow.out.stats.size() == 2 }, - // CheckM2 stub writes an empty report - no values; EukCC stub writes one row - { assert stats['test_bac'][0] == null }, - { assert stats['test_bac'][2].startsWith('checkm2_v') }, - { assert stats['test_euk'][0] == '90.0' }, // fake values assigned by eukcc in -stub - { assert stats['test_euk'][1] == '1.0' }, // fake values assigned by eukcc in -stub - { assert stats['test_euk'][2].startsWith('eukcc_v') } - ) - } - - } - - test("prokaryotes only - stub") { - - options "-stub" - - when { - workflow { - """ - input[0] = channel.of( - [ - [ id:'test_bac', domain:'bac' ], - file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) - ], - [ - [ id:'test_arc', domain:'arc' ], - file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) - ] - ) - input[1] = null - input[2] = 14897628 - input[3] = 'auto_euk' - input[4] = null - input[5] = true - input[6] = 'eukcc' - input[7] = null // eukcc_db is not required without eukaryotes + input[0] = channel.of([ + [ id:'test_euk', domain:'euk' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = 'auto_euk' // busco_db_lineage + input[2] = null // busco_db + input[3] = true // busco_clean + input[4] = 'eukcc' // eukaryotic_completeness_tool + input[5] = 'https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz' // eukcc_db """ } } @@ -92,13 +36,12 @@ nextflow_workflow { then { assert workflow.success assertAll( - { assert snapshot(workflow.out.stats.sort { it[0].id }).match() }, - { assert workflow.out.stats.size() == 2 }, - { assert workflow.out.stats.every { it[3].startsWith('checkm2_v') } }, - // CheckM2 database is downloaded once for all prokaryotes - { assert workflow.trace.tasks().count { it.name.contains('CHECKM2_DATABASEDOWNLOAD') } == 1 }, - // no eukaryotes - eukaryotic steps must not run - { assert !workflow.trace.tasks().any { it.name =~ /EUKCC|BUSCO|DB_UNTAR|GUNZIP_FASTA/ } } + { assert snapshot(workflow.out.stats).match() }, + { assert workflow.out.stats.size() == 1 }, + { assert workflow.out.stats[0][1] == '90.0' }, // fake values assigned by eukcc in -stub + { assert workflow.out.stats[0][2] == '1.0' }, // fake values assigned by eukcc in -stub + { assert workflow.out.stats[0][3].startsWith('eukcc_v') }, + { assert !workflow.trace.tasks().any { it.name.contains('BUSCO') } } ) } @@ -115,13 +58,11 @@ nextflow_workflow { [ id:'test_euk', domain:'euk' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) ]) - input[1] = null - input[2] = 14897628 - input[3] = 'auto_euk' - input[4] = null // busco_db - BUSCO downloads lineages itself - input[5] = true - input[6] = 'busco' - input[7] = params.modules_testdata_base_path + 'genomics/sarscov2/genome/db/kraken2.tar.gz' + input[1] = 'auto_euk' + input[2] = null // busco_db - BUSCO downloads lineages itself + input[3] = true + input[4] = 'busco' + input[5] = 'https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz' """ } } @@ -136,8 +77,6 @@ nextflow_workflow { // contamination is always taken from EukCC { assert workflow.out.stats[0][2] == '1.0' }, { assert workflow.out.stats[0][3] ==~ /busco_v[^;]+;eukcc_v[^;]+/ }, - // no prokaryotes - CheckM2 database must not be downloaded - { assert !workflow.trace.tasks().any { it.name.contains('CHECKM2') } }, { assert workflow.trace.tasks().any { it.name.contains('BUSCO_BUSCO') } } ) } @@ -155,13 +94,11 @@ nextflow_workflow { [ id:'test_euk', domain:'euk', contamination:2.5, stats_generation_software:'CustomTool_v1.0' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) ]) - input[1] = null - input[2] = 14897628 - input[3] = 'auto_euk' - input[4] = null - input[5] = true - input[6] = 'busco' - input[7] = null // eukcc_db is not required - EukCC is skipped + input[1] = 'auto_euk' + input[2] = null + input[3] = true + input[4] = 'busco' + input[5] = null // eukcc_db is not required - EukCC is skipped """ } } @@ -194,13 +131,11 @@ nextflow_workflow { [ id:'test_euk', domain:'euk', contamination:2.5, stats_generation_software:'CustomTool_v1.0' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) ]) - input[1] = null - input[2] = 14897628 - input[3] = 'auto_euk' - input[4] = null - input[5] = true - input[6] = 'eukcc' - input[7] = params.modules_testdata_base_path + 'genomics/sarscov2/genome/db/kraken2.tar.gz' + input[1] = 'auto_euk' + input[2] = null + input[3] = true + input[4] = 'eukcc' + input[5] = 'https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz' """ } } @@ -231,13 +166,11 @@ nextflow_workflow { [ id:'test_euk', domain:'euk' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) ]) - input[1] = null - input[2] = 14897628 - input[3] = 'auto_euk' - input[4] = null - input[5] = true - input[6] = 'eukcc' - input[7] = null // eukcc_db missing while eukaryotes are present + input[1] = 'auto_euk' + input[2] = null + input[3] = true + input[4] = 'eukcc' + input[5] = null // eukcc_db missing while eukaryotes are present """ } } @@ -250,4 +183,32 @@ nextflow_workflow { } + test("no genomes - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.empty() + input[1] = 'auto_euk' + input[2] = null + input[3] = true + input[4] = 'eukcc' + input[5] = null // eukcc_db is not required without eukaryotes + """ + } + } + + then { + assert workflow.success + assertAll( + { assert workflow.out.stats.size() == 0 }, + // no eukaryotes - eukaryotic steps must not run + { assert !workflow.trace.tasks().any { it.name =~ /EUKCC|BUSCO|DB_UNTAR|GUNZIP_FASTA/ } } + ) + } + + } + } diff --git a/subworkflows/local/genome_evaluation/tests/main.nf.test.snap b/subworkflows/local/genome_evaluation_euks/tests/main.nf.test.snap similarity index 62% rename from subworkflows/local/genome_evaluation/tests/main.nf.test.snap rename to subworkflows/local/genome_evaluation_euks/tests/main.nf.test.snap index 7bb94311..97d22b2e 100644 --- a/subworkflows/local/genome_evaluation/tests/main.nf.test.snap +++ b/subworkflows/local/genome_evaluation_euks/tests/main.nf.test.snap @@ -13,36 +13,7 @@ ] ] ], - "timestamp": "2026-10-20T10:38:25.344278", - "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.0" - } - }, - "prokaryotes only - stub": { - "content": [ - [ - [ - { - "id": "test_arc", - "domain": "arc" - }, - null, - null, - "checkm2_v1.1.0" - ], - [ - { - "id": "test_bac", - "domain": "bac" - }, - null, - null, - "checkm2_v1.1.0" - ] - ] - ], - "timestamp": "2026-10-20T10:01:14.903614", + "timestamp": "2026-10-21T18:04:58.162808", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.0" @@ -64,24 +35,15 @@ ] ] ], - "timestamp": "2026-10-20T10:38:53.012231", + "timestamp": "2026-10-21T18:05:55.032161", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.0" } }, - "mixed domains - eukcc - stub": { + "eukaryote - eukcc - stub": { "content": [ [ - [ - { - "id": "test_bac", - "domain": "bac" - }, - null, - null, - "checkm2_v1.1.0" - ], [ { "id": "test_euk", @@ -93,7 +55,7 @@ ] ] ], - "timestamp": "2026-10-20T09:53:08.084333", + "timestamp": "2026-10-21T18:04:14.72553", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.0" @@ -115,7 +77,7 @@ ] ] ], - "timestamp": "2026-10-20T10:38:42.005927", + "timestamp": "2026-10-21T18:05:21.38848", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.0" diff --git a/subworkflows/local/genome_evaluation_proks/main.nf b/subworkflows/local/genome_evaluation_proks/main.nf new file mode 100644 index 00000000..49293601 --- /dev/null +++ b/subworkflows/local/genome_evaluation_proks/main.nf @@ -0,0 +1,71 @@ +// +// Subworkflow that calculates completeness and contamination for prokaryotic genomes +// + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +include { CHECKM2_DATABASEDOWNLOAD } from '../../../modules/nf-core/checkm2/databasedownload/main' +include { CHECKM2_PREDICT } from '../../../modules/nf-core/checkm2/predict/main' + +include { parseStatsTable; mergeSoftware } from '../utils_nfcore_seqsubmit_pipeline' + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBWORKFLOW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +workflow GENOME_EVALUATION_PROKS { + + take: + ch_fasta // channel: [ val(meta), path(fasta) ] - prokaryotic genomes only + ch_checkm2_db // val: path to local CheckM2 database or null to trigger automatic download + ch_checkm2_db_download_id // val: CheckM2 database Zenodo download ID + + main: + + // Database preparation for checkm2 + // that step would be launched only if input is not empty + ch_do_download = ch_fasta + .first() + .map { _meta_fasta -> ch_checkm2_db_download_id } + + // Download and prepare db from scratch if no pre-built db provided + if (ch_checkm2_db) { + ch_checkm2_db_ready = channel.value([[id: 'checkm2_db'], file(ch_checkm2_db, checkIfExists: true)]) + } else { + CHECKM2_DATABASEDOWNLOAD(ch_do_download) + ch_checkm2_db_ready = CHECKM2_DATABASEDOWNLOAD.out.database + } + + // Genome evaluation with CheckM2 + + CHECKM2_PREDICT( + ch_fasta, + ch_checkm2_db_ready, + ) + + // ------ Completeness and contamination from CheckM2 + // Tools are listed in stats_generation_software separated by ';'. + // If stats_generation_software is given in the samplesheet, CheckM2 is appended to it. + + // Software name with version, e.g. checkm2_v1.0.2 + def checkm2_software = CHECKM2_PREDICT.out.versions_checkm2_predict + .map { _process_name, tool_name, version -> "${tool_name}_v${version}" } + .first() + + ch_prok_stats = CHECKM2_PREDICT.out.checkm2_tsv + .combine(checkm2_software) + .map { meta, table, software -> parseStatsTable(meta, table, software) } + .map { meta, completeness, contamination, software -> + [ meta, completeness, contamination, mergeSoftware(meta.stats_generation_software, [software]) ] + } + + emit: + stats = ch_prok_stats // channel: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] + +} + diff --git a/subworkflows/local/genome_evaluation_proks/meta.yml b/subworkflows/local/genome_evaluation_proks/meta.yml new file mode 100644 index 00000000..b982e81f --- /dev/null +++ b/subworkflows/local/genome_evaluation_proks/meta.yml @@ -0,0 +1,46 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "genome_evaluation_proks" +description: | + Estimates completeness and contamination of prokaryotic (bacterial and archaeal) genomes using CheckM2. + Downloads the CheckM2 database automatically when no pre-built database is provided. +keywords: + - genome + - completeness + - contamination + - checkm2 + - prokaryotes + - metagenomics + - MAGs + - bins +components: + - checkm2/databasedownload + - checkm2/predict +input: + - ch_fasta: + type: file + description: | + Channel containing prokaryotic genome FASTA files to evaluate. + Structure: [ val(meta), path(fasta) ] + pattern: "*.{fa,fasta,fna,fa.gz,fasta.gz,fna.gz}" + ontologies: + - edam: "http://edamontology.org/format_1929" # FASTA + - ch_checkm2_db: + type: directory + description: | + Path to a pre-built CheckM2 database. + Provide null to trigger automatic download via ch_checkm2_db_download_id. + - ch_checkm2_db_download_id: + type: integer + description: | + Zenodo record ID used to download the CheckM2 database via CHECKM2_DATABASEDOWNLOAD (e.g. 14897628). + Only used when ch_checkm2_db is null. +output: + - stats: + type: list + description: | + Channel containing completeness, contamination and software used per genome. + stats_generation_software lists the tools separated by ';', appended to the value given in the samplesheet. + Structure: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] +authors: + - "@KateSakharova" + - "@ochkalova" diff --git a/subworkflows/local/genome_evaluation_proks/tests/main.nf.test b/subworkflows/local/genome_evaluation_proks/tests/main.nf.test new file mode 100644 index 00000000..f24ce604 --- /dev/null +++ b/subworkflows/local/genome_evaluation_proks/tests/main.nf.test @@ -0,0 +1,106 @@ +nextflow_workflow { + + name "Test Subworkflow GENOME_EVALUATION_PROKS" + script "../main.nf" + workflow "GENOME_EVALUATION_PROKS" + + tag "subworkflows" + tag "subworkflows_local" + tag "subworkflows/genome_evaluation_proks" + tag "checkm2" + tag "checkm2/predict" + tag "checkm2/databasedownload" + + test("prokaryotes - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of( + [ + [ id:'test_bac', domain:'bac' ], + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ], + [ + [ id:'test_arc', domain:'arc' ], + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ] + ) + input[1] = null // checkm2_db - triggers CHECKM2_DATABASEDOWNLOAD + input[2] = 14897628 // checkm2_db_download_id + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.stats.sort { it[0].id }).match() }, + { assert workflow.out.stats.size() == 2 }, + // CheckM2 stub writes an empty report - no values + { assert workflow.out.stats.every { it[1] == null && it[2] == null } }, + { assert workflow.out.stats.every { it[3].startsWith('checkm2_v') } }, + // CheckM2 database is downloaded once for all prokaryotes + { assert workflow.trace.tasks().count { it.name.contains('CHECKM2_DATABASEDOWNLOAD') } == 1 } + ) + } + + } + + test("prokaryote with stats_generation_software - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_bac', domain:'bac', stats_generation_software:'CustomTool_v1.0' ], + file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/genome/genome.fna.gz', checkIfExists: true) + ]) + input[1] = null + input[2] = 14897628 + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.stats).match() }, + { assert workflow.out.stats.size() == 1 }, + // CheckM2 is appended to the software given in samplesheet + { assert workflow.out.stats[0][3] ==~ /CustomTool_v1\.0;checkm2_v[^;]+/ } + ) + } + + } + + test("no genomes - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.empty() + input[1] = null + input[2] = 14897628 + """ + } + } + + then { + assert workflow.success + assertAll( + { assert workflow.out.stats.size() == 0 }, + // CheckM2 database must not be downloaded without prokaryotes + { assert !workflow.trace.tasks().any { it.name.contains('CHECKM2') } } + ) + } + + } + +} diff --git a/subworkflows/local/genome_evaluation_proks/tests/main.nf.test.snap b/subworkflows/local/genome_evaluation_proks/tests/main.nf.test.snap new file mode 100644 index 00000000..f9ffeab8 --- /dev/null +++ b/subworkflows/local/genome_evaluation_proks/tests/main.nf.test.snap @@ -0,0 +1,52 @@ +{ + "prokaryote with stats_generation_software - stub": { + "content": [ + [ + [ + { + "id": "test_bac", + "domain": "bac", + "stats_generation_software": "CustomTool_v1.0" + }, + null, + null, + "CustomTool_v1.0;checkm2_v1.1.0" + ] + ] + ], + "timestamp": "2026-10-21T18:09:23.381378", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + }, + "prokaryotes - stub": { + "content": [ + [ + [ + { + "id": "test_arc", + "domain": "arc" + }, + null, + null, + "checkm2_v1.1.0" + ], + [ + { + "id": "test_bac", + "domain": "bac" + }, + null, + null, + "checkm2_v1.1.0" + ] + ] + ], + "timestamp": "2026-10-21T18:08:46.296846", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.0" + } + } +} \ No newline at end of file diff --git a/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf b/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf index 24e7854c..6c2b49b2 100644 --- a/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf @@ -298,3 +298,29 @@ def methodsDescriptionText(mqc_methods_yaml) { return description_html.toString() } + +// +// Read completeness and contamination from a CheckM2 quality_report.tsv or EukCC eukcc.tsv. +// Both are tab-separated with a header and genome name, completeness, contamination as first three columns. +// Empty or header-only tables (-stub mode, EukCC exit codes 201/204) give null values. +// +def parseStatsTable(meta, table, software) { + def lines = table.readLines() + def values = lines.size() > 1 ? lines[1].split('\t') : null + return [ + meta, + values ? values[1] : null, + values ? values[2] : null, + software + ] +} + +// +// Join software names with ';', appending launched tools to the software given in the samplesheet. +// Duplicates and empty values are removed, e.g. "CheckM2_v1.0.0;eukcc_v2.2.0" +// +def mergeSoftware(existing, tools) { + def existing_tools = existing ? existing.toString().tokenize(';').collect { tool -> tool.trim() } : [] + def merged = (existing_tools + tools.findAll { tool -> tool }.collect { tool -> tool.toString() }).unique() + return merged ? merged.join(';') : null +} diff --git a/tests/mag_no_rna_presence.nf.test b/tests/mag_no_rna_presence.nf.test index 9f4c0051..8fa7ac80 100644 --- a/tests/mag_no_rna_presence.nf.test +++ b/tests/mag_no_rna_presence.nf.test @@ -22,7 +22,21 @@ nextflow_pipeline { def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') // Early failure no need to test the rest of snapshots assert workflow.success + // Final RNA_presence decision per genome, read from the submission metadata table + def metadata_lines = path("$outputDir/mags/upload/genomes_metadata.tsv").readLines() + def metadata_header = metadata_lines[0].split('\t') as List + def rna_presence = metadata_lines.drop(1) + .findAll { line -> line.trim() } + .collectEntries { line -> + def values = line.split('\t', -1) + [ (values[metadata_header.indexOf('genome_name')]): values[metadata_header.indexOf('rRNA_presence')] ] + } assertAll( + { assert rna_presence.keySet() == ['no_rna_presence_prok', 'no_rna_presence_euk'] as Set }, + // complete bacterial isolate genome - all rRNA genes and enough tRNAs are expected + { assert rna_presence['no_rna_presence_prok'] == 'True' }, + // small eukaryotic genome fragment - eukaryotic rRNA set is not expected to be complete + { assert rna_presence['no_rna_presence_euk'] == 'False' }, { assert snapshot( // Number of successful tasks workflow.trace.succeeded().size(), diff --git a/workflows/genomesubmit.nf b/workflows/genomesubmit.nf index 4a293411..ce71b3eb 100644 --- a/workflows/genomesubmit.nf +++ b/workflows/genomesubmit.nf @@ -16,7 +16,8 @@ include { MULTIQC } from '../modules/nf-core/multi include { paramsSummaryMap } from 'plugin/nf-schema' include { FASTA_VALIDATION } from '../subworkflows/local/fasta_validation/main' -include { GENOME_EVALUATION } from '../subworkflows/local/genome_evaluation/main' +include { GENOME_EVALUATION_EUKS } from '../subworkflows/local/genome_evaluation_euks/main' +include { GENOME_EVALUATION_PROKS } from '../subworkflows/local/genome_evaluation_proks/main' include { RNA_DETECTION } from '../subworkflows/local/rna_detection/main' include { FASTA_CLASSIFY_CATPACK } from '../subworkflows/nf-core/fasta_classify_catpack/main' @@ -200,10 +201,21 @@ workflow GENOMESUBMIT { evaluation_present: true // Everything else goes here } - GENOME_EVALUATION ( - branched_stats_results.genome_evaluation_input, + // Split genomes to evaluate into prokaryotes and eukaryotes + domain_split_stats = branched_stats_results.genome_evaluation_input + .branch { meta, _fasta -> + proks: meta.domain in ['arc', 'bac'] + euks: meta.domain == 'euk' + } + + GENOME_EVALUATION_PROKS ( + domain_split_stats.proks, checkm2_db, - checkm2_db_download_id, + checkm2_db_download_id + ) + + GENOME_EVALUATION_EUKS ( + domain_split_stats.euks, busco_db_lineage, busco_db, busco_clean, @@ -211,8 +223,9 @@ workflow GENOMESUBMIT { eukcc_db ) - // Update metadata with completeness and contamination from CheckM2 (prokaryotes) or EukCC (eukaryotes) - fasta_updated_with_stats = GENOME_EVALUATION.out.stats + // Update metadata with completeness and contamination from CheckM2 (prokaryotes) or EukCC/BUSCO (eukaryotes) + fasta_updated_with_stats = GENOME_EVALUATION_PROKS.out.stats + .mix(GENOME_EVALUATION_EUKS.out.stats) .join(branched_stats_results.genome_evaluation_input) .map { meta, completeness, contamination, stats_software, fasta -> def updated_meta = meta + [ @@ -256,7 +269,7 @@ workflow GENOMESUBMIT { // --------- Generate manifests CREATE_MANIFESTS( - fasta_updated_with_taxonomy.map{_meta, fasta -> fasta}.collect(), + fasta_updated_with_stats.map{_meta, fasta -> fasta}.collect(), CONCAT_METADATA.out.file_out.map { _meta, file -> file }.first(), mags_or_bins_flag, // mags or bins study_accession_ch.first(), @@ -277,7 +290,7 @@ workflow GENOMESUBMIT { [ meta, manifest ] } // Combine fasta and manifests - ch_combined = fasta_updated_with_taxonomy + ch_combined = fasta_updated_with_stats .map { meta, fasta -> [meta.id, meta, fasta] } .join( manifests_ch.map { meta, manifest -> [meta.id, manifest] } // Has only [id: prefix] From 2c025dfd0aef24aad523ee011d7b71d1f14c1130 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Wed, 21 Oct 2026 19:09:36 +0100 Subject: [PATCH 11/24] lint and report NA stats in separate file --- conf/containers_conda_lock_files_amd64.config | 2 +- conf/containers_conda_lock_files_arm64.config | 2 +- conf/containers_docker_amd64.config | 2 +- .../local/genome_evaluation_euks/main.nf | 25 ++++++++++- .../local/genome_evaluation_euks/meta.yml | 6 +++ .../genome_evaluation_euks/tests/main.nf.test | 44 +++++++++++++++++++ .../local/genome_evaluation_proks/main.nf | 1 - .../utils_nfcore_seqsubmit_pipeline/main.nf | 7 +++ workflows/genomesubmit.nf | 1 + 9 files changed, 84 insertions(+), 6 deletions(-) diff --git a/conf/containers_conda_lock_files_amd64.config b/conf/containers_conda_lock_files_amd64.config index 4dc7cf67..9034d752 100644 --- a/conf/containers_conda_lock_files_amd64.config +++ b/conf/containers_conda_lock_files_amd64.config @@ -1,2 +1,2 @@ process { withName: 'BUSCO_BUSCO' { container = 'modules/nf-core/busco/busco/.conda-lock/linux_amd64-bd-6d1f7006d91892b3_1.txt' } } -process { withName: 'MULTIQC' { conda = 'modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt' } } \ No newline at end of file +process { withName: 'MULTIQC' { conda = 'modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt' } } diff --git a/conf/containers_conda_lock_files_arm64.config b/conf/containers_conda_lock_files_arm64.config index 707b0e4d..3733ddfd 100644 --- a/conf/containers_conda_lock_files_arm64.config +++ b/conf/containers_conda_lock_files_arm64.config @@ -1 +1 @@ -process { withName: 'MULTIQC' { conda = 'modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt' } } \ No newline at end of file +process { withName: 'MULTIQC' { conda = 'modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt' } } diff --git a/conf/containers_docker_amd64.config b/conf/containers_docker_amd64.config index 8d2bb8d5..7668fe46 100644 --- a/conf/containers_docker_amd64.config +++ b/conf/containers_docker_amd64.config @@ -1,2 +1,2 @@ process { withName: 'BUSCO_BUSCO' { container = 'community.wave.seqera.io/library/busco:6.1.0--6d1f7006d91892b3' } } -process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc' } } \ No newline at end of file +process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc' } } diff --git a/subworkflows/local/genome_evaluation_euks/main.nf b/subworkflows/local/genome_evaluation_euks/main.nf index 0879c1d1..ef163ae9 100644 --- a/subworkflows/local/genome_evaluation_euks/main.nf +++ b/subworkflows/local/genome_evaluation_euks/main.nf @@ -13,7 +13,7 @@ include { BUSCO_BUSCO } from '../../../modules/nf-core/busco/busco/ include { UNTAR as DB_UNTAR } from '../../../modules/nf-core/untar/main' include { GUNZIP as GUNZIP_FASTA } from '../../../modules/nf-core/gunzip/main' -include { parseStatsTable; mergeSoftware } from '../utils_nfcore_seqsubmit_pipeline' +include { parseStatsTable; mergeSoftware; isNotAssigned } from '../utils_nfcore_seqsubmit_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -138,8 +138,29 @@ workflow GENOME_EVALUATION_EUKS { } } + // ------ Filter out genomes without completeness or contamination + // EukCC reports NA when it cannot place a genome, BUSCO summary is missing when no genes are found. + // Values are not checked in -stub mode, where empty tool outputs give null values. + ch_euk_stats_branched = ch_euk_stats + .branch { _meta, completeness, contamination, _software -> + not_assigned: !workflow.stubRun && [completeness, contamination].any { value -> isNotAssigned(value) } + assigned: true + } + + ch_euk_stats_branched.not_assigned + .map { meta, completeness, contamination, software -> + log.warn("Genome '${meta.id}' is excluded from submission: ${software} returned completeness='${completeness}', contamination='${contamination}'") + "${meta.id}\t${completeness}\t${contamination}\t${software}" + } + .collectFile( + name: "${params.outdir}/${params.mode}/not_assigned_quality_genomes.tsv", + newLine: true, + seed: "sample\tcompleteness\tcontamination\tstats_generation_software\n" + ) + emit: - stats = ch_euk_stats // channel: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] + stats = ch_euk_stats_branched.assigned // channel: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] + not_assigned = ch_euk_stats_branched.not_assigned // channel: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] } diff --git a/subworkflows/local/genome_evaluation_euks/meta.yml b/subworkflows/local/genome_evaluation_euks/meta.yml index cd85fee9..adc0b561 100644 --- a/subworkflows/local/genome_evaluation_euks/meta.yml +++ b/subworkflows/local/genome_evaluation_euks/meta.yml @@ -59,6 +59,12 @@ output: Channel containing completeness, contamination and software used per genome. stats_generation_software lists the tools separated by ';', appended to the value given in the samplesheet. Structure: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] + - not_assigned: + type: list + description: | + Channel containing genomes excluded from submission because completeness or contamination + could not be estimated (missing, empty or NA). They are also reported in not_assigned_quality_genomes.tsv. + Structure: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] authors: - "@KateSakharova" - "@ochkalova" diff --git a/subworkflows/local/genome_evaluation_euks/tests/main.nf.test b/subworkflows/local/genome_evaluation_euks/tests/main.nf.test index 935e81a4..f20041e9 100644 --- a/subworkflows/local/genome_evaluation_euks/tests/main.nf.test +++ b/subworkflows/local/genome_evaluation_euks/tests/main.nf.test @@ -183,6 +183,50 @@ nextflow_workflow { } + test("eukaryote without estimate - eukcc - not assigned") { + + // Not a stub: values are not checked in -stub mode. + // SARS-CoV-2 genome has no fungal marker genes, so EukCC gives no estimate (exit code 201/204) + // and the genome is reported in not_assigned_quality_genomes.tsv instead of stats. + + when { + params { + mode = 'mags' + } + workflow { + """ + input[0] = channel.of([ + [ id:'test_not_assigned', domain:'euk' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = 'auto_euk' + input[2] = null + input[3] = true + input[4] = 'eukcc' + input[5] = 'https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz' + """ + } + } + + then { + def report = path("${params.outdir}/mags/not_assigned_quality_genomes.tsv") + assert workflow.success + assertAll( + { assert workflow.out.stats.size() == 0 }, + { assert workflow.out.not_assigned.size() == 1 }, + { assert workflow.out.not_assigned[0][0].id == 'test_not_assigned' }, + { assert workflow.out.not_assigned[0][1] == null }, + { assert workflow.out.not_assigned[0][2] == null }, + { assert report.exists() }, + { assert report.readLines()[0] == 'sample\tcompleteness\tcontamination\tstats_generation_software' }, + { assert report.readLines().size() == 2 }, + { assert report.readLines()[1].startsWith('test_not_assigned\tnull\tnull\teukcc_v') }, + { assert workflow.stdout.any { it.contains("Genome 'test_not_assigned' is excluded from submission") } } + ) + } + + } + test("no genomes - stub") { options "-stub" diff --git a/subworkflows/local/genome_evaluation_proks/main.nf b/subworkflows/local/genome_evaluation_proks/main.nf index 49293601..dc71d670 100644 --- a/subworkflows/local/genome_evaluation_proks/main.nf +++ b/subworkflows/local/genome_evaluation_proks/main.nf @@ -68,4 +68,3 @@ workflow GENOME_EVALUATION_PROKS { stats = ch_prok_stats // channel: [ val(meta), val(completeness), val(contamination), val(stats_generation_software) ] } - diff --git a/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf b/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf index 6c2b49b2..c89133d1 100644 --- a/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_seqsubmit_pipeline/main.nf @@ -315,6 +315,13 @@ def parseStatsTable(meta, table, software) { ] } +// +// Check if completeness or contamination value was not assigned by a tool: missing, empty or NA/NaN +// +def isNotAssigned(value) { + return value == null || value.toString().trim().toUpperCase() in ['', 'NA', 'NAN'] +} + // // Join software names with ';', appending launched tools to the software given in the samplesheet. // Duplicates and empty values are removed, e.g. "CheckM2_v1.0.0;eukcc_v2.2.0" diff --git a/workflows/genomesubmit.nf b/workflows/genomesubmit.nf index ce71b3eb..c1c06f95 100644 --- a/workflows/genomesubmit.nf +++ b/workflows/genomesubmit.nf @@ -224,6 +224,7 @@ workflow GENOMESUBMIT { ) // Update metadata with completeness and contamination from CheckM2 (prokaryotes) or EukCC/BUSCO (eukaryotes) + // Eukaryotic genomes without completeness or contamination are filtered out in GENOME_EVALUATION_EUKS fasta_updated_with_stats = GENOME_EVALUATION_PROKS.out.stats .mix(GENOME_EVALUATION_EUKS.out.stats) .join(branched_stats_results.genome_evaluation_input) From 118052103858afe04f3a7e400dcde92590377551 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Wed, 21 Oct 2026 19:19:42 +0100 Subject: [PATCH 12/24] change order of modes in outputs --- docs/output.md | 59 +++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/docs/output.md b/docs/output.md index 073efa31..520cfc90 100644 --- a/docs/output.md +++ b/docs/output.md @@ -8,39 +8,21 @@ The directories listed below will be created in the results directory (set with ## Pipeline overview -The pipeline is built using [Nextflow](https://www.nextflow.io/) and performs automated submission of sequence data to ENA. Exact steps and generated outputs depend on the data type and `--mode` executed (`mags`, `bins`, `metagenomic_assemblies` or `reads`). +The pipeline is built using [Nextflow](https://www.nextflow.io/) and performs automated submission of sequence data to ENA. Exact steps and generated outputs depend on the data type and `--mode` executed (`reads`, `metagenomic_assemblies`, `mags` or `bins`). -## `mags` and `bins` outputs +## `reads` outputs -When `--mode mags` or `--mode bins` is used, results are written under `mags/` or `bins/`. +When `--mode reads` is used, results are written under `reads/`.
    Output files -- `/` - - `upload/genomes_accessions.tsv`: accessions assigned to submitted genomes. - - `upload/genomes_metadata.tsv`: tabular metadata gathered for submission. - - `upload/manifests/`: manifests generated by `genome_uploader`. - - `databases/checkm2/`: downloaded CheckM2 database file (when downloaded during the run, only if prokaryotic genomes are present). - - `databases/cat_pack/`: prepared CAT_pack database directories (when generated during the run). - - `/coverage/`: `coverm genome` output for samples where `genome_coverage` had to be computed. - - `/rna/barrnap/`: `barrnap` output GFF for samples where `RNA_presence` had to be inferred (run with the kingdom matching the genome domain). - - `/rna/trnascanse/`: `tRNAscan-SE` outputs for the same RNA inference step. - - `/taxonomy/`: CAT/BAT taxonomic classification for samples where `NCBI_lineage` was missing. - - `/checkm2/`: CheckM2 report (`_checkm2_report.tsv`) for prokaryotic (bacteria and archaea) samples where completeness/contamination metadata had to be computed. - - `/eukcc/`: EukCC results (`_eukcc_results/eukcc.tsv`) for eukaryotic samples where completeness/contamination metadata had to be computed. Not created with `--eukaryotic_completeness_tool busco` if `contamination` was provided in the samplesheet. - - `/busco/-/`: BUSCO short summaries (`.txt`, `.json`), batch summary and log for eukaryotic samples, only with `--eukaryotic_completeness_tool busco`. - - `/busco/busco_downloads/lineages/`: BUSCO lineage datasets used in the run, only with `--save_busco_db`. - - `/upload/webin_cli/`: Webin-CLI wrapper output TSV with accessions for submitted genomes. +- `reads/` + - `upload/reads_accessions.tsv`: run accessions assigned to submitted reads.
    -Many of these per-sample directories are conditional. For example, if `genome_coverage` is already provided in the samplesheet, the corresponding `coverage/` directory will not be created for that sample. - -> [!NOTE] **Assigned accessions (ERZs)** \ -> Users should read the ENA documentation on referencing submitted data: \ -> mags: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/mag.html#assigned-accession-numbers \ -> bins: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/binned.html#assigned-accession-numbers +Manifest generation and Webin-CLI submission are executed by the workflow, but their intermediate outputs are not currently published into `--outdir` by the pipeline. ## `metagenomic_assemblies` outputs @@ -62,19 +44,38 @@ Assembly study registration, manifest generation, and Webin-CLI submission are e > Users should read the ENA documentation on referencing submitted data: \ > metagenomic assemblies: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/primary.html#assigned-accession-numbers -## `reads` outputs +## `mags` and `bins` outputs -When `--mode reads` is used, results are written under `reads/`. +When `--mode mags` or `--mode bins` is used, results are written under `mags/` or `bins/`.
    Output files -- `reads/` - - `upload/reads_accessions.tsv`: run accessions assigned to submitted reads. +- `/` + - `upload/genomes_accessions.tsv`: accessions assigned to submitted genomes. + - `upload/genomes_metadata.tsv`: tabular metadata gathered for submission. + - `upload/manifests/`: manifests generated by `genome_uploader`. + - `databases/checkm2/`: downloaded CheckM2 database file (when downloaded during the run, only if prokaryotic genomes are present). + - `databases/cat_pack/`: prepared CAT_pack database directories (when generated during the run). + - `/coverage/`: `coverm genome` output for samples where `genome_coverage` had to be computed. + - `/rna/barrnap/`: `barrnap` output GFF for samples where `RNA_presence` had to be inferred (run with the kingdom matching the genome domain). + - `/rna/trnascanse/`: `tRNAscan-SE` outputs for the same RNA inference step. + - `/taxonomy/`: CAT/BAT taxonomic classification for samples where `NCBI_lineage` was missing. + - `/checkm2/`: CheckM2 report (`_checkm2_report.tsv`) for prokaryotic (bacteria and archaea) samples where completeness/contamination metadata had to be computed. + - `/eukcc/`: EukCC results (`_eukcc_results/eukcc.tsv`) for eukaryotic samples where completeness/contamination metadata had to be computed. Not created with `--eukaryotic_completeness_tool busco` if `contamination` was provided in the samplesheet. + - `/busco/-/`: BUSCO short summaries (`.txt`, `.json`), batch summary and log for eukaryotic samples, only with `--eukaryotic_completeness_tool busco`. + - `/busco/busco_downloads/lineages/`: BUSCO lineage datasets used in the run, only with `--save_busco_db`. + - `/upload/webin_cli/`: Webin-CLI wrapper output TSV with accessions for submitted genomes. + - `not_assigned_quality_genomes.tsv`: List of eukaryotic genomes skipped during upload because their quality could not be assessed.
    -Manifest generation and Webin-CLI submission are executed by the workflow, but their intermediate outputs are not currently published into `--outdir` by the pipeline. +Many of these per-sample directories are conditional. For example, if `genome_coverage` is already provided in the samplesheet, the corresponding `coverage/` directory will not be created for that sample. + +> [!NOTE] **Assigned accessions (ERZs)** \ +> Users should read the ENA documentation on referencing submitted data: \ +> mags: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/mag.html#assigned-accession-numbers \ +> bins: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/binned.html#assigned-accession-numbers ## Common outputs From 4f630e81c2b32fef4353f32413c4a40e8fab7b98 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Thu, 22 Oct 2026 12:28:55 +0100 Subject: [PATCH 13/24] align docs and add real links to samplesheets in tests --- assets/schema_input_assembly.json | 2 +- assets/schema_input_genome.json | 4 +- conf/test_mag_no_quality_euk.conf | 3 +- conf/test_mag_no_rna_presence.conf | 7 ++- docs/usage.md | 52 +++++++++--------- nextflow_schema.json | 18 +++---- tests/mag_no_quality_euk.nf.test | 57 ++++++++++++++++++++ tests/mag_no_rna_presence.nf.test.snap | 74 +++++++++----------------- 8 files changed, 124 insertions(+), 93 deletions(-) create mode 100644 tests/mag_no_quality_euk.nf.test diff --git a/assets/schema_input_assembly.json b/assets/schema_input_assembly.json index a269c481..85e16f81 100644 --- a/assets/schema_input_assembly.json +++ b/assets/schema_input_assembly.json @@ -97,7 +97,7 @@ "type": "string", "enum": ["metagenome", "metatranscriptome"], "errorMessage": "Assembly type should be metagenome or metatranscriptome", - "description": "Assembly type: metagenome or metatranscriptome. Written to the ENA manifest as ASSEMBLY_TYPE 'primary metagenome' or 'metatranscriptome'. Default: metagenome", + "description": "Sequencing library source of the assembly: `metagenome` or `metatranscriptome`. Written to the ENA assembly manifest as ASSEMBLY_TYPE 'primary metagenome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/primary.html) or 'metatranscriptome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metatranscriptome.html) respectively.", "default": "metagenome", "meta": ["assembly_type"] } diff --git a/assets/schema_input_genome.json b/assets/schema_input_genome.json index 4a012224..9b7a379e 100644 --- a/assets/schema_input_genome.json +++ b/assets/schema_input_genome.json @@ -79,7 +79,7 @@ "stats_generation_software": { "type": "string", "default": null, - "description": "Tool, including version, that was used to calculate completeness and contamination, e.g. CheckM2_v1.0.0", + "description": "Tool, including version, that was used to calculate completeness and contamination, e.g. CheckM2_v1.0.0. Several tools are separated by `;`, e.g. busco_v6.1.0;eukcc_v2.2.0. If the pipeline runs additional tools for this genome, they are appended to the provided value.", "meta": ["stats_generation_software"] }, "completeness": { @@ -165,7 +165,7 @@ } ], "default": null, - "description": "Presence or absence of the 23S, 16S, and 5S rRNA genes and at least 18 tRNAs. This is used for MISAG/MIMAG assembly quality classification. Options: 'true' or 'false'", + "description": "Presence or absence of the 23S, 16S, and 5S rRNA genes (prokaryotes) or the 28S, 18S, 5.8S and 5S rRNA genes (eukaryotes) and at least 18 tRNAs. This is used for MISAG/MIMAG assembly quality classification. Options: true or false.", "meta": ["RNA_presence"] }, "NCBI_lineage": { diff --git a/conf/test_mag_no_quality_euk.conf b/conf/test_mag_no_quality_euk.conf index 194dc7a7..e61b8f93 100644 --- a/conf/test_mag_no_quality_euk.conf +++ b/conf/test_mag_no_quality_euk.conf @@ -31,8 +31,7 @@ params { config_profile_description = 'Single-case eukaryotic MAG test with missing completeness and contamination values' // Input data - //input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_quality.csv' - input = 'https://raw.githubusercontent.com/KateSakharova/test-datasets/refs/heads/feature/add-euks/samplesheets/mag_no_quality_euk.csv' + input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_quality_euk.csv' mode = "mags" submission_study = "TEST_STUDY" diff --git a/conf/test_mag_no_rna_presence.conf b/conf/test_mag_no_rna_presence.conf index bc58f017..fb7cb76f 100644 --- a/conf/test_mag_no_rna_presence.conf +++ b/conf/test_mag_no_rna_presence.conf @@ -16,6 +16,10 @@ process { memory: '12.GB', time: '1.h' ] + + withName: 'REGISTERSTUDY|SUBMIT|ENA_WEBIN_CLI_WRAPPER|CREATE_MANIFESTS' { + ext.when = false + } } params { @@ -23,8 +27,7 @@ params { config_profile_description = 'Single-case MAG test with missing RNA_presence value' // Input data - //input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_rna_presence.csv' - input = 'https://raw.githubusercontent.com/KateSakharova/test-datasets/refs/heads/feature/add-euks/samplesheets/mag_no_rna_presence.csv' + input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_rna_presence.csv' mode = "mags" submission_study = "PRJEB98843" diff --git a/docs/usage.md b/docs/usage.md index a580c4f7..25e2e293 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -219,17 +219,17 @@ assembly_001,data/assembly_001.fasta.gz,data/assembly_001_R1.fastq.gz,data/assem assembly_002,data/assembly_002.fasta.gz,,,42.7,ERR011323,MEGAHIT,1.2.9,metatranscriptome ``` -| Column | Required | Description | -| ------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `id` | Yes | A unique identifier for this data entry. Must be globally unique within the input dataset. | -| `fasta` | Yes | Path to assembly contigs in FASTA format compressed with `gzip`. | -| `fastq_1` | Conditional | Path to single-end/paired-end forward reads in FASTQ format (optionally gzipped). Required if `coverage` is not provided. | -| `fastq_2` | No | Path to the second read file in FASTQ format for paired-end data used to generate the source metagenomic assembly. Leave empty for single-end reads. | -| `coverage` | Conditional | Estimated sequencing depth of the assembly. If this value is missing, it is computed automatically during pipeline execution when reads are provided. | -| `run_accession` | Yes | ENA run accession for the reads used to generate the metagenomic assembly. Reads must already be submitted to ENA. | -| `assembler` | Yes | Name of the assembler software used to generate the assembly, e.g. MEGAHIT, SPAdes, metaSPAdes, Flye, etc. | -| `assembler_version` | Yes | Version of the assembler software used to generate the assembly, e.g. 1.0.0. | -| `assembly_type` | No | Sequencing library source: `metagenome` for metagenome assembly (would be used as _'primary metagenome'_ in manifest file following [ENA docs](https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/primary.html)) or `metatranscriptome` for metatranscriptome assembly (woule be used _'metatranscriptome'_ in assembly manifest following [ENA docs](https://ena-docs.readthedocs.io/en/latest/submit/assembly/metatranscriptome.html)). Default: `metagenome` | +| Column | Required | Description | +| ------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | Yes | A unique identifier for this data entry. Must be globally unique within the input dataset. | +| `fasta` | Yes | Path to assembly contigs in FASTA format compressed with `gzip`. | +| `fastq_1` | Conditional | Path to single-end/paired-end forward reads in FASTQ format (optionally gzipped). Required if `coverage` is not provided. | +| `fastq_2` | No | Path to the second read file in FASTQ format for paired-end data used to generate the source metagenomic assembly. Leave empty for single-end reads. | +| `coverage` | Conditional | Estimated sequencing depth of the assembly. If this value is missing, it is computed automatically during pipeline execution when reads are provided. | +| `run_accession` | Yes | ENA run accession for the reads used to generate the metagenomic assembly. Reads must already be submitted to ENA. | +| `assembler` | Yes | Name of the assembler software used to generate the assembly, e.g. MEGAHIT, SPAdes, metaSPAdes, Flye, etc. | +| `assembler_version` | Yes | Version of the assembler software used to generate the assembly, e.g. 1.0.0. | +| `assembly_type` | No | Sequencing library source of the assembly: `metagenome` or `metatranscriptome`. Written to the ENA assembly manifest as ASSEMBLY_TYPE 'primary metagenome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/primary.html) or 'metatranscriptome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metatranscriptome.html) respectively. Default: `metagenome`. | Provide either read files (`fastq_1`, optionally `fastq_2`) or a `coverage` value for each row. If `coverage` is missing and reads are provided, the workflow calculates average coverage with CoverM. See the [Methods documentation](docs/methods.md) for more information on how coverage is calculated. @@ -337,11 +337,11 @@ In particular, the CAT_pack database is extremely large and may take a long time - CheckM2: - provide the path to a local database with `--checkm2_db`, otherwise the pipeline downloads the version specified with `--checkm2_db_download_id` (by default Zenodo accession `14897628`). -- EukCC (required only if eukaryotic genomes are present and their completeness/contamination has to be calculated): - - provide the database with `--eukcc_db` as an uncompressed folder or as a `.tar.gz`/`.tgz` archive (local path or URL, e.g. `http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz`). Archives are extracted by the pipeline in every run, so we recommend downloading and extracting the database once and providing the folder. +- EukCC (used only if eukaryotic genomes are present and their completeness/contamination has to be calculated): + - provide the database with `--eukcc_db` as an uncompressed folder or as a `.tar.gz`/`.tgz` archive (local path or URL), otherwise the pipeline downloads `http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz`. URLs are downloaded and archives are extracted by the pipeline in every run, so we recommend downloading and extracting the database once and providing the folder. - BUSCO (used only with `--eukaryotic_completeness_tool busco`): - - provide a lineage dataset with `--busco_db` as a local folder or as a `.tar.gz`/`.tgz` archive (local path or URL), otherwise BUSCO downloads the lineage set by `--busco_db_lineage` during the run (requires an internet connection). A folder is expected to have the structure `/lineages/_odb(10|12)`. + - provide a lineage dataset with `--busco_db` as a local folder or as a `.tar.gz`/`.tgz` archive (local path or URL), otherwise BUSCO downloads the lineage set by `--busco_db_lineage` during the run (requires an internet connection). A folder is expected to contain a `lineages` subfolder with the lineage dataset, e.g. `lineages/eukaryota_odb10`. - CAT_pack: - provide the path to a local database (containing `tax/` and `db/` folders or a `tar.gz` archive) with `--cat_db`, otherwise the pipeline builds CAT_pack DB from NCBI non-redundant protein database (`nr`). @@ -355,17 +355,17 @@ Databases created/downloaded by the pipeline are published under: In addition to the [common parameters](#running-the-pipeline): -| Parameter | Required | Description | -| -------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--upload_tpa` | No | Mark assemblies as [third party assemblies (TPA)](#third-party-assemblies-tpa) when required. Default: `false`. | -| `--checkm2_db` | No | Path to a pre-downloaded CheckM2 database. If omitted, downloads the version set by `--checkm2_db_download_id`. Default: `14897628` (Zenodo accession). | -| `--cat_db` | No | Path to a local CAT_pack database. If omitted, builds CAT_pack DB from NCBI non-redundant protein database (`nr`). | -| `--eukaryotic_completeness_tool` | No | Tool to calculate completeness of eukaryotic MAGs/bins: `eukcc` or `busco`. Contamination is always calculated by EukCC. Default: `eukcc`. | -| `--eukcc_db` | Conditional | EukCC database folder or `.tar.gz`/`.tgz` archive (local path or URL). Required if eukaryotic genomes without completeness/contamination are present. | -| `--busco_db` | No | BUSCO lineage dataset folder or `.tar.gz`/`.tgz` archive (local path or URL). Used only with `--eukaryotic_completeness_tool busco`. If omitted, BUSCO downloads the lineage set by `--busco_db_lineage`. | -| `--busco_db_lineage` | No | BUSCO `*_odb10`/`*_odb12` lineage to check against, or `auto`, `auto_prok`, `auto_euk` for automatic lineage selection. Default: `auto_euk`. | -| `--save_busco_db` | No | Save BUSCO lineage datasets used in the run to the output directory. Default: `false`. | -| `--busco_clean` | No | Remove BUSCO intermediate files to reduce the number of files in the work directory. Default: `false`. | +| Parameter | Required | Description | +| -------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--upload_tpa` | No | Mark assemblies as [third party assemblies (TPA)](#third-party-assemblies-tpa) when required. Default: `false`. | +| `--checkm2_db` | No | Path to a pre-downloaded CheckM2 database. If omitted, downloads the version set by `--checkm2_db_download_id`. Default: `14897628` (Zenodo accession). | +| `--cat_db` | No | Path to a local CAT_pack database. If omitted, builds CAT_pack DB from NCBI non-redundant protein database (`nr`). | +| `--eukaryotic_completeness_tool` | No | Tool used to calculate completeness of eukaryotic MAGs/bins: `eukcc` or `busco`. Contamination is always calculated by EukCC, unless it is provided in the samplesheet. Default: `eukcc`. | +| `--eukcc_db` | No | EukCC database as an uncompressed folder or a `.tar.gz`/`.tgz` archive (local path or URL). Used to calculate completeness and contamination of eukaryotic MAGs/bins if those values were not provided in the samplesheet. URLs are downloaded and archives are extracted by the pipeline in every run, so we recommend downloading and extracting the database once and providing the folder. Default: `http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz`. | +| `--busco_db` | No | BUSCO `*_odb10` or `*_odb12` lineage dataset as an uncompressed folder or a `.tar.gz`/`.tgz` archive (local path or URL), e.g. `https://busco-data.ezlab.org/v5/data/lineages/eukaryota_odb10.2024-01-08.tar.gz`. A folder is expected to contain a `lineages` subfolder with the lineage dataset, e.g. `lineages/eukaryota_odb10`. If provided, BUSCO runs in offline mode. If omitted, BUSCO downloads the lineage set by `--busco_db_lineage` during the run (requires an internet connection). Used only with `--eukaryotic_completeness_tool busco`. | +| `--busco_db_lineage` | No | Name of the BUSCO `*_odb10` or `*_odb12` lineage to check eukaryotic genomes against (e.g. `eukaryota_odb10`), or `auto`, `auto_prok`, `auto_euk` for automatic lineage selection. When used with `--busco_db`, it should correspond to the lineage supplied there. Without `--busco_db`, the lineage is downloaded during the run (requires an internet connection). Used only with `--eukaryotic_completeness_tool busco`. Default: `auto_euk`. | +| `--save_busco_db` | No | Save BUSCO lineage datasets downloaded during the run (when `--busco_db` is not provided) to the output directory. Useful for reproducibility, as BUSCO datasets are frequently updated and old versions do not always remain accessible. Used only with `--eukaryotic_completeness_tool busco`. Default: `false`. | +| `--busco_clean` | No | Remove BUSCO intermediate files after each run. BUSCO creates a large number of intermediate files, which may cause problems on clusters with file number limits, particularly with many MAGs/bins. Used only with `--eukaryotic_completeness_tool busco`. Default: `false`. | Example `mags` mode upload to TEST server, run command with docker: @@ -392,7 +392,7 @@ nextflow run nf-core/seqsubmit \ - **Domain assignment**: the domain of each genome (bacteria, archaea or eukaryote) is decided from `NCBI_lineage` (provided in the samplesheet or assigned by CAT_pack). Genomes whose lineage does not contain Eukaryota/`2759` or Archaea/`2157` are processed as bacteria, so a missing or incorrect lineage leads to prokaryotic tools being used for that genome. - **Eukaryotic bins/MAGs**: - - EukCC database (`--eukcc_db`) has to be provided, it is not downloaded automatically. + - EukCC database (`--eukcc_db`) is downloaded and extracted in every run unless a local folder is provided. - BUSCO is used only for completeness, contamination is always taken from EukCC (or from the samplesheet). - If EukCC finds no marker genes or MetaEuk predicts no proteins for a genome, completeness and contamination stay empty for that genome. The same happens for completeness when BUSCO finds no genes. diff --git a/nextflow_schema.json b/nextflow_schema.json index 15f1a867..fff58c6f 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -107,42 +107,36 @@ "properties": { "busco_db": { "type": "string", - "description": "Download URL, local tar.gz archive, or local uncompressed directory for an *_odb10 or *_odb12 BUSCO lineage dataset. Used only with `--eukaryotic_completeness_tool busco`.", - "help_text": "Download BUSCO database in tar.gz archive, e.g. https://busco-data.ezlab.org/v5/data/lineages/eukaryota_odb10.2024-01-08.tar.gz, `/path/to/eukaryota_odb10.2024-01-08.tar.gz`.\n\nFor more details, check the [BUSCO section in the usage documentation](https://nf-co.re/mag/latest/docs/usage/#busco).", + "description": "BUSCO `*_odb10` or `*_odb12` lineage dataset as an uncompressed folder or a `.tar.gz`/`.tgz` archive (local path or URL), e.g. `https://busco-data.ezlab.org/v5/data/lineages/eukaryota_odb10.2024-01-08.tar.gz`. A folder is expected to contain a `lineages` subfolder with the lineage dataset, e.g. `lineages/eukaryota_odb10`. If provided, BUSCO runs in offline mode. If omitted, BUSCO downloads the lineage set by `--busco_db_lineage` during the run (requires an internet connection). Used only with `--eukaryotic_completeness_tool busco`.", "format": "path", "exists": true }, "busco_db_lineage": { "type": "string", - "description": "Name of the BUSCO *_odb10 or *_odb12 lineage to check eukaryotic genomes against. Additionally supports 'auto', 'auto_prok' and 'auto_euk' for automatic lineage selection mode. Used only with `--eukaryotic_completeness_tool busco`.", - "help_text": "Typically used in combination with `--busco_db`, corresponding to the lineage files supplied within the `--busco_db` file or directory.\n\nIf supplying without a `--busco_db`, will require an internet connection to work!", + "description": "Name of the BUSCO `*_odb10` or `*_odb12` lineage to check eukaryotic genomes against (e.g. `eukaryota_odb10`), or `auto`, `auto_prok`, `auto_euk` for automatic lineage selection. When used with `--busco_db`, it should correspond to the lineage supplied there. Without `--busco_db`, the lineage is downloaded during the run (requires an internet connection). Used only with `--eukaryotic_completeness_tool busco`.", "pattern": "(.*_odb(10|12))|auto(_prok|_euk)?$", "default": "auto_euk" }, "save_busco_db": { "type": "boolean", - "description": "Save the used BUSCO lineage datasets provided via `--busco_db`.", - "help_text": "Useful to allow reproducibility, as BUSCO datasets are frequently updated and old versions do not always remain accessible.", + "description": "Save BUSCO lineage datasets downloaded during the run (when `--busco_db` is not provided) to the output directory. Useful for reproducibility, as BUSCO datasets are frequently updated and old versions do not always remain accessible. Used only with `--eukaryotic_completeness_tool busco`.", "default": false }, "busco_clean": { "type": "boolean", - "description": "Enable clean-up of temporary files created during BUSCO runs.", - "help_text": "By default, BUSCO creates a large number of intermediate files every run. This may cause problems on some clusters which have file number limits in plate, particularly with large numbers of bins. Enabling this option cleans these files, reducing the total file count of the work directory.", + "description": "Remove BUSCO intermediate files after each run. BUSCO creates a large number of intermediate files, which may cause problems on clusters with file number limits, particularly with many MAGs/bins. Used only with `--eukaryotic_completeness_tool busco`.", "default": false }, "eukcc_db": { "type": "string", - "description": "Path to EukCC database folder or .tar.gz/.tgz archive (local path or URL), used for eukaryotic genomes.", - "help_text": "EukCC database, e.g. http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz. Can be given as an uncompressed folder, or as a .tar.gz/.tgz archive (local path or URL) that will be extracted by the pipeline. Required if there are eukaryotic genomes. To avoid downloading it in every run, download and extract it once and provide the folder.", + "description": "EukCC database as an uncompressed folder or a `.tar.gz`/`.tgz` archive (local path or URL). Used to calculate completeness and contamination of eukaryotic MAGs/bins if those values were not provided in the samplesheet. URLs are downloaded and archives are extracted by the pipeline in every run, so we recommend downloading and extracting the database once and providing the folder.", "format": "path", "exists": true, "default": "http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz" }, "eukaryotic_completeness_tool": { "type": "string", - "description": "Tool used to calculate completeness of eukaryotic MAGs/bins: eukcc or busco.", - "help_text": "Contamination of eukaryotic MAGs/bins is always calculated by EukCC (unless provided in the samplesheet). Completeness is calculated by EukCC by default, or by BUSCO if `busco` is selected.", + "description": "Tool used to calculate completeness of eukaryotic MAGs/bins: `eukcc` or `busco`. Contamination is always calculated by EukCC, unless it is provided in the samplesheet.", "enum": ["eukcc", "busco"], "default": "eukcc" } diff --git a/tests/mag_no_quality_euk.nf.test b/tests/mag_no_quality_euk.nf.test new file mode 100644 index 00000000..142bf03f --- /dev/null +++ b/tests/mag_no_quality_euk.nf.test @@ -0,0 +1,57 @@ +nextflow_pipeline { + + name "Test genome submission workflow - no_quality_euk" + script "../main.nf" + tag "pipeline" + tag "mode_mag" + tag "test_mag_no_quality_euk" + profile "test_mag_no_quality_euk" + + test("-profile test_mag_no_quality_euk") { + + when { + params { + outdir = "$outputDir" + } + } + + 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}', '**/manifests_test/*']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + // Early failure no need to test the rest of snapshots + assert workflow.success + // Completeness, contamination and stats software per genome, read from the submission metadata table + def metadata_lines = path("$outputDir/mags/upload/genomes_metadata.tsv").readLines() + def metadata_header = metadata_lines[0].split('\t') as List + def stats = metadata_lines.drop(1) + .findAll { line -> line.trim() } + .collectEntries { line -> + def values = line.split('\t', -1) + [ (values[metadata_header.indexOf('genome_name')]): [ + completeness: values[metadata_header.indexOf('completeness')], + contamination: values[metadata_header.indexOf('contamination')], + software: values[metadata_header.indexOf('stats_generation_software')] + ] ] + } + assertAll( + { assert stats.keySet() == ['no_quality_euk'] as Set }, + // eukaryotic genome - completeness and contamination are calculated by EukCC + { assert stats['no_quality_euk'].software.toLowerCase().startsWith('eukcc') }, + { assert stats['no_quality_euk'].completeness }, + { assert stats['no_quality_euk'].contamination }, + { assert snapshot( + // Number of successful tasks + workflow.trace.succeeded().size(), + // 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_seqsubmit_software_mqc_versions.yml"), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } +} diff --git a/tests/mag_no_rna_presence.nf.test.snap b/tests/mag_no_rna_presence.nf.test.snap index 7fec9d9f..03582af5 100644 --- a/tests/mag_no_rna_presence.nf.test.snap +++ b/tests/mag_no_rna_presence.nf.test.snap @@ -1,16 +1,11 @@ { "-profile test_mag_no_rna_presence": { "content": [ - 10, + 12, { "BARRNAP": { "barrnap": 0.9 }, - "CONCAT_ACCESSIONS": { - "coreutils": 9.4, - "find": "4.6.0", - "pigz": 2.8 - }, "CONCAT_METADATA": { "coreutils": 9.4, "find": "4.6.0", @@ -22,17 +17,9 @@ "CREATE_GENOME_METADATA_TSV": { "bash": "5.2.37(1)-release" }, - "CREATE_MANIFESTS": { - "genome_uploader": "3.0.4" - }, "FALINT": { "falint": "1.2.0" }, - "SUBMIT": { - "ena-webin-cli": "9.0.3", - "mgnify-pipelines-toolkit": "1.5.1", - "python": "3.12.13" - }, "TRNASCANSE": { "tRNAscan-SE": "2.0.12" }, @@ -42,68 +29,59 @@ }, [ "mags", - "mags/no_rna_presence", - "mags/no_rna_presence/rna", - "mags/no_rna_presence/rna/barrnap", - "mags/no_rna_presence/rna/barrnap/no_rna_presence_bac.gff", - "mags/no_rna_presence/rna/trnascanse", - "mags/no_rna_presence/rna/trnascanse/no_rna_presence.log", - "mags/no_rna_presence/rna/trnascanse/no_rna_presence.stats", - "mags/no_rna_presence/rna/trnascanse/no_rna_presence.tsv", - "mags/no_rna_presence/upload", - "mags/no_rna_presence/upload/webin_cli", - "mags/no_rna_presence/upload/webin_cli/no_rna_presence_accessions.tsv", + "mags/no_rna_presence_euk", + "mags/no_rna_presence_euk/rna", + "mags/no_rna_presence_euk/rna/barrnap", + "mags/no_rna_presence_euk/rna/barrnap/no_rna_presence_euk_euk.gff", + "mags/no_rna_presence_euk/rna/trnascanse", + "mags/no_rna_presence_euk/rna/trnascanse/no_rna_presence_euk.log", + "mags/no_rna_presence_euk/rna/trnascanse/no_rna_presence_euk.stats", + "mags/no_rna_presence_euk/rna/trnascanse/no_rna_presence_euk.tsv", + "mags/no_rna_presence_prok", + "mags/no_rna_presence_prok/rna", + "mags/no_rna_presence_prok/rna/barrnap", + "mags/no_rna_presence_prok/rna/barrnap/no_rna_presence_prok_bac.gff", + "mags/no_rna_presence_prok/rna/trnascanse", + "mags/no_rna_presence_prok/rna/trnascanse/no_rna_presence_prok.log", + "mags/no_rna_presence_prok/rna/trnascanse/no_rna_presence_prok.stats", + "mags/no_rna_presence_prok/rna/trnascanse/no_rna_presence_prok.tsv", "mags/upload", - "mags/upload/genomes_accessions.tsv", "mags/upload/genomes_metadata.tsv", - "mags/upload/manifests", - "mags/upload/manifests/results", - "mags/upload/manifests/results/MAG_upload", - "mags/upload/manifests/results/MAG_upload/ENA_backup.json", - "mags/upload/manifests/results/MAG_upload/genome_samples.xml", - "mags/upload/manifests/results/MAG_upload/manifests_test", - "mags/upload/manifests/results/MAG_upload/registered_MAGs_test.tsv", "multiqc", "multiqc/multiqc_data", "multiqc/multiqc_data/llms-full.txt", "multiqc/multiqc_data/multiqc.log", "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_Genomes assigned accessions.txt", "multiqc/multiqc_data/multiqc_citations.txt", "multiqc/multiqc_data/multiqc_data.json", "multiqc/multiqc_data/multiqc_genome_metadata.txt", - "multiqc/multiqc_data/multiqc_sample_registration.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/Genomes assigned accessions.pdf", "multiqc/multiqc_plots/pdf/genome_metadata.pdf", - "multiqc/multiqc_plots/pdf/sample_registration.pdf", "multiqc/multiqc_plots/png", - "multiqc/multiqc_plots/png/Genomes assigned accessions.png", "multiqc/multiqc_plots/png/genome_metadata.png", - "multiqc/multiqc_plots/png/sample_registration.png", "multiqc/multiqc_plots/svg", - "multiqc/multiqc_plots/svg/Genomes assigned accessions.svg", "multiqc/multiqc_plots/svg/genome_metadata.svg", - "multiqc/multiqc_plots/svg/sample_registration.svg", "multiqc/multiqc_report.html", "pipeline_info", "pipeline_info/nf_core_seqsubmit_software_mqc_versions.yml" ], [ - "no_rna_presence_bac.gff:md5,df19e1b84ba6f691d20c72b397c88abf", - "no_rna_presence.tsv:md5,abd958e8addba39c9e4d7f6b97a1a7c6", - "genomes_metadata.tsv:md5,28fdaa0fe237cba4d0370c07d5f9ebaa", + "no_rna_presence_euk_euk.gff:md5,df19e1b84ba6f691d20c72b397c88abf", + "no_rna_presence_euk.tsv:md5,68d0b807755e195d09aaa082d59827e7", + "no_rna_presence_prok_bac.gff:md5,468c2be7060d743f95295f1ecf751e19", + "no_rna_presence_prok.tsv:md5,55ef27998a528dd2f97f761becd7e4ea", + "genomes_metadata.tsv:md5,2acbde2a328213ee6b5153bffa72d697", "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", - "multiqc_genome_metadata.txt:md5,efa903988140642f4f3d12b8e034e7a1" + "multiqc_genome_metadata.txt:md5,40f68f54d23fdb12371b9b69991101ea" ] ], + "timestamp": "2026-10-22T10:01:43.171583", "meta": { - "nf-test": "0.9.3", + "nf-test": "0.9.5", "nextflow": "26.04.0" - }, - "timestamp": "2026-06-24T16:13:51.780521" + } } } \ No newline at end of file From a1d1c85749b0814c5de18088ef27d91d82051abe Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Fri, 23 Oct 2026 09:01:16 +0100 Subject: [PATCH 14/24] busco fix attempt --- modules/nf-core/busco/busco/busco-busco.diff | 11 ++++++++--- modules/nf-core/busco/busco/main.nf | 9 +++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/modules/nf-core/busco/busco/busco-busco.diff b/modules/nf-core/busco/busco/busco-busco.diff index 58a9a795..fc1c60e8 100644 --- a/modules/nf-core/busco/busco/busco-busco.diff +++ b/modules/nf-core/busco/busco/busco-busco.diff @@ -4,13 +4,18 @@ Changes in component 'nf-core/busco/busco' Changes in 'busco/busco/main.nf': --- modules/nf-core/busco/busco/main.nf +++ modules/nf-core/busco/busco/main.nf -@@ -67,7 +67,8 @@ +@@ -67,7 +67,13 @@ export BUSCO_BBTOOLS_MEMORY=${bbtools_memory} # Fix Augustus for Apptainer - ENV_AUGUSTUS=/opt/conda/etc/conda/activate.d/augustus.sh -+ #ENV_AUGUSTUS=/opt/conda/etc/conda/activate.d/augustus.sh -+ ENV_AUGUSTUS=/opt/wave/.pixi/envs/default/etc/conda/activate.d/augustus.sh ++ # Pixi-based Wave images activate the environment only via the entrypoint, which Singularity/Apptainer skip ++ if [ -d /opt/wave/.pixi/envs/default/bin ]; then ++ export PATH="/opt/wave/.pixi/envs/default/bin:\${PATH}" ++ ENV_AUGUSTUS=/opt/wave/.pixi/envs/default/etc/conda/activate.d/augustus.sh ++ else ++ ENV_AUGUSTUS=/opt/conda/etc/conda/activate.d/augustus.sh ++ fi set +u if [ -z "\${AUGUSTUS_CONFIG_PATH}" ] && [ -f "\${ENV_AUGUSTUS}" ]; then source "\${ENV_AUGUSTUS}" diff --git a/modules/nf-core/busco/busco/main.nf b/modules/nf-core/busco/busco/main.nf index 81d2e4eb..261d0ec7 100644 --- a/modules/nf-core/busco/busco/main.nf +++ b/modules/nf-core/busco/busco/main.nf @@ -67,8 +67,13 @@ process BUSCO_BUSCO { export BUSCO_BBTOOLS_MEMORY=${bbtools_memory} # Fix Augustus for Apptainer - #ENV_AUGUSTUS=/opt/conda/etc/conda/activate.d/augustus.sh - ENV_AUGUSTUS=/opt/wave/.pixi/envs/default/etc/conda/activate.d/augustus.sh + # Pixi-based Wave images activate the environment only via the entrypoint, which Singularity/Apptainer skip + if [ -d /opt/wave/.pixi/envs/default/bin ]; then + export PATH="/opt/wave/.pixi/envs/default/bin:\${PATH}" + ENV_AUGUSTUS=/opt/wave/.pixi/envs/default/etc/conda/activate.d/augustus.sh + else + ENV_AUGUSTUS=/opt/conda/etc/conda/activate.d/augustus.sh + fi set +u if [ -z "\${AUGUSTUS_CONFIG_PATH}" ] && [ -f "\${ENV_AUGUSTUS}" ]; then source "\${ENV_AUGUSTUS}" From 685905bcdaa215a357c94df828291319287bfe82 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Fri, 23 Oct 2026 14:56:36 +0100 Subject: [PATCH 15/24] turn off more ena in mags tests --- conf/test_mag_no_quality_euk.conf | 2 +- conf/test_mag_no_rna_presence.conf | 2 +- conf/test_mag_no_taxonomy.conf | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/conf/test_mag_no_quality_euk.conf b/conf/test_mag_no_quality_euk.conf index e61b8f93..4ce99771 100644 --- a/conf/test_mag_no_quality_euk.conf +++ b/conf/test_mag_no_quality_euk.conf @@ -21,7 +21,7 @@ process { ext.args = '--clade fungi --simple' } - withName: 'REGISTERSTUDY|SUBMIT|ENA_WEBIN_CLI_WRAPPER' { + withName: 'REGISTERSTUDY|SUBMIT|CREATE_MANIFESTS' { ext.when = false } } diff --git a/conf/test_mag_no_rna_presence.conf b/conf/test_mag_no_rna_presence.conf index 6f8edd29..3e07f4b8 100644 --- a/conf/test_mag_no_rna_presence.conf +++ b/conf/test_mag_no_rna_presence.conf @@ -17,7 +17,7 @@ process { time: '1.h' ] - withName: 'REGISTERSTUDY|SUBMIT|ENA_WEBIN_CLI_WRAPPER|CREATE_MANIFESTS' { + withName: 'REGISTERSTUDY|SUBMIT|CREATE_MANIFESTS' { ext.when = false } } diff --git a/conf/test_mag_no_taxonomy.conf b/conf/test_mag_no_taxonomy.conf index 3fea8048..54355a70 100644 --- a/conf/test_mag_no_taxonomy.conf +++ b/conf/test_mag_no_taxonomy.conf @@ -16,6 +16,10 @@ process { memory: '12.GB', time: '1.h' ] + + withName: 'REGISTERSTUDY|SUBMIT|CREATE_MANIFESTS' { + ext.when = false + } } params { @@ -27,8 +31,7 @@ params { outdir = 'test_output' mode = "mags" - submission_study = null - study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' + submission_study = "TEST_STUDY" centre_name = "TEST_CENTER" test_upload = true From 35bf5dc5a0b39f316cea9bf22e64232b3b1c8db8 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Fri, 23 Oct 2026 15:14:28 +0100 Subject: [PATCH 16/24] turn off more ena in mags tests --- ..._quality_euk_without_ena_interaction.conf} | 0 ...rna_presence_without_ena_interaction.conf} | 0 ..._no_taxonomy_without_ena_interaction.conf} | 0 nextflow.config | 6 +- ...ality_euk_without_ena_interaction.nf.test} | 8 +- ...y_euk_without_ena_interaction.nf.test.snap | 74 +++++++++++++++++++ ..._presence_without_ena_interaction.nf.test} | 8 +- ...ence_without_ena_interaction.nf.test.snap} | 0 ..._taxonomy_without_ena_interaction.nf.test} | 8 +- ...nomy_without_ena_interaction.nf.test.snap} | 41 +--------- 10 files changed, 92 insertions(+), 53 deletions(-) rename conf/{test_mag_no_quality_euk.conf => test_mag_no_quality_euk_without_ena_interaction.conf} (100%) rename conf/{test_mag_no_rna_presence.conf => test_mag_no_rna_presence_without_ena_interaction.conf} (100%) rename conf/{test_mag_no_taxonomy.conf => test_mag_no_taxonomy_without_ena_interaction.conf} (100%) rename tests/{mag_no_quality_euk.nf.test => mag_no_quality_euk_without_ena_interaction.nf.test} (90%) create mode 100644 tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap rename tests/{mag_no_rna_presence.nf.test => mag_no_rna_presence_without_ena_interaction.nf.test} (89%) rename tests/{mag_no_rna_presence.nf.test.snap => mag_no_rna_presence_without_ena_interaction.nf.test.snap} (100%) rename tests/{mag_no_taxonomy.nf.test => mag_no_taxonomy_without_ena_interaction.nf.test} (84%) rename tests/{mag_no_taxonomy.nf.test.snap => mag_no_taxonomy_without_ena_interaction.nf.test.snap} (59%) diff --git a/conf/test_mag_no_quality_euk.conf b/conf/test_mag_no_quality_euk_without_ena_interaction.conf similarity index 100% rename from conf/test_mag_no_quality_euk.conf rename to conf/test_mag_no_quality_euk_without_ena_interaction.conf diff --git a/conf/test_mag_no_rna_presence.conf b/conf/test_mag_no_rna_presence_without_ena_interaction.conf similarity index 100% rename from conf/test_mag_no_rna_presence.conf rename to conf/test_mag_no_rna_presence_without_ena_interaction.conf diff --git a/conf/test_mag_no_taxonomy.conf b/conf/test_mag_no_taxonomy_without_ena_interaction.conf similarity index 100% rename from conf/test_mag_no_taxonomy.conf rename to conf/test_mag_no_taxonomy_without_ena_interaction.conf diff --git a/nextflow.config b/nextflow.config index d6a0da0b..440e76e9 100644 --- a/nextflow.config +++ b/nextflow.config @@ -258,10 +258,10 @@ profiles { test_mag_no_coverage_single_reads { includeConfig 'conf/test_mag_no_coverage_single_reads.conf' } test_mag_no_coverage_paired_reads { includeConfig 'conf/test_mag_no_coverage_paired_reads.conf' } test_mag_no_quality { includeConfig 'conf/test_mag_no_quality.conf' } - test_mag_no_quality_euk { includeConfig 'conf/test_mag_no_quality_euk.conf' } + test_mag_no_quality_euk_without_ena_interaction { includeConfig 'conf/test_mag_no_quality_euk_without_ena_interaction.conf' } test_mag_one_contig { includeConfig 'conf/test_mag_one_contig.conf' } - test_mag_no_rna_presence { includeConfig 'conf/test_mag_no_rna_presence.conf' } - test_mag_no_taxonomy { includeConfig 'conf/test_mag_no_taxonomy.conf' } + test_mag_no_rna_presence_without_ena_interaction { includeConfig 'conf/test_mag_no_rna_presence_without_ena_interaction.conf' } + test_mag_no_taxonomy_without_ena_interaction { includeConfig 'conf/test_mag_no_taxonomy_without_ena_interaction.conf' } test_assembly_complete_metadata_existing_study { includeConfig 'conf/test_assembly_complete_metadata_existing_study.config' } test_assembly_complete_metadata { includeConfig 'conf/test_assembly_complete_metadata.config' } test_assembly_no_coverage_single_reads { includeConfig 'conf/test_assembly_no_coverage_single_reads.config' } diff --git a/tests/mag_no_quality_euk.nf.test b/tests/mag_no_quality_euk_without_ena_interaction.nf.test similarity index 90% rename from tests/mag_no_quality_euk.nf.test rename to tests/mag_no_quality_euk_without_ena_interaction.nf.test index 142bf03f..5266a4b2 100644 --- a/tests/mag_no_quality_euk.nf.test +++ b/tests/mag_no_quality_euk_without_ena_interaction.nf.test @@ -1,13 +1,13 @@ nextflow_pipeline { - name "Test genome submission workflow - no_quality_euk" + name "Test genome submission workflow - no_quality_euk without ENA interaction" script "../main.nf" tag "pipeline" tag "mode_mag" - tag "test_mag_no_quality_euk" - profile "test_mag_no_quality_euk" + tag "test_mag_no_quality_euk_without_ena_interaction" + profile "test_mag_no_quality_euk_without_ena_interaction" - test("-profile test_mag_no_quality_euk") { + test("-profile test_mag_no_quality_euk_without_ena_interaction") { when { params { diff --git a/tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap b/tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap new file mode 100644 index 00000000..48449b96 --- /dev/null +++ b/tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap @@ -0,0 +1,74 @@ +{ + "-profile test_mag_no_quality_euk": { + "content": [ + 7, + { + "CONCAT_METADATA": { + "coreutils": 9.4, + "find": "4.6.0", + "pigz": 2.8 + }, + "CREATE_GENOME_METADATA_TSV": { + "bash": "5.2.37(1)-release" + }, + "DB_UNTAR": { + "untar": 1.34 + }, + "EUKCC_SINGLE": { + "eukcc": "2.2.0", + "metaeuk": "4.a0f584d", + "pplacer": "v1.1.alpha19-0-g807f6f3" + }, + "FALINT": { + "falint": "1.2.0" + }, + "GUNZIP_FASTA": { + "gunzip": 1.13 + }, + "Workflow": { + "nf-core/seqsubmit": "v1.0.0" + } + }, + [ + "mags", + "mags/no_quality_euk", + "mags/no_quality_euk/eukcc", + "mags/no_quality_euk/eukcc/no_quality_euk_eukcc_results", + "mags/no_quality_euk/eukcc/no_quality_euk_eukcc_results/eukcc.tsv", + "mags/upload", + "mags/upload/genomes_metadata.tsv", + "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_genome_metadata.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/genome_metadata.pdf", + "multiqc/multiqc_plots/png", + "multiqc/multiqc_plots/png/genome_metadata.png", + "multiqc/multiqc_plots/svg", + "multiqc/multiqc_plots/svg/genome_metadata.svg", + "multiqc/multiqc_report.html", + "pipeline_info", + "pipeline_info/nf_core_seqsubmit_software_mqc_versions.yml" + ], + [ + "eukcc.tsv:md5,f30a5cae1c74b9c5e0e0b1d0f4c3c3f6", + "genomes_metadata.tsv:md5,e3c541346f66663954e19d114dd744c0", + "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", + "multiqc_genome_metadata.txt:md5,22652d4228d3297c03baf7ff1505f8bc" + ] + ], + "timestamp": "2026-10-23T15:01:23.80635663", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.10.3" + } + } +} \ No newline at end of file diff --git a/tests/mag_no_rna_presence.nf.test b/tests/mag_no_rna_presence_without_ena_interaction.nf.test similarity index 89% rename from tests/mag_no_rna_presence.nf.test rename to tests/mag_no_rna_presence_without_ena_interaction.nf.test index 8fa7ac80..b03046a4 100644 --- a/tests/mag_no_rna_presence.nf.test +++ b/tests/mag_no_rna_presence_without_ena_interaction.nf.test @@ -1,13 +1,13 @@ nextflow_pipeline { - name "Test genome submission workflow - no_rna_presence" + name "Test genome submission workflow - no_rna_presence without ENA interaction" script "../main.nf" tag "pipeline" tag "mode_mag" - tag "test_mag_no_rna_presence" - profile "test_mag_no_rna_presence" + tag "test_mag_no_rna_presence_without_ena_interaction" + profile "test_mag_no_rna_presence_without_ena_interaction" - test("-profile test_mag_no_rna_presence") { + test("-profile test_mag_no_rna_presence_without_ena_interaction") { when { params { diff --git a/tests/mag_no_rna_presence.nf.test.snap b/tests/mag_no_rna_presence_without_ena_interaction.nf.test.snap similarity index 100% rename from tests/mag_no_rna_presence.nf.test.snap rename to tests/mag_no_rna_presence_without_ena_interaction.nf.test.snap diff --git a/tests/mag_no_taxonomy.nf.test b/tests/mag_no_taxonomy_without_ena_interaction.nf.test similarity index 84% rename from tests/mag_no_taxonomy.nf.test rename to tests/mag_no_taxonomy_without_ena_interaction.nf.test index d5296c47..903de8c5 100644 --- a/tests/mag_no_taxonomy.nf.test +++ b/tests/mag_no_taxonomy_without_ena_interaction.nf.test @@ -1,13 +1,13 @@ nextflow_pipeline { - name "Test genome submission workflow - no_taxonomy" + name "Test genome submission workflow - no_taxonomy without ENA interaction" script "../main.nf" tag "pipeline" tag "mode_mag" - tag "test_mag_no_taxonomy" - profile "test_mag_no_taxonomy" + tag "test_mag_no_taxonomy_without_ena_interaction" + profile "test_mag_no_taxonomy_without_ena_interaction" - test("-profile test_mag_no_taxonomy") { + test("-profile test_mag_no_taxonomy_without_ena_interaction") { when { params { diff --git a/tests/mag_no_taxonomy.nf.test.snap b/tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap similarity index 59% rename from tests/mag_no_taxonomy.nf.test.snap rename to tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap index 725912d2..730bc46e 100644 --- a/tests/mag_no_taxonomy.nf.test.snap +++ b/tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap @@ -1,7 +1,7 @@ { "-profile test_mag_no_taxonomy": { "content": [ - 12, + 8, { "CATPACK_ADDNAMES_BINS": { "catpack": 6.0 @@ -12,11 +12,6 @@ "CAT_DB_UNTAR": { "untar": 1.34 }, - "CONCAT_ACCESSIONS": { - "coreutils": 9.4, - "find": "4.6.0", - "pigz": 2.8 - }, "CONCAT_METADATA": { "coreutils": 9.4, "find": "4.6.0", @@ -25,23 +20,12 @@ "CREATE_GENOME_METADATA_TSV": { "bash": "5.2.37(1)-release" }, - "CREATE_MANIFESTS": { - "genome_uploader": "3.0.4" - }, "FALINT": { "falint": "1.2.0" }, - "REGISTERSTUDY": { - "mgnify-pipelines-toolkit": "1.5.1" - }, "RENAME_FASTA_FOR_CATPACK": { "bash": "5.2.37(1)-release" }, - "SUBMIT": { - "ena-webin-cli": "9.0.3", - "mgnify-pipelines-toolkit": "1.5.1", - "python": "3.12.13" - }, "Workflow": { "nf-core/seqsubmit": "v1.0.0" } @@ -52,44 +36,25 @@ "mags/no_taxonomy/taxonomy", "mags/no_taxonomy/taxonomy/no_taxonomy.bin2classification.txt", "mags/no_taxonomy/taxonomy/no_taxonomy.txt", - "mags/no_taxonomy/upload", - "mags/no_taxonomy/upload/webin_cli", - "mags/no_taxonomy/upload/webin_cli/no_taxonomy_accessions.tsv", "mags/upload", - "mags/upload/genomes_accessions.tsv", "mags/upload/genomes_metadata.tsv", - "mags/upload/manifests", - "mags/upload/manifests/results", - "mags/upload/manifests/results/MAG_upload", - "mags/upload/manifests/results/MAG_upload/ENA_backup.json", - "mags/upload/manifests/results/MAG_upload/genome_samples.xml", - "mags/upload/manifests/results/MAG_upload/manifests_test", - "mags/upload/manifests/results/MAG_upload/registered_MAGs_test.tsv", "multiqc", "multiqc/multiqc_data", "multiqc/multiqc_data/llms-full.txt", "multiqc/multiqc_data/multiqc.log", "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_Genomes assigned accessions.txt", "multiqc/multiqc_data/multiqc_citations.txt", "multiqc/multiqc_data/multiqc_data.json", "multiqc/multiqc_data/multiqc_genome_metadata.txt", - "multiqc/multiqc_data/multiqc_sample_registration.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/Genomes assigned accessions.pdf", "multiqc/multiqc_plots/pdf/genome_metadata.pdf", - "multiqc/multiqc_plots/pdf/sample_registration.pdf", "multiqc/multiqc_plots/png", - "multiqc/multiqc_plots/png/Genomes assigned accessions.png", "multiqc/multiqc_plots/png/genome_metadata.png", - "multiqc/multiqc_plots/png/sample_registration.png", "multiqc/multiqc_plots/svg", - "multiqc/multiqc_plots/svg/Genomes assigned accessions.svg", "multiqc/multiqc_plots/svg/genome_metadata.svg", - "multiqc/multiqc_plots/svg/sample_registration.svg", "multiqc/multiqc_report.html", "pipeline_info", "pipeline_info/nf_core_seqsubmit_software_mqc_versions.yml" @@ -102,10 +67,10 @@ "multiqc_genome_metadata.txt:md5,c2bdf8ba36b55b5f48fa07a26e5222f5" ] ], - "timestamp": "2026-10-15T16:23:14.854681", + "timestamp": "2026-10-23T14:57:41.967071271", "meta": { "nf-test": "0.9.5", - "nextflow": "26.10.0" + "nextflow": "26.10.3" } } } \ No newline at end of file From d86daa6b22aaa2c9159589df3b796dd6fdaf0ef0 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Fri, 23 Oct 2026 15:50:27 +0100 Subject: [PATCH 17/24] turn off more ena in mags tests --- nf-test.config | 4 ++++ tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap | 2 +- .../mag_no_rna_presence_without_ena_interaction.nf.test.snap | 2 +- tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/nf-test.config b/nf-test.config index 2d67bcf5..5e4a9860 100644 --- a/nf-test.config +++ b/nf-test.config @@ -9,9 +9,13 @@ config { configFile = "tests/nextflow.config" // ignore tests coming from the nf-core/modules repo + // ignore euk_mags_quality assessment because Eukcc DB is big for GA + // ignore genome_evaluation_proks test because checkm2 container is too big ignore = [ 'modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*', + 'tests/mag_no_quality_euk_without_ena_interaction.nf.test', + 'subworkflows/local/genome_evaluation_proks/tests/*' ] // run all test with defined profile(s) from the main nextflow.config diff --git a/tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap b/tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap index 48449b96..d8dec831 100644 --- a/tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap +++ b/tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap @@ -1,5 +1,5 @@ { - "-profile test_mag_no_quality_euk": { + "-profile test_mag_no_quality_euk_without_ena_interaction": { "content": [ 7, { diff --git a/tests/mag_no_rna_presence_without_ena_interaction.nf.test.snap b/tests/mag_no_rna_presence_without_ena_interaction.nf.test.snap index 03582af5..91878700 100644 --- a/tests/mag_no_rna_presence_without_ena_interaction.nf.test.snap +++ b/tests/mag_no_rna_presence_without_ena_interaction.nf.test.snap @@ -1,5 +1,5 @@ { - "-profile test_mag_no_rna_presence": { + "-profile test_mag_no_rna_presence_without_ena_interaction": { "content": [ 12, { diff --git a/tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap b/tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap index 730bc46e..9093f8e8 100644 --- a/tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap +++ b/tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap @@ -1,5 +1,5 @@ { - "-profile test_mag_no_taxonomy": { + "-profile test_mag_no_taxonomy_without_ena_interaction": { "content": [ 8, { From 316a9337960e1aac22ff36c99c7725f1d0b4f5ae Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Mon, 26 Oct 2026 21:03:09 +0000 Subject: [PATCH 18/24] rewording --- assets/schema_input_assembly.json | 2 +- docs/usage.md | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/assets/schema_input_assembly.json b/assets/schema_input_assembly.json index 85e16f81..45d1aaa4 100644 --- a/assets/schema_input_assembly.json +++ b/assets/schema_input_assembly.json @@ -97,7 +97,7 @@ "type": "string", "enum": ["metagenome", "metatranscriptome"], "errorMessage": "Assembly type should be metagenome or metatranscriptome", - "description": "Sequencing library source of the assembly: `metagenome` or `metatranscriptome`. Written to the ENA assembly manifest as ASSEMBLY_TYPE 'primary metagenome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/primary.html) or 'metatranscriptome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metatranscriptome.html) respectively.", + "description": "Assembly type: `metagenome` or `metatranscriptome`. Written to the ENA assembly manifest as ASSEMBLY_TYPE 'primary metagenome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/primary.html) or 'metatranscriptome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metatranscriptome.html) respectively.", "default": "metagenome", "meta": ["assembly_type"] } diff --git a/docs/usage.md b/docs/usage.md index 25e2e293..9bfd2b74 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -219,17 +219,17 @@ assembly_001,data/assembly_001.fasta.gz,data/assembly_001_R1.fastq.gz,data/assem assembly_002,data/assembly_002.fasta.gz,,,42.7,ERR011323,MEGAHIT,1.2.9,metatranscriptome ``` -| Column | Required | Description | -| ------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `id` | Yes | A unique identifier for this data entry. Must be globally unique within the input dataset. | -| `fasta` | Yes | Path to assembly contigs in FASTA format compressed with `gzip`. | -| `fastq_1` | Conditional | Path to single-end/paired-end forward reads in FASTQ format (optionally gzipped). Required if `coverage` is not provided. | -| `fastq_2` | No | Path to the second read file in FASTQ format for paired-end data used to generate the source metagenomic assembly. Leave empty for single-end reads. | -| `coverage` | Conditional | Estimated sequencing depth of the assembly. If this value is missing, it is computed automatically during pipeline execution when reads are provided. | -| `run_accession` | Yes | ENA run accession for the reads used to generate the metagenomic assembly. Reads must already be submitted to ENA. | -| `assembler` | Yes | Name of the assembler software used to generate the assembly, e.g. MEGAHIT, SPAdes, metaSPAdes, Flye, etc. | -| `assembler_version` | Yes | Version of the assembler software used to generate the assembly, e.g. 1.0.0. | -| `assembly_type` | No | Sequencing library source of the assembly: `metagenome` or `metatranscriptome`. Written to the ENA assembly manifest as ASSEMBLY_TYPE 'primary metagenome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/primary.html) or 'metatranscriptome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metatranscriptome.html) respectively. Default: `metagenome`. | +| Column | Required | Description | +| ------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | Yes | A unique identifier for this data entry. Must be globally unique within the input dataset. | +| `fasta` | Yes | Path to assembly contigs in FASTA format compressed with `gzip`. | +| `fastq_1` | Conditional | Path to single-end/paired-end forward reads in FASTQ format (optionally gzipped). Required if `coverage` is not provided. | +| `fastq_2` | No | Path to the second read file in FASTQ format for paired-end data used to generate the source metagenomic assembly. Leave empty for single-end reads. | +| `coverage` | Conditional | Estimated sequencing depth of the assembly. If this value is missing, it is computed automatically during pipeline execution when reads are provided. | +| `run_accession` | Yes | ENA run accession for the reads used to generate the metagenomic assembly. Reads must already be submitted to ENA. | +| `assembler` | Yes | Name of the assembler software used to generate the assembly, e.g. MEGAHIT, SPAdes, metaSPAdes, Flye, etc. | +| `assembler_version` | Yes | Version of the assembler software used to generate the assembly, e.g. 1.0.0. | +| `assembly_type` | No | Assembly type: `metagenome` or `metatranscriptome`. Written to the ENA assembly manifest as ASSEMBLY_TYPE 'primary metagenome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/primary.html) or 'metatranscriptome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metatranscriptome.html) respectively. Default: `metagenome`. | Provide either read files (`fastq_1`, optionally `fastq_2`) or a `coverage` value for each row. If `coverage` is missing and reads are provided, the workflow calculates average coverage with CoverM. See the [Methods documentation](docs/methods.md) for more information on how coverage is calculated. From 6680da6a266efead299c3ebb211b5c0520dbd1ea Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Thu, 29 Oct 2026 23:36:56 +0000 Subject: [PATCH 19/24] fixes after review --- assets/schema_input_assembly.json | 2 +- ..._mag_no_quality_euk_skip_ena_queries.conf} | 2 +- ... => test_mag_no_rna_skip_ena_queries.conf} | 4 +- ...est_mag_no_taxonomy_skip_ena_queries.conf} | 2 +- ...test_mag_one_contig_skip_ena_queries.conf} | 9 ++-- docs/methods.md | 2 +- docs/usage.md | 38 +++++++++++----- nextflow.config | 10 ++--- nextflow_schema.json | 27 +++++++++++- nf-test.config | 2 +- .../local/genome_evaluation_euks/main.nf | 2 +- .../genome_evaluation_euks/tests/main.nf.test | 10 ++--- .../local/genome_evaluation_proks/main.nf | 2 +- .../tests/main.nf.test | 4 +- ...g_no_quality_euk_skip_ena_queries.nf.test} | 6 +-- ...quality_euk_skip_ena_queries.nf.test.snap} | 2 +- ...st => mag_no_rna_skip_ena_queries.nf.test} | 6 +-- ... mag_no_rna_skip_ena_queries.nf.test.snap} | 2 +- ... mag_no_taxonomy_skip_ena_queries.nf.test} | 6 +-- ...no_taxonomy_skip_ena_queries.nf.test.snap} | 2 +- ...> mag_one_contig_skip_ena_queries.nf.test} | 8 ++-- ..._one_contig_skip_ena_queries.nf.test.snap} | 2 +- workflows/genomesubmit.nf | 43 +++++++++++-------- 23 files changed, 122 insertions(+), 71 deletions(-) rename conf/{test_mag_no_quality_euk_without_ena_interaction.conf => test_mag_no_quality_euk_skip_ena_queries.conf} (93%) rename conf/{test_mag_no_rna_presence_without_ena_interaction.conf => test_mag_no_rna_skip_ena_queries.conf} (90%) rename conf/{test_mag_no_taxonomy_without_ena_interaction.conf => test_mag_no_taxonomy_skip_ena_queries.conf} (95%) rename conf/{test_mag_one_contig.conf => test_mag_one_contig_skip_ena_queries.conf} (81%) rename tests/{mag_no_quality_euk_without_ena_interaction.nf.test => mag_no_quality_euk_skip_ena_queries.nf.test} (93%) rename tests/{mag_no_quality_euk_without_ena_interaction.nf.test.snap => mag_no_quality_euk_skip_ena_queries.nf.test.snap} (97%) rename tests/{mag_no_rna_presence_without_ena_interaction.nf.test => mag_no_rna_skip_ena_queries.nf.test} (92%) rename tests/{mag_no_rna_presence_without_ena_interaction.nf.test.snap => mag_no_rna_skip_ena_queries.nf.test.snap} (98%) rename tests/{mag_no_taxonomy_without_ena_interaction.nf.test => mag_no_taxonomy_skip_ena_queries.nf.test} (89%) rename tests/{mag_no_taxonomy_without_ena_interaction.nf.test.snap => mag_no_taxonomy_skip_ena_queries.nf.test.snap} (97%) rename tests/{mag_one_contig.nf.test => mag_one_contig_skip_ena_queries.nf.test} (85%) rename tests/{mag_one_contig.nf.test.snap => mag_one_contig_skip_ena_queries.nf.test.snap} (95%) diff --git a/assets/schema_input_assembly.json b/assets/schema_input_assembly.json index 45d1aaa4..acd44fe0 100644 --- a/assets/schema_input_assembly.json +++ b/assets/schema_input_assembly.json @@ -97,7 +97,7 @@ "type": "string", "enum": ["metagenome", "metatranscriptome"], "errorMessage": "Assembly type should be metagenome or metatranscriptome", - "description": "Assembly type: `metagenome` or `metatranscriptome`. Written to the ENA assembly manifest as ASSEMBLY_TYPE 'primary metagenome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/primary.html) or 'metatranscriptome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metatranscriptome.html) respectively.", + "description": "Assembly type: `metagenome` or `metatranscriptome`. Written to the ENA assembly manifest as ASSEMBLY_TYPE 'primary metagenome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metagenome/primary.html) or 'metatranscriptome' (ENA docs: https://ena-docs.readthedocs.io/en/latest/submit/assembly/metatranscriptome.html) respectively. Default: `metagenome`.", "default": "metagenome", "meta": ["assembly_type"] } diff --git a/conf/test_mag_no_quality_euk_without_ena_interaction.conf b/conf/test_mag_no_quality_euk_skip_ena_queries.conf similarity index 93% rename from conf/test_mag_no_quality_euk_without_ena_interaction.conf rename to conf/test_mag_no_quality_euk_skip_ena_queries.conf index 4ce99771..f15db4a6 100644 --- a/conf/test_mag_no_quality_euk_without_ena_interaction.conf +++ b/conf/test_mag_no_quality_euk_skip_ena_queries.conf @@ -28,7 +28,7 @@ process { params { config_profile_name = 'Test --mode mags no_quality profile' - config_profile_description = 'Single-case eukaryotic MAG test with missing completeness and contamination values' + config_profile_description = 'Single-case eukaryotic MAG test with missing completeness and contamination values. Test skips all modules using ENA queries.' // Input data input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_quality_euk.csv' diff --git a/conf/test_mag_no_rna_presence_without_ena_interaction.conf b/conf/test_mag_no_rna_skip_ena_queries.conf similarity index 90% rename from conf/test_mag_no_rna_presence_without_ena_interaction.conf rename to conf/test_mag_no_rna_skip_ena_queries.conf index 3e07f4b8..2b9c00b5 100644 --- a/conf/test_mag_no_rna_presence_without_ena_interaction.conf +++ b/conf/test_mag_no_rna_skip_ena_queries.conf @@ -23,8 +23,8 @@ process { } params { - config_profile_name = 'Test --mode mags no_rna_presence profile' - config_profile_description = 'Single-case MAG test with missing RNA_presence value' + config_profile_name = 'Test --mode mags no_rna profile' + config_profile_description = 'Single-case MAG test with missing RNA_presence value. Test skips all modules using ENA queries.' // Input data input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_rna_presence.csv' diff --git a/conf/test_mag_no_taxonomy_without_ena_interaction.conf b/conf/test_mag_no_taxonomy_skip_ena_queries.conf similarity index 95% rename from conf/test_mag_no_taxonomy_without_ena_interaction.conf rename to conf/test_mag_no_taxonomy_skip_ena_queries.conf index 54355a70..063be2cc 100644 --- a/conf/test_mag_no_taxonomy_without_ena_interaction.conf +++ b/conf/test_mag_no_taxonomy_skip_ena_queries.conf @@ -24,7 +24,7 @@ process { params { config_profile_name = 'Test --mode mags no_taxonomy profile' - config_profile_description = 'Single-case MAG test with missing NCBI_lineage value' + config_profile_description = 'Single-case MAG test with missing NCBI_lineage value. Test skips all modules using ENA queries.' // Input data input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_taxonomy.csv' diff --git a/conf/test_mag_one_contig.conf b/conf/test_mag_one_contig_skip_ena_queries.conf similarity index 81% rename from conf/test_mag_one_contig.conf rename to conf/test_mag_one_contig_skip_ena_queries.conf index 06ec0ec1..3c4656d2 100644 --- a/conf/test_mag_one_contig.conf +++ b/conf/test_mag_one_contig_skip_ena_queries.conf @@ -16,19 +16,22 @@ process { memory: '12.GB', time: '1.h' ] + + withName: 'REGISTERSTUDY|SUBMIT|CREATE_MANIFESTS' { + ext.when = false + } } params { config_profile_name = 'Test --mode mags one_contig profile' - config_profile_description = 'Single-case MAG test with one contig assembly' + config_profile_description = 'Single-case MAG test with one contig assembly. No submission performed, invalid_fastas.tsv file generated. Test skips all modules using ENA queries.' // Input data input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_one_contig.csv' outdir = 'test_output' mode = "mags" - submission_study = null - study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' + submission_study = "TEST_STUDY" centre_name = "TEST_CENTER" test_upload = true diff --git a/docs/methods.md b/docs/methods.md index d56fc25a..0cc5ca5a 100644 --- a/docs/methods.md +++ b/docs/methods.md @@ -149,7 +149,7 @@ The final `True`/`False` decision is then merged back into the submission metada ### Completeness and contamination assessment -Completeness and contamination are evaluated in a genome quality step split by domain: prokaryotic genomes go to the `GENOME_EVALUATION_PROKS` subworkflow and eukaryotic genomes to the `GENOME_EVALUATION_EUKS` subworkflow. +Completeness and contamination are evaluated in a genome quality step split by domain: prokaryotic genomes go to the `PROKARYOTIC_GENOME_EVALUATION` subworkflow and eukaryotic genomes to the `EUKARYOTIC_GENOME_EVALUATION` subworkflow. The workflow checks three samplesheet fields: `completeness`, `contamination`, and `stats_generation_software`. If all three are already present, those values are reused. If any of them is missing, the genome is analysed with a tool selected by its domain. diff --git a/docs/usage.md b/docs/usage.md index 9bfd2b74..056c9e81 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -9,6 +9,7 @@ - [Introduction](#introduction) - [Before you start](#before-you-start) - [Submission study](#submission-study) +- [Production vs Test submission](#production-vs-test-submission) - [Data privacy](#data-privacy) - [Third party assemblies (TPA)](#third-party-assemblies-tpa) - [`reads` mode](#reads-mode) @@ -116,6 +117,21 @@ study-soil-2026 Soil microbiome study Survey of soil microbiota | `existing_study_type` | No | ENA study type (e.g. `Metagenomics`, `Other`). | | `new_study_type` | No | Custom study type. Only used when `existing_study_type` is set to `Other`. | +## Production vs Test submission + +Real data submissions are always uploaded to the **ENA Production** server (alternatively called LIVE). + +If you want to test the submission process without making a permanent submission, you can use the ENA Test server (alternatively called TEST). This allows you to create all the necessary records (e.g. studies and samples) and upload your data for testing. Submissions to the TEST server are automatically deleted after 24 hours. Check [ENA documentation](https://ena-docs.readthedocs.io/en/latest/submit/general-guide/interactive.html) for more information. + +Alternatively, you can use _validation_ mode to check whether your submission files are valid without uploading any data to either the TEST or LIVE server. This is particularly useful during development and for checking files before a real submission. Those procedures are controlled with `--test_upload` and `--webincli_mode` arguments described in [Running the pipeline](#running-the-pipeline). + +| `--test-upload` | `--webincli_mode` | Action | +| --------------- | ----------------- |-----------------------------------------------------------------------------| +| `false` | `submit` | Submission to LIVE server. | +| `true` | `submit` | Submission to TEST server. Pipeline default settings. | +| `false` | `validate` | Registration of records on LIVE server without upload. **Restricted mode**. | +| `true` | `validate` | Registration of records on TEST server without upload. | + ## Data privacy You can reference private ENA data if you have access to it via your Webin account (it was submitted previously under your credentials). To use private data accessions in your submission metadata, specify the `--is_private` flag. The pipeline will then use your provided Webin credentials to fetch the required metadata. @@ -426,17 +442,17 @@ nextflow run nf-core/seqsubmit \ Parameters common to all modes: -| Parameter | Required | Description | -| ------------------------------------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--mode` | Yes | Type of the data to be submitted. Options: `mags`, `bins`, `metagenomic_assemblies`, `reads`. | -| `--input` | Yes | Path to samplesheet describing the data to be submitted (supported formats: csv, tsv, yaml, yml, json). Columns/fields depend on the pipeline mode. See [usage docs](https://nf-co.re/seqsubmit/usage#samplesheet-input). | -| `--outdir` | Yes | Path to the output directory for pipeline results. You have to use absolute paths to storage on Cloud infrastructure. | -| `--submission_study` OR `--study_metadata` | Yes (one of) | ENA study accession (PRJ/ERP) to submit the data to OR metadata file in JSON/TSV/CSV format to register a new study. | -| `--centre_name` | Yes | Name of the submitter's organisation (mandatory for broker accounts). | -| `--test_upload` | No | Submit to the ENA TEST server instead of the LIVE server. Use that flag for development purposes or for validation of your submissions. Submission would be done to TEST ENA server instead of LIVE server. TEST server holds data 24h and removes afterwords. LIVE server does not have option to modify your submission, you can only suppress data and re-upload. Default: `true`. | -| `--webincli_mode` | No | Webin-CLI mode for ENA interaction: `submit` uploads data, `validate` performs validation only. `validate` mode checks correctness of manifest files, data access and validity. `submit` mode does validation and push data to ENA server. Default: `submit`. | -| `--is_private` | No | Use if you are referencing private data accessions in your submission. Set to true when the referenced project/reads/assembly are still private in ENA, so metadata is fetched via authenticated access. Does NOT affect the privacy of your own submission, use --release_date for that. Default: `false`. | -| `--release_date` | No | Use if you want to keep your data private in ENA after submission until a particular date (format: YYYY-MM-DD). Data stays private until this date, then is automatically released and indexed by ENA. Must be no more than 2 years from today. Omit to release the study publicly immediately. | +| Parameter | Required | Description | +| ------------------------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--mode` | Yes | Type of the data to be submitted. Options: `mags`, `bins`, `metagenomic_assemblies`, `reads`. | +| `--input` | Yes | Path to samplesheet describing the data to be submitted (supported formats: csv, tsv, yaml, yml, json). Columns/fields depend on the pipeline mode. See [usage docs](https://nf-co.re/seqsubmit/usage#samplesheet-input). | +| `--outdir` | Yes | Path to the output directory for pipeline results. You have to use absolute paths to storage on Cloud infrastructure. | +| `--submission_study` OR `--study_metadata` | Yes (one of) | ENA study accession (PRJ/ERP) to submit the data to OR metadata file in JSON/TSV/CSV format to register a new study. | +| `--centre_name` | Yes | Name of the submitter's organisation (mandatory for broker accounts). | +| `--test_upload` | No | Submit to the ENA TEST server instead of the LIVE server. Use that flag for development purposes or for validation of your submissions. Submission would be done to TEST ENA server instead of LIVE server. TEST server holds data 24h and removes afterwords. LIVE server does not have option to modify your submission, you can only suppress data and re-upload. Default: `true`. It is restricted to use `--test-upload=false` with `--webincli_mode validate` because study and/or samples would be registered on LIVE server but data would not be submitted. | +| `--webincli_mode` | No | Webin-CLI mode for ENA interaction: `submit` uploads data, `validate` performs validation only. `validate` mode checks correctness of manifest files, data access and validity. `submit` mode does validation and push data to ENA server. Default: `submit`. | +| `--is_private` | No | Use if you are referencing private data accessions in your submission. Set to true when the referenced project/reads/assembly are still private in ENA, so metadata is fetched via authenticated access. Does NOT affect the privacy of your own submission, use --release_date for that. Default: `false`. | +| `--release_date` | No | Use if you want to keep your data private in ENA after submission until a particular date (format: YYYY-MM-DD). Data stays private until this date, then is automatically released and indexed by ENA. Must be no more than 2 years from today. Omit to release the study publicly immediately. | Each mode also has additional parameters and example commands — see its own "`` parameters and example" subsection above. diff --git a/nextflow.config b/nextflow.config index 440e76e9..e1e16efd 100644 --- a/nextflow.config +++ b/nextflow.config @@ -35,7 +35,7 @@ params { busco_db = null busco_db_lineage = 'auto_euk' save_busco_db = false - busco_clean = false + busco_clean = true // -- eukcc eukaryotic_completeness_tool = 'eukcc' eukcc_db = 'http://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_ver_1.1.tar.gz' @@ -258,10 +258,10 @@ profiles { test_mag_no_coverage_single_reads { includeConfig 'conf/test_mag_no_coverage_single_reads.conf' } test_mag_no_coverage_paired_reads { includeConfig 'conf/test_mag_no_coverage_paired_reads.conf' } test_mag_no_quality { includeConfig 'conf/test_mag_no_quality.conf' } - test_mag_no_quality_euk_without_ena_interaction { includeConfig 'conf/test_mag_no_quality_euk_without_ena_interaction.conf' } - test_mag_one_contig { includeConfig 'conf/test_mag_one_contig.conf' } - test_mag_no_rna_presence_without_ena_interaction { includeConfig 'conf/test_mag_no_rna_presence_without_ena_interaction.conf' } - test_mag_no_taxonomy_without_ena_interaction { includeConfig 'conf/test_mag_no_taxonomy_without_ena_interaction.conf' } + test_mag_no_quality_euk_skip_ena_queries { includeConfig 'conf/test_mag_no_quality_euk_skip_ena_queries.conf' } + test_mag_one_contig_skip_ena_queries { includeConfig 'conf/test_mag_one_contig_skip_ena_queries.conf' } + test_mag_no_rna_skip_ena_queries { includeConfig 'conf/test_mag_no_rna_skip_ena_queries.conf' } + test_mag_no_taxonomy_skip_ena_queries { includeConfig 'conf/test_mag_no_taxonomy_skip_ena_queries.conf' } test_assembly_complete_metadata_existing_study { includeConfig 'conf/test_assembly_complete_metadata_existing_study.config' } test_assembly_complete_metadata { includeConfig 'conf/test_assembly_complete_metadata.config' } test_assembly_no_coverage_single_reads { includeConfig 'conf/test_assembly_no_coverage_single_reads.config' } diff --git a/nextflow_schema.json b/nextflow_schema.json index fff58c6f..fd089390 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -125,7 +125,7 @@ "busco_clean": { "type": "boolean", "description": "Remove BUSCO intermediate files after each run. BUSCO creates a large number of intermediate files, which may cause problems on clusters with file number limits, particularly with many MAGs/bins. Used only with `--eukaryotic_completeness_tool busco`.", - "default": false + "default": true }, "eukcc_db": { "type": "string", @@ -320,7 +320,7 @@ "type": "boolean", "description": "Upload to ENA TEST server instead of LIVE server", "default": true, - "help_text": "Use that flag for development purposes or for validation of your submissions. Submission would be done to TEST ENA server instead of LIVE server. TEST server holds data 24h and removes afterwords. LIVE server does not have option to modify your submission, you can only suppress data and re-upload" + "help_text": "Use that flag for development purposes or for validation of your submissions. Submission would be done to TEST ENA server instead of LIVE server. TEST server holds data 24h and removes afterwords. LIVE server does not have option to modify your submission, you can only suppress data and re-upload. It is restricted to use --test-upload=false with --webincli_mode validate because study and/or samples would be registered on LIVE server but data would not be submitted." }, "is_private": { "type": "boolean", @@ -395,6 +395,29 @@ }, { "$ref": "#/$defs/pipeline_options" + }, + { + "if": { + "properties": { + "test_upload": { + "const": false + } + }, + "required": ["test_upload"] + }, + "then": { + "properties": { + "webincli_mode": { + "const": "submit" + } + }, + "required": ["webincli_mode"], + "errorMessage": { + "properties": { + "webincli_mode": "LIVE ENA submissions require webincli_mode to be 'submit'. Validation-only mode cannot be used with the LIVE server." + } + } + } } ] } diff --git a/nf-test.config b/nf-test.config index 5e4a9860..f12dc9ed 100644 --- a/nf-test.config +++ b/nf-test.config @@ -14,7 +14,7 @@ config { ignore = [ 'modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*', - 'tests/mag_no_quality_euk_without_ena_interaction.nf.test', + 'tests/mag_no_quality_euk_skip_ena_queries.nf.test', 'subworkflows/local/genome_evaluation_proks/tests/*' ] diff --git a/subworkflows/local/genome_evaluation_euks/main.nf b/subworkflows/local/genome_evaluation_euks/main.nf index ef163ae9..7879a3ef 100644 --- a/subworkflows/local/genome_evaluation_euks/main.nf +++ b/subworkflows/local/genome_evaluation_euks/main.nf @@ -21,7 +21,7 @@ include { parseStatsTable; mergeSoftware; isNotAssigned } from '../utils_nfcore_ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -workflow GENOME_EVALUATION_EUKS { +workflow EUKARYOTIC_GENOME_EVALUATION { take: ch_fasta // channel: [ val(meta), path(fasta) ] - eukaryotic genomes only diff --git a/subworkflows/local/genome_evaluation_euks/tests/main.nf.test b/subworkflows/local/genome_evaluation_euks/tests/main.nf.test index f20041e9..abb61936 100644 --- a/subworkflows/local/genome_evaluation_euks/tests/main.nf.test +++ b/subworkflows/local/genome_evaluation_euks/tests/main.nf.test @@ -1,8 +1,8 @@ nextflow_workflow { - name "Test Subworkflow GENOME_EVALUATION_EUKS" + name "Test Subworkflow EUKARYOTIC_GENOME_EVALUATION" script "../main.nf" - workflow "GENOME_EVALUATION_EUKS" + workflow "EUKARYOTIC_GENOME_EVALUATION" tag "subworkflows" tag "subworkflows_local" @@ -28,7 +28,7 @@ nextflow_workflow { input[2] = null // busco_db input[3] = true // busco_clean input[4] = 'eukcc' // eukaryotic_completeness_tool - input[5] = 'https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz' // eukcc_db + input[5] = '.' // fake folder replacing eukcc_db because test DB https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz is big """ } } @@ -62,7 +62,7 @@ nextflow_workflow { input[2] = null // busco_db - BUSCO downloads lineages itself input[3] = true input[4] = 'busco' - input[5] = 'https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz' + input[5] = '.' // fake folder replacing eukcc_db """ } } @@ -135,7 +135,7 @@ nextflow_workflow { input[2] = null input[3] = true input[4] = 'eukcc' - input[5] = 'https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz' + input[5] = '.' // fake folder replacing eukcc_db """ } } diff --git a/subworkflows/local/genome_evaluation_proks/main.nf b/subworkflows/local/genome_evaluation_proks/main.nf index dc71d670..fe1ef7b5 100644 --- a/subworkflows/local/genome_evaluation_proks/main.nf +++ b/subworkflows/local/genome_evaluation_proks/main.nf @@ -18,7 +18,7 @@ include { parseStatsTable; mergeSoftware } from '../utils_nfcore_seqsubmit_pipel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -workflow GENOME_EVALUATION_PROKS { +workflow PROKARYOTIC_GENOME_EVALUATION { take: ch_fasta // channel: [ val(meta), path(fasta) ] - prokaryotic genomes only diff --git a/subworkflows/local/genome_evaluation_proks/tests/main.nf.test b/subworkflows/local/genome_evaluation_proks/tests/main.nf.test index f24ce604..bdac14a5 100644 --- a/subworkflows/local/genome_evaluation_proks/tests/main.nf.test +++ b/subworkflows/local/genome_evaluation_proks/tests/main.nf.test @@ -1,8 +1,8 @@ nextflow_workflow { - name "Test Subworkflow GENOME_EVALUATION_PROKS" + name "Test Subworkflow PROKARYOTIC_GENOME_EVALUATION" script "../main.nf" - workflow "GENOME_EVALUATION_PROKS" + workflow "PROKARYOTIC_GENOME_EVALUATION" tag "subworkflows" tag "subworkflows_local" diff --git a/tests/mag_no_quality_euk_without_ena_interaction.nf.test b/tests/mag_no_quality_euk_skip_ena_queries.nf.test similarity index 93% rename from tests/mag_no_quality_euk_without_ena_interaction.nf.test rename to tests/mag_no_quality_euk_skip_ena_queries.nf.test index 5266a4b2..75ade752 100644 --- a/tests/mag_no_quality_euk_without_ena_interaction.nf.test +++ b/tests/mag_no_quality_euk_skip_ena_queries.nf.test @@ -4,10 +4,10 @@ nextflow_pipeline { script "../main.nf" tag "pipeline" tag "mode_mag" - tag "test_mag_no_quality_euk_without_ena_interaction" - profile "test_mag_no_quality_euk_without_ena_interaction" + tag "test_mag_no_quality_euk_skip_ena_queries" + profile "test_mag_no_quality_euk_skip_ena_queries" - test("-profile test_mag_no_quality_euk_without_ena_interaction") { + test("-profile test_mag_no_quality_euk_skip_ena_queries") { when { params { diff --git a/tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap b/tests/mag_no_quality_euk_skip_ena_queries.nf.test.snap similarity index 97% rename from tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap rename to tests/mag_no_quality_euk_skip_ena_queries.nf.test.snap index d8dec831..d23244ce 100644 --- a/tests/mag_no_quality_euk_without_ena_interaction.nf.test.snap +++ b/tests/mag_no_quality_euk_skip_ena_queries.nf.test.snap @@ -1,5 +1,5 @@ { - "-profile test_mag_no_quality_euk_without_ena_interaction": { + "-profile test_mag_no_quality_euk_skip_ena_queries": { "content": [ 7, { diff --git a/tests/mag_no_rna_presence_without_ena_interaction.nf.test b/tests/mag_no_rna_skip_ena_queries.nf.test similarity index 92% rename from tests/mag_no_rna_presence_without_ena_interaction.nf.test rename to tests/mag_no_rna_skip_ena_queries.nf.test index b03046a4..7778deb9 100644 --- a/tests/mag_no_rna_presence_without_ena_interaction.nf.test +++ b/tests/mag_no_rna_skip_ena_queries.nf.test @@ -4,10 +4,10 @@ nextflow_pipeline { script "../main.nf" tag "pipeline" tag "mode_mag" - tag "test_mag_no_rna_presence_without_ena_interaction" - profile "test_mag_no_rna_presence_without_ena_interaction" + tag "test_mag_no_rna_skip_ena_queries" + profile "test_mag_no_rna_skip_ena_queries" - test("-profile test_mag_no_rna_presence_without_ena_interaction") { + test("-profile test_mag_no_rna_skip_ena_queries") { when { params { diff --git a/tests/mag_no_rna_presence_without_ena_interaction.nf.test.snap b/tests/mag_no_rna_skip_ena_queries.nf.test.snap similarity index 98% rename from tests/mag_no_rna_presence_without_ena_interaction.nf.test.snap rename to tests/mag_no_rna_skip_ena_queries.nf.test.snap index 91878700..c3836415 100644 --- a/tests/mag_no_rna_presence_without_ena_interaction.nf.test.snap +++ b/tests/mag_no_rna_skip_ena_queries.nf.test.snap @@ -1,5 +1,5 @@ { - "-profile test_mag_no_rna_presence_without_ena_interaction": { + "-profile test_mag_no_rna_skip_ena_queries": { "content": [ 12, { diff --git a/tests/mag_no_taxonomy_without_ena_interaction.nf.test b/tests/mag_no_taxonomy_skip_ena_queries.nf.test similarity index 89% rename from tests/mag_no_taxonomy_without_ena_interaction.nf.test rename to tests/mag_no_taxonomy_skip_ena_queries.nf.test index 903de8c5..d78cfecf 100644 --- a/tests/mag_no_taxonomy_without_ena_interaction.nf.test +++ b/tests/mag_no_taxonomy_skip_ena_queries.nf.test @@ -4,10 +4,10 @@ nextflow_pipeline { script "../main.nf" tag "pipeline" tag "mode_mag" - tag "test_mag_no_taxonomy_without_ena_interaction" - profile "test_mag_no_taxonomy_without_ena_interaction" + tag "test_mag_no_taxonomy_skip_ena_queries" + profile "test_mag_no_taxonomy_skip_ena_queries" - test("-profile test_mag_no_taxonomy_without_ena_interaction") { + test("-profile test_mag_no_taxonomy_skip_ena_queries") { when { params { diff --git a/tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap b/tests/mag_no_taxonomy_skip_ena_queries.nf.test.snap similarity index 97% rename from tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap rename to tests/mag_no_taxonomy_skip_ena_queries.nf.test.snap index 9093f8e8..9cbbf2dd 100644 --- a/tests/mag_no_taxonomy_without_ena_interaction.nf.test.snap +++ b/tests/mag_no_taxonomy_skip_ena_queries.nf.test.snap @@ -1,5 +1,5 @@ { - "-profile test_mag_no_taxonomy_without_ena_interaction": { + "-profile test_mag_no_taxonomy_skip_ena_queries": { "content": [ 8, { diff --git a/tests/mag_one_contig.nf.test b/tests/mag_one_contig_skip_ena_queries.nf.test similarity index 85% rename from tests/mag_one_contig.nf.test rename to tests/mag_one_contig_skip_ena_queries.nf.test index 1904dff7..fe6dcad4 100644 --- a/tests/mag_one_contig.nf.test +++ b/tests/mag_one_contig_skip_ena_queries.nf.test @@ -1,13 +1,13 @@ nextflow_pipeline { - name "Test genome submission workflow - one_contig" + name "Test genome submission workflow - one_contig. No ENA interaction." script "../main.nf" tag "pipeline" tag "mode_mag" - tag "test_mag_one_contig" - profile "test_mag_one_contig" + tag "test_mag_one_contig_skip_ena_queries" + profile "test_mag_one_contig_skip_ena_queries" - test("-profile test_mag_one_contig") { + test("-profile test_mag_one_contig_skip_ena_queries") { when { params { diff --git a/tests/mag_one_contig.nf.test.snap b/tests/mag_one_contig_skip_ena_queries.nf.test.snap similarity index 95% rename from tests/mag_one_contig.nf.test.snap rename to tests/mag_one_contig_skip_ena_queries.nf.test.snap index be530c2e..8cc913f1 100644 --- a/tests/mag_one_contig.nf.test.snap +++ b/tests/mag_one_contig_skip_ena_queries.nf.test.snap @@ -1,5 +1,5 @@ { - "-profile test_mag_one_contig": { + "-profile test_mag_one_contig_skip_ena_queries": { "content": [ 1, { diff --git a/workflows/genomesubmit.nf b/workflows/genomesubmit.nf index e427da44..29ac1c53 100644 --- a/workflows/genomesubmit.nf +++ b/workflows/genomesubmit.nf @@ -16,8 +16,8 @@ include { MULTIQC } from '../modules/nf-core/multi include { paramsSummaryMap } from 'plugin/nf-schema' include { FASTA_VALIDATION } from '../subworkflows/local/fasta_validation/main' -include { GENOME_EVALUATION_EUKS } from '../subworkflows/local/genome_evaluation_euks/main' -include { GENOME_EVALUATION_PROKS } from '../subworkflows/local/genome_evaluation_proks/main' +include { EUKARYOTIC_GENOME_EVALUATION } from '../subworkflows/local/genome_evaluation_euks/main' +include { PROKARYOTIC_GENOME_EVALUATION } from '../subworkflows/local/genome_evaluation_proks/main' include { RNA_DETECTION } from '../subworkflows/local/rna_detection/main' include { FASTA_CLASSIFY_CATPACK } from '../subworkflows/nf-core/fasta_classify_catpack/main' @@ -119,13 +119,13 @@ workflow GENOMESUBMIT { // --------- Taxonomy branched_taxonomy_results = fasta_updated_with_coverage .branch { meta, _fasta -> - genome_taxonomy_input: !(meta.NCBI_lineage) + taxonomy_absent: !(meta.NCBI_lineage) taxonomy_present: true // Everything else goes here } // Change extension for all files required taxonomy to .fasta because CATPACK requires suffix as input RENAME_FASTA_FOR_CATPACK ( - branched_taxonomy_results.genome_taxonomy_input + branched_taxonomy_results.taxonomy_absent ) // build input structures for CAT_DB depending on what provided as input @@ -148,11 +148,12 @@ workflow GENOMESUBMIT { ) fasta_updated_with_taxonomy = FASTA_CLASSIFY_CATPACK.out.bat_classification - .join(branched_taxonomy_results.genome_taxonomy_input) + .join(branched_taxonomy_results.taxonomy_absent) .map { meta, taxa_tsv, fasta -> def lines = taxa_tsv.readLines() def updated_meta = meta.clone() // support for empty taxonomy files required for -stub mode + // skip header and take 4th column from table corresponding to lineage updated_meta.NCBI_lineage = lines ? lines[1].split('\t')[3] : null return [updated_meta, fasta] } @@ -161,10 +162,18 @@ workflow GENOMESUBMIT { // --------- Add meta.domain value for eukaryotes (euk) and prokaryotes (bac and arc) domain_identification = fasta_updated_with_taxonomy .map { meta, fasta -> - def lineage = meta.NCBI_lineage + def lineage = meta.NCBI_lineage.toLowerCase() def parts = lineage.tokenize(';').collect { p -> p.trim() } - def is_euk = lineage.contains('ukaryot') || parts.contains('2759') - def is_arc = lineage.contains('rchaea') || parts.contains('2157') + def is_euk = parts.any { it == 'eukaryot' } || parts.contains('2759') + def is_arc = parts.any { it == 'archaea' } || parts.contains('2157') + def is_bac = parts.any { it == 'bacteria' } || parts.contains('2') + + if (!is_euk && !is_arc && !is_bac) { + throw new IllegalStateException( + "Unassigned or unrecognized taxonomic lineage for ${meta.id}: '${meta.NCBI_lineage}. \ + Provide NCBI format taxonomy or remove it from MAG/bin submission'" + ) + } [ meta + [domain: is_euk ? 'euk' : (is_arc ? 'arc' : 'bac')], fasta ] } @@ -204,18 +213,18 @@ workflow GENOMESUBMIT { // Split genomes to evaluate into prokaryotes and eukaryotes domain_split_stats = branched_stats_results.genome_evaluation_input .branch { meta, _fasta -> - proks: meta.domain in ['arc', 'bac'] - euks: meta.domain == 'euk' + prokaryotes: meta.domain in ['arc', 'bac'] + eukaryotes: meta.domain == 'euk' } - GENOME_EVALUATION_PROKS ( - domain_split_stats.proks, + PROKARYOTIC_GENOME_EVALUATION ( + domain_split_stats.prokaryotes, checkm2_db, checkm2_db_download_id ) - GENOME_EVALUATION_EUKS ( - domain_split_stats.euks, + EUKARYOTIC_GENOME_EVALUATION ( + domain_split_stats.eukaryotes, busco_db_lineage, busco_db, busco_clean, @@ -224,9 +233,9 @@ workflow GENOMESUBMIT { ) // Update metadata with completeness and contamination from CheckM2 (prokaryotes) or EukCC/BUSCO (eukaryotes) - // Eukaryotic genomes without completeness or contamination are filtered out in GENOME_EVALUATION_EUKS - fasta_updated_with_stats = GENOME_EVALUATION_PROKS.out.stats - .mix(GENOME_EVALUATION_EUKS.out.stats) + // Eukaryotic genomes without completeness or contamination are filtered out in EUKARYOTIC_GENOME_EVALUATION + fasta_updated_with_stats = PROKARYOTIC_GENOME_EVALUATION.out.stats + .mix(EUKARYOTIC_GENOME_EVALUATION.out.stats) .join(branched_stats_results.genome_evaluation_input) .map { meta, completeness, contamination, stats_software, fasta -> def updated_meta = meta + [ From 4718f18a691f07214be5370d93d29268244fea10 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Thu, 29 Oct 2026 23:37:45 +0000 Subject: [PATCH 20/24] fixes after review lint --- docs/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index 056c9e81..fe61c540 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -126,7 +126,7 @@ If you want to test the submission process without making a permanent submission Alternatively, you can use _validation_ mode to check whether your submission files are valid without uploading any data to either the TEST or LIVE server. This is particularly useful during development and for checking files before a real submission. Those procedures are controlled with `--test_upload` and `--webincli_mode` arguments described in [Running the pipeline](#running-the-pipeline). | `--test-upload` | `--webincli_mode` | Action | -| --------------- | ----------------- |-----------------------------------------------------------------------------| +| --------------- | ----------------- | --------------------------------------------------------------------------- | | `false` | `submit` | Submission to LIVE server. | | `true` | `submit` | Submission to TEST server. Pipeline default settings. | | `false` | `validate` | Registration of records on LIVE server without upload. **Restricted mode**. | From eb6c99986e07d843ec230b1fea42b598659a690c Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Thu, 29 Oct 2026 23:43:29 +0000 Subject: [PATCH 21/24] fixes after review lint --- docs/usage.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index fe61c540..ba9cd8ad 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -125,12 +125,12 @@ If you want to test the submission process without making a permanent submission Alternatively, you can use _validation_ mode to check whether your submission files are valid without uploading any data to either the TEST or LIVE server. This is particularly useful during development and for checking files before a real submission. Those procedures are controlled with `--test_upload` and `--webincli_mode` arguments described in [Running the pipeline](#running-the-pipeline). -| `--test-upload` | `--webincli_mode` | Action | -| --------------- | ----------------- | --------------------------------------------------------------------------- | -| `false` | `submit` | Submission to LIVE server. | -| `true` | `submit` | Submission to TEST server. Pipeline default settings. | -| `false` | `validate` | Registration of records on LIVE server without upload. **Restricted mode**. | -| `true` | `validate` | Registration of records on TEST server without upload. | +| `--test_upload` | `--webincli_mode` | Action | +|-----------------| ----------------- |------------------------------------------------------------------------------------| +| `false` | `submit` | Submission to LIVE server. | +| `true` | `submit` | Submission to TEST server. Pipeline default settings. | +| `false` | `validate` | Registration of records on LIVE server without upload. **Restricted combination**. | +| `true` | `validate` | Registration of records on TEST server without upload. | ## Data privacy From aaf9a144877022954ad2d63b1ccfdfed6c5a1c9f Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Fri, 30 Oct 2026 11:13:12 +0000 Subject: [PATCH 22/24] fixes domain assign --- docs/usage.md | 2 +- workflows/genomesubmit.nf | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index acebb02e..5cc94df3 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -126,7 +126,7 @@ If you want to test the submission process without making a permanent submission Alternatively, you can use _validation_ mode to check whether your submission files are valid without uploading any data to either the TEST or LIVE server. This is particularly useful during development and for checking files before a real submission. Those procedures are controlled with `--test_upload` and `--webincli_mode` arguments described in [Running the pipeline](#running-the-pipeline). | `--test_upload` | `--webincli_mode` | Action | -|-----------------| ----------------- |------------------------------------------------------------------------------------| +| --------------- | ----------------- | ---------------------------------------------------------------------------------- | | `false` | `submit` | Submission to LIVE server. | | `true` | `submit` | Submission to TEST server. Pipeline default settings. | | `false` | `validate` | Registration of records on LIVE server without upload. **Restricted combination**. | diff --git a/workflows/genomesubmit.nf b/workflows/genomesubmit.nf index 29ac1c53..d3665a48 100644 --- a/workflows/genomesubmit.nf +++ b/workflows/genomesubmit.nf @@ -164,9 +164,9 @@ workflow GENOMESUBMIT { .map { meta, fasta -> def lineage = meta.NCBI_lineage.toLowerCase() def parts = lineage.tokenize(';').collect { p -> p.trim() } - def is_euk = parts.any { it == 'eukaryot' } || parts.contains('2759') - def is_arc = parts.any { it == 'archaea' } || parts.contains('2157') - def is_bac = parts.any { it == 'bacteria' } || parts.contains('2') + def is_euk = lineage.contains('eukaryot') || parts.contains('2759') + def is_arc = lineage.contains('archaea') || parts.contains('2157') + def is_bac = lineage.contains('bacteria') || parts.contains('2') if (!is_euk && !is_arc && !is_bac) { throw new IllegalStateException( From 70bf91190b59914fdc5457748d722d50399ff867 Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Fri, 30 Oct 2026 14:24:05 +0000 Subject: [PATCH 23/24] simplify tests --- ..._mag_no_coverage_pe_skip_ena_queries.conf} | 9 +- ..._mag_no_coverage_se_skip_ena_queries.conf} | 9 +- docs/usage.md | 7 +- nextflow.config | 40 ++-- nextflow_schema.json | 50 ++-- nf-test.config | 4 +- .../genome_evaluation_euks/tests/main.nf.test | 202 ---------------- .../tests/main_stub.nf.test | 215 ++++++++++++++++++ ...in.nf.test.snap => main_stub.nf.test.snap} | 0 ...g_no_coverage_pe_skip_ena_queries.nf.test} | 8 +- ...coverage_pe_skip_ena_queries.nf.test.snap} | 43 +--- ...g_no_coverage_se_skip_ena_queries.nf.test} | 8 +- ...coverage_se_skip_ena_queries.nf.test.snap} | 43 +--- 13 files changed, 295 insertions(+), 343 deletions(-) rename conf/{test_mag_no_coverage_paired_reads.conf => test_mag_no_coverage_pe_skip_ena_queries.conf} (84%) rename conf/{test_mag_no_coverage_single_reads.conf => test_mag_no_coverage_se_skip_ena_queries.conf} (84%) create mode 100644 subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test rename subworkflows/local/genome_evaluation_euks/tests/{main.nf.test.snap => main_stub.nf.test.snap} (100%) rename tests/{mag_no_coverage_paired_reads.nf.test => mag_no_coverage_pe_skip_ena_queries.nf.test} (88%) rename tests/{mag_no_coverage_paired_reads.nf.test.snap => mag_no_coverage_pe_skip_ena_queries.nf.test.snap} (54%) rename tests/{mag_no_coverage_single_reads.nf.test => mag_no_coverage_se_skip_ena_queries.nf.test} (88%) rename tests/{mag_no_coverage_single_reads.nf.test.snap => mag_no_coverage_se_skip_ena_queries.nf.test.snap} (54%) diff --git a/conf/test_mag_no_coverage_paired_reads.conf b/conf/test_mag_no_coverage_pe_skip_ena_queries.conf similarity index 84% rename from conf/test_mag_no_coverage_paired_reads.conf rename to conf/test_mag_no_coverage_pe_skip_ena_queries.conf index 920e9263..a9eaa016 100644 --- a/conf/test_mag_no_coverage_paired_reads.conf +++ b/conf/test_mag_no_coverage_pe_skip_ena_queries.conf @@ -16,19 +16,22 @@ process { memory: '12.GB', time: '1.h' ] + + withName: 'REGISTERSTUDY|SUBMIT|CREATE_MANIFESTS' { + ext.when = false + } } params { config_profile_name = 'Test --mode mags no_coverage_paired_reads profile' - config_profile_description = 'Single-case MAG test with missing genome_coverage and paired-end reads' + config_profile_description = 'Single-case MAG test with missing genome_coverage and paired-end reads. Test skips all modules using ENA queries.' // Input data input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_coverage_paired_reads.csv' outdir = 'test_output' mode = "mags" - submission_study = null - study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' + submission_study = "TEST_STUDY" centre_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_mag_no_coverage_single_reads.conf b/conf/test_mag_no_coverage_se_skip_ena_queries.conf similarity index 84% rename from conf/test_mag_no_coverage_single_reads.conf rename to conf/test_mag_no_coverage_se_skip_ena_queries.conf index ebbc5ce3..52ffcab5 100644 --- a/conf/test_mag_no_coverage_single_reads.conf +++ b/conf/test_mag_no_coverage_se_skip_ena_queries.conf @@ -16,19 +16,22 @@ process { memory: '12.GB', time: '1.h' ] + + withName: 'REGISTERSTUDY|SUBMIT|CREATE_MANIFESTS' { + ext.when = false + } } params { config_profile_name = 'Test --mode mags no_coverage_single_reads profile' - config_profile_description = 'Single-case MAG test with missing genome_coverage and single-end reads' + config_profile_description = 'Single-case MAG test with missing genome_coverage and single-end reads. Test skips all modules using ENA queries.' // Input data input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_no_coverage_single_reads.csv' outdir = 'test_output' mode = "mags" - submission_study = null - study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' + submission_study = "TEST_STUDY" centre_name = "TEST_CENTER" test_upload = true diff --git a/docs/usage.md b/docs/usage.md index 5cc94df3..9ae37709 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -346,7 +346,7 @@ If `genome_coverage`, `stats_generation_software`, `completeness`, `contaminatio ### Preparing the CheckM2, EukCC, BUSCO and CAT_pack databases -`mags` and `bins` submission modes use CheckM2 (prokaryotes), EukCC and optionally BUSCO (eukaryotes) and CAT_pack tools that require specialized databases for completeness/contamination assessment and taxonomy assignment. +`mags` and `bins` submission modes use [CheckM2](https://github.com/chklovski/CheckM2) (prokaryotes), [EukCC](https://github.com/EBI-Metagenomics/EukCC) and optionally [BUSCO](https://busco.ezlab.org/busco_userguide.html) (eukaryotes) and [CAT_pack](https://github.com/MGXlab/CAT_pack) tools that require specialized databases for completeness/contamination assessment and taxonomy assignment. You can either provide pre-existing databases or let the pipeline prepare them during execution. @@ -365,8 +365,6 @@ In particular, the CAT_pack database is extremely large and may take a long time - CAT_pack: - provide the path to a local database (containing `tax/` and `db/` folders or a `tar.gz` archive) with `--cat_db`, otherwise the pipeline builds CAT_pack DB from NCBI non-redundant protein database (`nr`). -See the [CAT_pack documentation](https://github.com/MGXlab/CAT_pack), [CheckM2 documentation](https://github.com/chklovski/CheckM2), [EukCC documentation](https://eukcc.readthedocs.io) and [BUSCO documentation](https://busco.ezlab.org/busco_userguide.html) for more details on usage and creation of databases. - Databases created/downloaded by the pipeline are published under: `/databases/`. In subsequent pipeline runs you can reuse them using `--cat_db /databases/cat_pack/` and `--checkm2_db /databases/checkm2/`. @@ -408,9 +406,10 @@ nextflow run nf-core/seqsubmit \ - **Viral bins/MAGs**: Submitting viral genomes that require additional metadata generation is not supported. For such genomes tRNA and rRNA prediction, quality assessment (completeness/contamination estimation) and taxonomy assignment are not implemented. If all the required metadata (`completeness`, `contamination`, `stats_generation_software`, `RNA_presence` and `NCBI_lineage`) is already provided in the samplesheet, viral bins/MAGs can still be submitted normally. Tracked in [issue #63](https://github.com/nf-core/seqsubmit/issues/63). -- **Domain assignment**: the domain of each genome (bacteria, archaea or eukaryote) is decided from `NCBI_lineage` (provided in the samplesheet or assigned by CAT_pack). Genomes whose lineage does not contain Eukaryota/`2759` or Archaea/`2157` are processed as bacteria, so a missing or incorrect lineage leads to prokaryotic tools being used for that genome. +- **Domain assignment**: the domain of each genome (bacteria, archaea or eukaryote) is decided from `NCBI_lineage` (provided in the samplesheet or assigned by CAT_pack). Genomes whose lineage does not contain `Eukaryota`/`2759` or `Archaea`/`2157` or `Bacteria`/`2` are raising pipeline error. - **Eukaryotic bins/MAGs**: + - Taxonomic lineage assignment is implemented using CAT_pack that is using Prodigal (prokaryotic gene caller) which can raise errors on long sequences. - EukCC database (`--eukcc_db`) is downloaded and extracted in every run unless a local folder is provided. - BUSCO is used only for completeness, contamination is always taken from EukCC (or from the samplesheet). - If EukCC finds no marker genes or MetaEuk predicts no proteins for a genome, completeness and contamination stay empty for that genome. The same happens for completeness when BUSCO finds no genes. diff --git a/nextflow.config b/nextflow.config index f443256b..be9ad8cd 100644 --- a/nextflow.config +++ b/nextflow.config @@ -251,25 +251,25 @@ profiles { singularity.runOptions = '--nv' } - test { includeConfig 'conf/test.config' } - test_full { includeConfig 'conf/test_full.config' } - test_mag_complete_metadata_existing_study { includeConfig 'conf/test_mag_complete_metadata_existing_study.conf' } - test_mag_complete_metadata { includeConfig 'conf/test_mag_complete_metadata.config' } - test_mag_no_coverage_single_reads { includeConfig 'conf/test_mag_no_coverage_single_reads.conf' } - test_mag_no_coverage_paired_reads { includeConfig 'conf/test_mag_no_coverage_paired_reads.conf' } - test_mag_no_quality { includeConfig 'conf/test_mag_no_quality.conf' } - test_mag_no_quality_euk_skip_ena_queries { includeConfig 'conf/test_mag_no_quality_euk_skip_ena_queries.conf' } - test_mag_one_contig_skip_ena_queries { includeConfig 'conf/test_mag_one_contig_skip_ena_queries.conf' } - test_mag_no_rna_skip_ena_queries { includeConfig 'conf/test_mag_no_rna_skip_ena_queries.conf' } - test_mag_no_taxonomy_skip_ena_queries { includeConfig 'conf/test_mag_no_taxonomy_skip_ena_queries.conf' } - test_assembly_complete_metadata_existing_study { includeConfig 'conf/test_assembly_complete_metadata_existing_study.config' } - test_assembly_complete_metadata { includeConfig 'conf/test_assembly_complete_metadata.config' } - test_assembly_no_coverage_single_reads { includeConfig 'conf/test_assembly_no_coverage_single_reads.config' } - test_assembly_no_coverage_paired_reads { includeConfig 'conf/test_assembly_no_coverage_paired_reads.config' } - test_assembly_one_contig { includeConfig 'conf/test_assembly_one_contig.config' } - test_reads_paired { includeConfig 'conf/test_reads_paired.config' } - test_reads_long_bam { includeConfig 'conf/test_reads_long_bam.config' } - test_reads_long_bam_validate { includeConfig 'conf/test_reads_long_bam_validate.config' } + test { includeConfig 'conf/test.config' } + test_full { includeConfig 'conf/test_full.config' } + test_mag_complete_metadata_existing_study { includeConfig 'conf/test_mag_complete_metadata_existing_study.conf' } + test_mag_complete_metadata { includeConfig 'conf/test_mag_complete_metadata.config' } + test_mag_no_coverage_se_skip_ena_queries { includeConfig 'conf/test_mag_no_coverage_se_skip_ena_queries.conf' } + test_mag_no_coverage_pe_skip_ena_queries { includeConfig 'conf/test_mag_no_coverage_pe_skip_ena_queries.conf' } + test_mag_no_quality { includeConfig 'conf/test_mag_no_quality.conf' } + test_mag_no_quality_euk_skip_ena_queries { includeConfig 'conf/test_mag_no_quality_euk_skip_ena_queries.conf' } + test_mag_one_contig_skip_ena_queries { includeConfig 'conf/test_mag_one_contig_skip_ena_queries.conf' } + test_mag_no_rna_skip_ena_queries { includeConfig 'conf/test_mag_no_rna_skip_ena_queries.conf' } + test_mag_no_taxonomy_skip_ena_queries { includeConfig 'conf/test_mag_no_taxonomy_skip_ena_queries.conf' } + test_assembly_complete_metadata_existing_study { includeConfig 'conf/test_assembly_complete_metadata_existing_study.config' } + test_assembly_complete_metadata { includeConfig 'conf/test_assembly_complete_metadata.config' } + test_assembly_no_coverage_single_reads { includeConfig 'conf/test_assembly_no_coverage_single_reads.config' } + test_assembly_no_coverage_paired_reads { includeConfig 'conf/test_assembly_no_coverage_paired_reads.config' } + test_assembly_one_contig { includeConfig 'conf/test_assembly_one_contig.config' } + test_reads_paired { includeConfig 'conf/test_reads_paired.config' } + test_reads_long_bam { includeConfig 'conf/test_reads_long_bam.config' } + test_reads_long_bam_validate { includeConfig 'conf/test_reads_long_bam_validate.config' } } // Load nf-core custom profiles from different institutions @@ -361,7 +361,7 @@ manifest { email: 'sofia@ebi.ac.uk', github: 'https://github.com/ochkalova', contribution: ['author', 'maintainer'], // List of contribution types ('author', 'maintainer' or 'contributor') - orcid: '' + orcid: '0000-0003-2814-6012' ], [ name: 'Timothy Rozday', diff --git a/nextflow_schema.json b/nextflow_schema.json index fd089390..d24f69a8 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -354,7 +354,32 @@ "enum": ["submit", "validate"], "help_text": "Controls ENA Webin-CLI mode. `validate` mode checks correctness of manifest files, data access and validity. `submit` mode does validation and push data to ENA server. Default: submit." } - } + }, + "allOf": [ + { + "if": { + "properties": { + "test_upload": { + "const": false + } + }, + "required": ["test_upload"] + }, + "then": { + "properties": { + "webincli_mode": { + "const": "submit" + } + }, + "required": ["webincli_mode"], + "errorMessage": { + "properties": { + "webincli_mode": "LIVE ENA submissions require webincli_mode to be 'submit'. Validation-only mode cannot be used with the LIVE server." + } + } + } + } + ] } }, "oneOf": [ @@ -395,29 +420,6 @@ }, { "$ref": "#/$defs/pipeline_options" - }, - { - "if": { - "properties": { - "test_upload": { - "const": false - } - }, - "required": ["test_upload"] - }, - "then": { - "properties": { - "webincli_mode": { - "const": "submit" - } - }, - "required": ["webincli_mode"], - "errorMessage": { - "properties": { - "webincli_mode": "LIVE ENA submissions require webincli_mode to be 'submit'. Validation-only mode cannot be used with the LIVE server." - } - } - } } ] } diff --git a/nf-test.config b/nf-test.config index f12dc9ed..c05281c5 100644 --- a/nf-test.config +++ b/nf-test.config @@ -11,11 +11,13 @@ config { // ignore tests coming from the nf-core/modules repo // ignore euk_mags_quality assessment because Eukcc DB is big for GA // ignore genome_evaluation_proks test because checkm2 container is too big + // ignore genome_evaluation_euks test with Eukcc DB download which is big for GA ignore = [ 'modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*', 'tests/mag_no_quality_euk_skip_ena_queries.nf.test', - 'subworkflows/local/genome_evaluation_proks/tests/*' + 'subworkflows/local/genome_evaluation_proks/tests/*', + 'subworkflows/local/genome_evaluation_euks/tests/main.nf.test' ] // run all test with defined profile(s) from the main nextflow.config diff --git a/subworkflows/local/genome_evaluation_euks/tests/main.nf.test b/subworkflows/local/genome_evaluation_euks/tests/main.nf.test index abb61936..fa81d940 100644 --- a/subworkflows/local/genome_evaluation_euks/tests/main.nf.test +++ b/subworkflows/local/genome_evaluation_euks/tests/main.nf.test @@ -7,181 +7,7 @@ nextflow_workflow { tag "subworkflows" tag "subworkflows_local" tag "subworkflows/genome_evaluation_euks" - tag "busco" - tag "busco/busco" tag "eukcc" - tag "untar" - tag "gunzip" - - test("eukaryote - eukcc - stub") { - - options "-stub" - - when { - workflow { - """ - input[0] = channel.of([ - [ id:'test_euk', domain:'euk' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) - ]) - input[1] = 'auto_euk' // busco_db_lineage - input[2] = null // busco_db - input[3] = true // busco_clean - input[4] = 'eukcc' // eukaryotic_completeness_tool - input[5] = '.' // fake folder replacing eukcc_db because test DB https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz is big - """ - } - } - - then { - assert workflow.success - assertAll( - { assert snapshot(workflow.out.stats).match() }, - { assert workflow.out.stats.size() == 1 }, - { assert workflow.out.stats[0][1] == '90.0' }, // fake values assigned by eukcc in -stub - { assert workflow.out.stats[0][2] == '1.0' }, // fake values assigned by eukcc in -stub - { assert workflow.out.stats[0][3].startsWith('eukcc_v') }, - { assert !workflow.trace.tasks().any { it.name.contains('BUSCO') } } - ) - } - - } - - test("eukaryote - busco - stub") { - - options "-stub" - - when { - workflow { - """ - input[0] = channel.of([ - [ id:'test_euk', domain:'euk' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) - ]) - input[1] = 'auto_euk' - input[2] = null // busco_db - BUSCO downloads lineages itself - input[3] = true - input[4] = 'busco' - input[5] = '.' // fake folder replacing eukcc_db - """ - } - } - - then { - assert workflow.success - assertAll( - { assert snapshot(workflow.out.stats).match() }, - { assert workflow.out.stats.size() == 1 }, - // completeness is taken from BUSCO - stub writes no short summary json, so it is empty - { assert workflow.out.stats[0][1] == null }, - // contamination is always taken from EukCC - { assert workflow.out.stats[0][2] == '1.0' }, - { assert workflow.out.stats[0][3] ==~ /busco_v[^;]+;eukcc_v[^;]+/ }, - { assert workflow.trace.tasks().any { it.name.contains('BUSCO_BUSCO') } } - ) - } - - } - - test("eukaryote with contamination - busco - stub") { - - options "-stub" - - when { - workflow { - """ - input[0] = channel.of([ - [ id:'test_euk', domain:'euk', contamination:2.5, stats_generation_software:'CustomTool_v1.0' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) - ]) - input[1] = 'auto_euk' - input[2] = null - input[3] = true - input[4] = 'busco' - input[5] = null // eukcc_db is not required - EukCC is skipped - """ - } - } - - then { - assert workflow.success - assertAll( - { assert snapshot(workflow.out.stats).match() }, - { assert workflow.out.stats.size() == 1 }, - // completeness from BUSCO (stub - empty), contamination kept from samplesheet - { assert workflow.out.stats[0][1] == null }, - { assert workflow.out.stats[0][2] == 2.5 }, - // BUSCO is appended to the software given in samplesheet, EukCC is not listed - { assert workflow.out.stats[0][3] ==~ /CustomTool_v1\.0;busco_v[^;]+/ }, - { assert !workflow.trace.tasks().any { it.name =~ /EUKCC|GUNZIP_FASTA|DB_UNTAR/ } }, - { assert workflow.trace.tasks().any { it.name.contains('BUSCO_BUSCO') } } - ) - } - - } - - test("eukaryote with contamination - eukcc - stub") { - - options "-stub" - - when { - workflow { - """ - input[0] = channel.of([ - [ id:'test_euk', domain:'euk', contamination:2.5, stats_generation_software:'CustomTool_v1.0' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) - ]) - input[1] = 'auto_euk' - input[2] = null - input[3] = true - input[4] = 'eukcc' - input[5] = '.' // fake folder replacing eukcc_db - """ - } - } - - then { - assert workflow.success - assertAll( - { assert snapshot(workflow.out.stats).match() }, - { assert workflow.out.stats.size() == 1 }, - // completeness from EukCC, contamination kept from samplesheet - { assert workflow.out.stats[0][1] == '90.0' }, - { assert workflow.out.stats[0][2] == 2.5 }, - { assert workflow.out.stats[0][3] ==~ /CustomTool_v1\.0;eukcc_v[^;]+/ }, - { assert workflow.trace.tasks().any { it.name.contains('EUKCC_SINGLE') } } - ) - } - - } - - test("eukaryote - no eukcc_db - stub") { - - options "-stub" - - when { - workflow { - """ - input[0] = channel.of([ - [ id:'test_euk', domain:'euk' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) - ]) - input[1] = 'auto_euk' - input[2] = null - input[3] = true - input[4] = 'eukcc' - input[5] = null // eukcc_db missing while eukaryotes are present - """ - } - } - - then { - assert workflow.failed - assert workflow.stdout.any { it.contains('--eukcc_db is not provided') } || - workflow.stderr.any { it.contains('--eukcc_db is not provided') } - } - - } test("eukaryote without estimate - eukcc - not assigned") { @@ -227,32 +53,4 @@ nextflow_workflow { } - test("no genomes - stub") { - - options "-stub" - - when { - workflow { - """ - input[0] = channel.empty() - input[1] = 'auto_euk' - input[2] = null - input[3] = true - input[4] = 'eukcc' - input[5] = null // eukcc_db is not required without eukaryotes - """ - } - } - - then { - assert workflow.success - assertAll( - { assert workflow.out.stats.size() == 0 }, - // no eukaryotes - eukaryotic steps must not run - { assert !workflow.trace.tasks().any { it.name =~ /EUKCC|BUSCO|DB_UNTAR|GUNZIP_FASTA/ } } - ) - } - - } - } diff --git a/subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test b/subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test new file mode 100644 index 00000000..37a6d4ac --- /dev/null +++ b/subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test @@ -0,0 +1,215 @@ +nextflow_workflow { + + name "Test Subworkflow EUKARYOTIC_GENOME_EVALUATION" + script "../main.nf" + workflow "EUKARYOTIC_GENOME_EVALUATION" + + tag "subworkflows" + tag "subworkflows_local" + tag "subworkflows/genome_evaluation_euks" + tag "subworkflows/genome_evaluation_euks_stub" + tag "busco" + tag "busco/busco" + tag "eukcc" + tag "untar" + tag "gunzip" + + test("eukaryote - eukcc - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_euk', domain:'euk' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = 'auto_euk' // busco_db_lineage + input[2] = null // busco_db + input[3] = true // busco_clean + input[4] = 'eukcc' // eukaryotic_completeness_tool + input[5] = '.' // fake folder replacing eukcc_db because test DB https://ftp.ebi.ac.uk/pub/databases/metagenomics/eukcc/eukcc2_db_tiny_fungi_test.tar.gz is big + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.stats).match() }, + { assert workflow.out.stats.size() == 1 }, + { assert workflow.out.stats[0][1] == '90.0' }, // fake values assigned by eukcc in -stub + { assert workflow.out.stats[0][2] == '1.0' }, // fake values assigned by eukcc in -stub + { assert workflow.out.stats[0][3].startsWith('eukcc_v') }, + { assert !workflow.trace.tasks().any { it.name.contains('BUSCO') } } + ) + } + + } + + test("eukaryote - busco - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_euk', domain:'euk' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = 'auto_euk' + input[2] = null // busco_db - BUSCO downloads lineages itself + input[3] = true + input[4] = 'busco' + input[5] = '.' // fake folder replacing eukcc_db + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.stats).match() }, + { assert workflow.out.stats.size() == 1 }, + // completeness is taken from BUSCO - stub writes no short summary json, so it is empty + { assert workflow.out.stats[0][1] == null }, + // contamination is always taken from EukCC + { assert workflow.out.stats[0][2] == '1.0' }, + { assert workflow.out.stats[0][3] ==~ /busco_v[^;]+;eukcc_v[^;]+/ }, + { assert workflow.trace.tasks().any { it.name.contains('BUSCO_BUSCO') } } + ) + } + + } + + test("eukaryote with contamination - busco - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_euk', domain:'euk', contamination:2.5, stats_generation_software:'CustomTool_v1.0' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = 'auto_euk' + input[2] = null + input[3] = true + input[4] = 'busco' + input[5] = null // eukcc_db is not required - EukCC is skipped + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.stats).match() }, + { assert workflow.out.stats.size() == 1 }, + // completeness from BUSCO (stub - empty), contamination kept from samplesheet + { assert workflow.out.stats[0][1] == null }, + { assert workflow.out.stats[0][2] == 2.5 }, + // BUSCO is appended to the software given in samplesheet, EukCC is not listed + { assert workflow.out.stats[0][3] ==~ /CustomTool_v1\.0;busco_v[^;]+/ }, + { assert !workflow.trace.tasks().any { it.name =~ /EUKCC|GUNZIP_FASTA|DB_UNTAR/ } }, + { assert workflow.trace.tasks().any { it.name.contains('BUSCO_BUSCO') } } + ) + } + + } + + test("eukaryote with contamination - eukcc - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_euk', domain:'euk', contamination:2.5, stats_generation_software:'CustomTool_v1.0' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = 'auto_euk' + input[2] = null + input[3] = true + input[4] = 'eukcc' + input[5] = '.' // fake folder replacing eukcc_db + """ + } + } + + then { + assert workflow.success + assertAll( + { assert snapshot(workflow.out.stats).match() }, + { assert workflow.out.stats.size() == 1 }, + // completeness from EukCC, contamination kept from samplesheet + { assert workflow.out.stats[0][1] == '90.0' }, + { assert workflow.out.stats[0][2] == 2.5 }, + { assert workflow.out.stats[0][3] ==~ /CustomTool_v1\.0;eukcc_v[^;]+/ }, + { assert workflow.trace.tasks().any { it.name.contains('EUKCC_SINGLE') } } + ) + } + + } + + test("eukaryote - no eukcc_db - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.of([ + [ id:'test_euk', domain:'euk' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = 'auto_euk' + input[2] = null + input[3] = true + input[4] = 'eukcc' + input[5] = null // eukcc_db missing while eukaryotes are present + """ + } + } + + then { + assert workflow.failed + assert workflow.stdout.any { it.contains('--eukcc_db is not provided') } || + workflow.stderr.any { it.contains('--eukcc_db is not provided') } + } + + } + + test("no genomes - stub") { + + options "-stub" + + when { + workflow { + """ + input[0] = channel.empty() + input[1] = 'auto_euk' + input[2] = null + input[3] = true + input[4] = 'eukcc' + input[5] = null // eukcc_db is not required without eukaryotes + """ + } + } + + then { + assert workflow.success + assertAll( + { assert workflow.out.stats.size() == 0 }, + // no eukaryotes - eukaryotic steps must not run + { assert !workflow.trace.tasks().any { it.name =~ /EUKCC|BUSCO|DB_UNTAR|GUNZIP_FASTA/ } } + ) + } + + } + +} diff --git a/subworkflows/local/genome_evaluation_euks/tests/main.nf.test.snap b/subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test.snap similarity index 100% rename from subworkflows/local/genome_evaluation_euks/tests/main.nf.test.snap rename to subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test.snap diff --git a/tests/mag_no_coverage_paired_reads.nf.test b/tests/mag_no_coverage_pe_skip_ena_queries.nf.test similarity index 88% rename from tests/mag_no_coverage_paired_reads.nf.test rename to tests/mag_no_coverage_pe_skip_ena_queries.nf.test index 406fd332..e5fdc09b 100644 --- a/tests/mag_no_coverage_paired_reads.nf.test +++ b/tests/mag_no_coverage_pe_skip_ena_queries.nf.test @@ -1,13 +1,13 @@ nextflow_pipeline { - name "Test genome submission workflow - no_coverage_paired_reads" + name "Test genome submission workflow - no_coverage_paired_reads skip_ena_queries" script "../main.nf" tag "pipeline" tag "mode_mag" - tag "test_mag_no_coverage_paired_reads" - profile "test_mag_no_coverage_paired_reads" + tag "test_mag_no_coverage_pe_skip_ena_queries" + profile "test_mag_no_coverage_pe_skip_ena_queries" - test("-profile test_mag_no_coverage_paired_reads") { + test("-profile test_mag_no_coverage_pe_skip_ena_queries") { when { params { diff --git a/tests/mag_no_coverage_paired_reads.nf.test.snap b/tests/mag_no_coverage_pe_skip_ena_queries.nf.test.snap similarity index 54% rename from tests/mag_no_coverage_paired_reads.nf.test.snap rename to tests/mag_no_coverage_pe_skip_ena_queries.nf.test.snap index a8d4989c..b6138dcb 100644 --- a/tests/mag_no_coverage_paired_reads.nf.test.snap +++ b/tests/mag_no_coverage_pe_skip_ena_queries.nf.test.snap @@ -1,13 +1,8 @@ { - "-profile test_mag_no_coverage_paired_reads": { + "-profile test_mag_no_coverage_pe_skip_ena_queries": { "content": [ - 9, + 5, { - "CONCAT_ACCESSIONS": { - "coreutils": 9.4, - "find": "4.6.0", - "pigz": 2.8 - }, "CONCAT_METADATA": { "coreutils": 9.4, "find": "4.6.0", @@ -19,20 +14,9 @@ "CREATE_GENOME_METADATA_TSV": { "bash": "5.2.37(1)-release" }, - "CREATE_MANIFESTS": { - "genome_uploader": "3.0.4" - }, "FALINT": { "falint": "1.2.0" }, - "REGISTERSTUDY": { - "mgnify-pipelines-toolkit": "1.5.5" - }, - "SUBMIT": { - "ena-webin-cli": "9.0.3", - "mgnify-pipelines-toolkit": "1.5.5", - "python": "3.12.16" - }, "Workflow": { "nf-core/seqsubmit": "v1.0.0" } @@ -42,44 +26,25 @@ "mags/no_coverage_paired_reads", "mags/no_coverage_paired_reads/coverage", "mags/no_coverage_paired_reads/coverage/no_coverage_paired_reads.depth.tsv", - "mags/no_coverage_paired_reads/upload", - "mags/no_coverage_paired_reads/upload/webin_cli", - "mags/no_coverage_paired_reads/upload/webin_cli/no_coverage_paired_reads_accessions.tsv", "mags/upload", - "mags/upload/genomes_accessions.tsv", "mags/upload/genomes_metadata.tsv", - "mags/upload/manifests", - "mags/upload/manifests/results", - "mags/upload/manifests/results/MAG_upload", - "mags/upload/manifests/results/MAG_upload/ENA_backup.json", - "mags/upload/manifests/results/MAG_upload/genome_samples.xml", - "mags/upload/manifests/results/MAG_upload/manifests_test", - "mags/upload/manifests/results/MAG_upload/registered_MAGs_test.tsv", "multiqc", "multiqc/multiqc_data", "multiqc/multiqc_data/llms-full.txt", "multiqc/multiqc_data/multiqc.log", "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_Genomes assigned accessions.txt", "multiqc/multiqc_data/multiqc_citations.txt", "multiqc/multiqc_data/multiqc_data.json", "multiqc/multiqc_data/multiqc_genome_metadata.txt", - "multiqc/multiqc_data/multiqc_sample_registration.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/Genomes assigned accessions.pdf", "multiqc/multiqc_plots/pdf/genome_metadata.pdf", - "multiqc/multiqc_plots/pdf/sample_registration.pdf", "multiqc/multiqc_plots/png", - "multiqc/multiqc_plots/png/Genomes assigned accessions.png", "multiqc/multiqc_plots/png/genome_metadata.png", - "multiqc/multiqc_plots/png/sample_registration.png", "multiqc/multiqc_plots/svg", - "multiqc/multiqc_plots/svg/Genomes assigned accessions.svg", "multiqc/multiqc_plots/svg/genome_metadata.svg", - "multiqc/multiqc_plots/svg/sample_registration.svg", "multiqc/multiqc_report.html", "pipeline_info", "pipeline_info/nf_core_seqsubmit_software_mqc_versions.yml" @@ -91,10 +56,10 @@ "multiqc_genome_metadata.txt:md5,73ca3eaa259e29711518c466246aeed5" ] ], - "timestamp": "2026-10-16T11:28:13.637453", + "timestamp": "2026-10-30T11:24:46.224163", "meta": { "nf-test": "0.9.5", - "nextflow": "26.10.0" + "nextflow": "26.10.4" } } } \ No newline at end of file diff --git a/tests/mag_no_coverage_single_reads.nf.test b/tests/mag_no_coverage_se_skip_ena_queries.nf.test similarity index 88% rename from tests/mag_no_coverage_single_reads.nf.test rename to tests/mag_no_coverage_se_skip_ena_queries.nf.test index 5ec80f3e..72644af3 100644 --- a/tests/mag_no_coverage_single_reads.nf.test +++ b/tests/mag_no_coverage_se_skip_ena_queries.nf.test @@ -1,13 +1,13 @@ nextflow_pipeline { - name "Test genome submission workflow - no_coverage_single_reads" + name "Test genome submission workflow - no_coverage_single_reads skip_ena_queries" script "../main.nf" tag "pipeline" tag "mode_mag" - tag "test_mag_no_coverage_single_reads" - profile "test_mag_no_coverage_single_reads" + tag "test_mag_no_coverage_se_skip_ena_queries" + profile "test_mag_no_coverage_se_skip_ena_queries" - test("-profile test_mag_no_coverage_single_reads") { + test("-profile test_mag_no_coverage_se_skip_ena_queries") { when { params { diff --git a/tests/mag_no_coverage_single_reads.nf.test.snap b/tests/mag_no_coverage_se_skip_ena_queries.nf.test.snap similarity index 54% rename from tests/mag_no_coverage_single_reads.nf.test.snap rename to tests/mag_no_coverage_se_skip_ena_queries.nf.test.snap index f2fa2e8a..0a4c2c87 100644 --- a/tests/mag_no_coverage_single_reads.nf.test.snap +++ b/tests/mag_no_coverage_se_skip_ena_queries.nf.test.snap @@ -1,13 +1,8 @@ { - "-profile test_mag_no_coverage_single_reads": { + "-profile test_mag_no_coverage_se_skip_ena_queries": { "content": [ - 9, + 5, { - "CONCAT_ACCESSIONS": { - "coreutils": 9.4, - "find": "4.6.0", - "pigz": 2.8 - }, "CONCAT_METADATA": { "coreutils": 9.4, "find": "4.6.0", @@ -19,20 +14,9 @@ "CREATE_GENOME_METADATA_TSV": { "bash": "5.2.37(1)-release" }, - "CREATE_MANIFESTS": { - "genome_uploader": "3.0.4" - }, "FALINT": { "falint": "1.2.0" }, - "REGISTERSTUDY": { - "mgnify-pipelines-toolkit": "1.5.5" - }, - "SUBMIT": { - "ena-webin-cli": "9.0.3", - "mgnify-pipelines-toolkit": "1.5.5", - "python": "3.12.16" - }, "Workflow": { "nf-core/seqsubmit": "v1.0.0" } @@ -42,44 +26,25 @@ "mags/no_coverage_single_reads", "mags/no_coverage_single_reads/coverage", "mags/no_coverage_single_reads/coverage/no_coverage_single_reads.depth.tsv", - "mags/no_coverage_single_reads/upload", - "mags/no_coverage_single_reads/upload/webin_cli", - "mags/no_coverage_single_reads/upload/webin_cli/no_coverage_single_reads_accessions.tsv", "mags/upload", - "mags/upload/genomes_accessions.tsv", "mags/upload/genomes_metadata.tsv", - "mags/upload/manifests", - "mags/upload/manifests/results", - "mags/upload/manifests/results/MAG_upload", - "mags/upload/manifests/results/MAG_upload/ENA_backup.json", - "mags/upload/manifests/results/MAG_upload/genome_samples.xml", - "mags/upload/manifests/results/MAG_upload/manifests_test", - "mags/upload/manifests/results/MAG_upload/registered_MAGs_test.tsv", "multiqc", "multiqc/multiqc_data", "multiqc/multiqc_data/llms-full.txt", "multiqc/multiqc_data/multiqc.log", "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_Genomes assigned accessions.txt", "multiqc/multiqc_data/multiqc_citations.txt", "multiqc/multiqc_data/multiqc_data.json", "multiqc/multiqc_data/multiqc_genome_metadata.txt", - "multiqc/multiqc_data/multiqc_sample_registration.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/Genomes assigned accessions.pdf", "multiqc/multiqc_plots/pdf/genome_metadata.pdf", - "multiqc/multiqc_plots/pdf/sample_registration.pdf", "multiqc/multiqc_plots/png", - "multiqc/multiqc_plots/png/Genomes assigned accessions.png", "multiqc/multiqc_plots/png/genome_metadata.png", - "multiqc/multiqc_plots/png/sample_registration.png", "multiqc/multiqc_plots/svg", - "multiqc/multiqc_plots/svg/Genomes assigned accessions.svg", "multiqc/multiqc_plots/svg/genome_metadata.svg", - "multiqc/multiqc_plots/svg/sample_registration.svg", "multiqc/multiqc_report.html", "pipeline_info", "pipeline_info/nf_core_seqsubmit_software_mqc_versions.yml" @@ -91,10 +56,10 @@ "multiqc_genome_metadata.txt:md5,f87520e8673df42da7971d6b4723d020" ] ], - "timestamp": "2026-10-16T11:59:29.524504", + "timestamp": "2026-10-30T11:25:33.120308", "meta": { "nf-test": "0.9.5", - "nextflow": "26.10.0" + "nextflow": "26.10.4" } } } \ No newline at end of file From bae827006ba8fccedc324488b7af80c02f05a1cf Mon Sep 17 00:00:00 2001 From: Ekaterina Sakharova Date: Fri, 30 Oct 2026 16:21:55 +0000 Subject: [PATCH 24/24] simplify tests more and add test_mag_missing_metadata --- conf/test.config | 9 +- conf/test_full.config | 8 +- conf/test_mag_complete_metadata.config | 2 +- ..._mag_complete_metadata_existing_study.conf | 2 +- conf/test_mag_missing_metadata.config | 38 +++++ ...t_mag_no_coverage_pe_skip_ena_queries.conf | 2 +- ...t_mag_no_coverage_se_skip_ena_queries.conf | 2 +- conf/test_mag_no_quality.conf | 2 +- ...t_mag_no_quality_euk_skip_ena_queries.conf | 2 +- conf/test_mag_no_rna_skip_ena_queries.conf | 2 +- ...test_mag_no_taxonomy_skip_ena_queries.conf | 2 +- .../test_mag_one_contig_skip_ena_queries.conf | 2 +- nextflow.config | 1 + nf-test.config | 8 +- .../main.nf | 0 .../meta.yml | 2 +- .../tests/main.nf.test | 2 +- .../tests/main_stub.nf.test | 6 +- .../tests/main_stub.nf.test.snap | 0 .../main.nf | 0 .../meta.yml | 2 +- .../tests/main.nf.test | 2 +- .../tests/main.nf.test.snap | 0 tests/default.nf.test.snap | 49 +----- tests/mag_missing_metadata.nf.test | 39 +++++ tests/mag_missing_metadata.nf.test.snap | 143 ++++++++++++++++++ workflows/genomesubmit.nf | 4 +- 27 files changed, 259 insertions(+), 72 deletions(-) create mode 100644 conf/test_mag_missing_metadata.config rename subworkflows/local/{genome_evaluation_euks => eukaryotic_genome_evaluation}/main.nf (100%) rename subworkflows/local/{genome_evaluation_euks => eukaryotic_genome_evaluation}/meta.yml (98%) rename subworkflows/local/{genome_evaluation_euks => eukaryotic_genome_evaluation}/tests/main.nf.test (97%) rename subworkflows/local/{genome_evaluation_euks => eukaryotic_genome_evaluation}/tests/main_stub.nf.test (97%) rename subworkflows/local/{genome_evaluation_euks => eukaryotic_genome_evaluation}/tests/main_stub.nf.test.snap (100%) rename subworkflows/local/{genome_evaluation_proks => prokaryotic_genome_evaluation}/main.nf (100%) rename subworkflows/local/{genome_evaluation_proks => prokaryotic_genome_evaluation}/meta.yml (97%) rename subworkflows/local/{genome_evaluation_proks => prokaryotic_genome_evaluation}/tests/main.nf.test (98%) rename subworkflows/local/{genome_evaluation_proks => prokaryotic_genome_evaluation}/tests/main.nf.test.snap (100%) create mode 100644 tests/mag_missing_metadata.nf.test create mode 100644 tests/mag_missing_metadata.nf.test.snap diff --git a/conf/test.config b/conf/test.config index 93347675..7f0f987e 100644 --- a/conf/test.config +++ b/conf/test.config @@ -16,19 +16,22 @@ process { memory: '12.GB', time: '1.h' ] + + withName: 'REGISTERSTUDY|SUBMIT|CREATE_MANIFESTS' { + ext.when = false + } } params { config_profile_name = 'Test profile for minimal pipeline test' - config_profile_description = 'Runs --mode mags with multiple mags and missing metadata' + config_profile_description = 'Runs --mode mags with multiple mags and missing metadata. Test skips all modules using ENA queries.' // Input data input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_multiple_bins_missing_metadata.csv' outdir = 'test_output' mode = "mags" - submission_study = null - study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' + submission_study = "TEST_STUDY" centre_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_full.config b/conf/test_full.config index b7278aa6..6ad1895a 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -9,6 +9,11 @@ ---------------------------------------------------------------------------------------- */ +process { + withName: 'REGISTERSTUDY|SUBMIT|CREATE_MANIFESTS' { + ext.when = false + } +} params { config_profile_name = 'Full test profile' @@ -19,8 +24,7 @@ params { outdir = 'test_output' mode = "mags" - submission_study = null - study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' + submission_study = "TEST_STUDY" centre_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_mag_complete_metadata.config b/conf/test_mag_complete_metadata.config index 4a1689e5..b4fcbfcb 100644 --- a/conf/test_mag_complete_metadata.config +++ b/conf/test_mag_complete_metadata.config @@ -5,7 +5,7 @@ Defines input files and everything required to run a fast and simple pipeline test. Use as follows: - nextflow run nf-core/seqsubmit -profile test, --outdir + nextflow run nf-core/seqsubmit -profile test_mag_complete_metadata, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/conf/test_mag_complete_metadata_existing_study.conf b/conf/test_mag_complete_metadata_existing_study.conf index edfba5a8..f18ebe5d 100644 --- a/conf/test_mag_complete_metadata_existing_study.conf +++ b/conf/test_mag_complete_metadata_existing_study.conf @@ -5,7 +5,7 @@ Defines input files and everything required to run a fast and simple pipeline test. Use as follows: - nextflow run nf-core/seqsubmit -profile test, --outdir + nextflow run nf-core/seqsubmit -profile test_mag_complete_metadata_existing_study, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/conf/test_mag_missing_metadata.config b/conf/test_mag_missing_metadata.config new file mode 100644 index 00000000..8c335090 --- /dev/null +++ b/conf/test_mag_missing_metadata.config @@ -0,0 +1,38 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for running minimal tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines input files and everything required to run a fast and simple pipeline test. + + Use as follows: + nextflow run nf-core/seqsubmit -profile test, --outdir + +---------------------------------------------------------------------------------------- +*/ + +process { + resourceLimits = [ + cpus: 2, + memory: '12.GB', + time: '1.h' + ] +} + +params { + config_profile_name = 'Test profile for minimal pipeline test' + config_profile_description = 'Runs --mode mags with multiple mags and missing metadata with ENA test upload' + + // Input data + input = params.pipelines_testdata_base_path + 'seqsubmit/samplesheets/mag_multiple_bins_missing_metadata.csv' + outdir = 'test_output' + + mode = "mags" + submission_study = null + study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' + centre_name = "TEST_CENTER" + + test_upload = true + + cat_db = params.pipelines_testdata_base_path + 'seqsubmit/test_data/small_cat_db/tax-db.tar.gz' + checkm2_db = null +} diff --git a/conf/test_mag_no_coverage_pe_skip_ena_queries.conf b/conf/test_mag_no_coverage_pe_skip_ena_queries.conf index a9eaa016..69d737c0 100644 --- a/conf/test_mag_no_coverage_pe_skip_ena_queries.conf +++ b/conf/test_mag_no_coverage_pe_skip_ena_queries.conf @@ -5,7 +5,7 @@ Defines input files and everything required to run a fast and simple pipeline test. Use as follows: - nextflow run nf-core/seqsubmit -profile test, --outdir + nextflow run nf-core/seqsubmit -profile test_mag_no_coverage_pe_skip_ena_queries, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/conf/test_mag_no_coverage_se_skip_ena_queries.conf b/conf/test_mag_no_coverage_se_skip_ena_queries.conf index 52ffcab5..d3e2982c 100644 --- a/conf/test_mag_no_coverage_se_skip_ena_queries.conf +++ b/conf/test_mag_no_coverage_se_skip_ena_queries.conf @@ -5,7 +5,7 @@ Defines input files and everything required to run a fast and simple pipeline test. Use as follows: - nextflow run nf-core/seqsubmit -profile test, --outdir + nextflow run nf-core/seqsubmit -profile test_mag_no_coverage_se_skip_ena_queries, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/conf/test_mag_no_quality.conf b/conf/test_mag_no_quality.conf index 4b8e12ce..f6a43e1b 100644 --- a/conf/test_mag_no_quality.conf +++ b/conf/test_mag_no_quality.conf @@ -5,7 +5,7 @@ Defines input files and everything required to run a fast and simple pipeline test. Use as follows: - nextflow run nf-core/seqsubmit -profile test, --outdir + nextflow run nf-core/seqsubmit -profile test_mag_no_quality, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/conf/test_mag_no_quality_euk_skip_ena_queries.conf b/conf/test_mag_no_quality_euk_skip_ena_queries.conf index f15db4a6..880aca62 100644 --- a/conf/test_mag_no_quality_euk_skip_ena_queries.conf +++ b/conf/test_mag_no_quality_euk_skip_ena_queries.conf @@ -5,7 +5,7 @@ Defines input files and everything required to run a fast and simple pipeline test. Use as follows: - nextflow run nf-core/seqsubmit -profile test, --outdir + nextflow run nf-core/seqsubmit -profile test_mag_no_quality_euk_skip_ena_queries, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/conf/test_mag_no_rna_skip_ena_queries.conf b/conf/test_mag_no_rna_skip_ena_queries.conf index 2b9c00b5..6a6df87f 100644 --- a/conf/test_mag_no_rna_skip_ena_queries.conf +++ b/conf/test_mag_no_rna_skip_ena_queries.conf @@ -5,7 +5,7 @@ Defines input files and everything required to run a fast and simple pipeline test. Use as follows: - nextflow run nf-core/seqsubmit -profile test, --outdir + nextflow run nf-core/seqsubmit -profile test_mag_no_rna_skip_ena_queries, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/conf/test_mag_no_taxonomy_skip_ena_queries.conf b/conf/test_mag_no_taxonomy_skip_ena_queries.conf index 063be2cc..1f359745 100644 --- a/conf/test_mag_no_taxonomy_skip_ena_queries.conf +++ b/conf/test_mag_no_taxonomy_skip_ena_queries.conf @@ -5,7 +5,7 @@ Defines input files and everything required to run a fast and simple pipeline test. Use as follows: - nextflow run nf-core/seqsubmit -profile test, --outdir + nextflow run nf-core/seqsubmit -profile test_mag_no_taxonomy_skip_ena_queries, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/conf/test_mag_one_contig_skip_ena_queries.conf b/conf/test_mag_one_contig_skip_ena_queries.conf index 3c4656d2..9b06fc01 100644 --- a/conf/test_mag_one_contig_skip_ena_queries.conf +++ b/conf/test_mag_one_contig_skip_ena_queries.conf @@ -5,7 +5,7 @@ Defines input files and everything required to run a fast and simple pipeline test. Use as follows: - nextflow run nf-core/seqsubmit -profile test, --outdir + nextflow run nf-core/seqsubmit -profile test_mag_one_contig_skip_ena_queries, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/nextflow.config b/nextflow.config index be9ad8cd..177b5b85 100644 --- a/nextflow.config +++ b/nextflow.config @@ -255,6 +255,7 @@ profiles { test_full { includeConfig 'conf/test_full.config' } test_mag_complete_metadata_existing_study { includeConfig 'conf/test_mag_complete_metadata_existing_study.conf' } test_mag_complete_metadata { includeConfig 'conf/test_mag_complete_metadata.config' } + test_mag_missing_metadata { includeConfig 'conf/test_mag_missing_metadata.config' } test_mag_no_coverage_se_skip_ena_queries { includeConfig 'conf/test_mag_no_coverage_se_skip_ena_queries.conf' } test_mag_no_coverage_pe_skip_ena_queries { includeConfig 'conf/test_mag_no_coverage_pe_skip_ena_queries.conf' } test_mag_no_quality { includeConfig 'conf/test_mag_no_quality.conf' } diff --git a/nf-test.config b/nf-test.config index c05281c5..372bac9e 100644 --- a/nf-test.config +++ b/nf-test.config @@ -10,14 +10,14 @@ config { // ignore tests coming from the nf-core/modules repo // ignore euk_mags_quality assessment because Eukcc DB is big for GA - // ignore genome_evaluation_proks test because checkm2 container is too big - // ignore genome_evaluation_euks test with Eukcc DB download which is big for GA + // ignore prokaryotic_genome_evaluation test because checkm2 container is too big + // ignore eukaryotic_genome_evaluation test with Eukcc DB download which is big for GA ignore = [ 'modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*', 'tests/mag_no_quality_euk_skip_ena_queries.nf.test', - 'subworkflows/local/genome_evaluation_proks/tests/*', - 'subworkflows/local/genome_evaluation_euks/tests/main.nf.test' + 'subworkflows/local/prokaryotic_genome_evaluation/tests/*', + 'subworkflows/local/eukaryotic_genome_evaluation/tests/main.nf.test' ] // run all test with defined profile(s) from the main nextflow.config diff --git a/subworkflows/local/genome_evaluation_euks/main.nf b/subworkflows/local/eukaryotic_genome_evaluation/main.nf similarity index 100% rename from subworkflows/local/genome_evaluation_euks/main.nf rename to subworkflows/local/eukaryotic_genome_evaluation/main.nf diff --git a/subworkflows/local/genome_evaluation_euks/meta.yml b/subworkflows/local/eukaryotic_genome_evaluation/meta.yml similarity index 98% rename from subworkflows/local/genome_evaluation_euks/meta.yml rename to subworkflows/local/eukaryotic_genome_evaluation/meta.yml index adc0b561..ac99b995 100644 --- a/subworkflows/local/genome_evaluation_euks/meta.yml +++ b/subworkflows/local/eukaryotic_genome_evaluation/meta.yml @@ -1,5 +1,5 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json -name: "genome_evaluation_euks" +name: "eukaryotic_genome_evaluation" description: | Estimates completeness and contamination of eukaryotic genomes. Contamination is calculated by EukCC (or kept from the samplesheet). diff --git a/subworkflows/local/genome_evaluation_euks/tests/main.nf.test b/subworkflows/local/eukaryotic_genome_evaluation/tests/main.nf.test similarity index 97% rename from subworkflows/local/genome_evaluation_euks/tests/main.nf.test rename to subworkflows/local/eukaryotic_genome_evaluation/tests/main.nf.test index fa81d940..84e1b3c3 100644 --- a/subworkflows/local/genome_evaluation_euks/tests/main.nf.test +++ b/subworkflows/local/eukaryotic_genome_evaluation/tests/main.nf.test @@ -6,7 +6,7 @@ nextflow_workflow { tag "subworkflows" tag "subworkflows_local" - tag "subworkflows/genome_evaluation_euks" + tag "subworkflows/eukaryotic_genome_evaluation" tag "eukcc" test("eukaryote without estimate - eukcc - not assigned") { diff --git a/subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test b/subworkflows/local/eukaryotic_genome_evaluation/tests/main_stub.nf.test similarity index 97% rename from subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test rename to subworkflows/local/eukaryotic_genome_evaluation/tests/main_stub.nf.test index 37a6d4ac..1d273290 100644 --- a/subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test +++ b/subworkflows/local/eukaryotic_genome_evaluation/tests/main_stub.nf.test @@ -1,13 +1,13 @@ nextflow_workflow { - name "Test Subworkflow EUKARYOTIC_GENOME_EVALUATION" + name "Test Subworkflow EUKARYOTIC_GENOME_EVALUATION -stub" script "../main.nf" workflow "EUKARYOTIC_GENOME_EVALUATION" tag "subworkflows" tag "subworkflows_local" - tag "subworkflows/genome_evaluation_euks" - tag "subworkflows/genome_evaluation_euks_stub" + tag "subworkflows/eukaryotic_genome_evaluation" + tag "subworkflows/eukaryotic_genome_evaluation_stub" tag "busco" tag "busco/busco" tag "eukcc" diff --git a/subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test.snap b/subworkflows/local/eukaryotic_genome_evaluation/tests/main_stub.nf.test.snap similarity index 100% rename from subworkflows/local/genome_evaluation_euks/tests/main_stub.nf.test.snap rename to subworkflows/local/eukaryotic_genome_evaluation/tests/main_stub.nf.test.snap diff --git a/subworkflows/local/genome_evaluation_proks/main.nf b/subworkflows/local/prokaryotic_genome_evaluation/main.nf similarity index 100% rename from subworkflows/local/genome_evaluation_proks/main.nf rename to subworkflows/local/prokaryotic_genome_evaluation/main.nf diff --git a/subworkflows/local/genome_evaluation_proks/meta.yml b/subworkflows/local/prokaryotic_genome_evaluation/meta.yml similarity index 97% rename from subworkflows/local/genome_evaluation_proks/meta.yml rename to subworkflows/local/prokaryotic_genome_evaluation/meta.yml index b982e81f..02c4ad77 100644 --- a/subworkflows/local/genome_evaluation_proks/meta.yml +++ b/subworkflows/local/prokaryotic_genome_evaluation/meta.yml @@ -1,5 +1,5 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json -name: "genome_evaluation_proks" +name: "prokaryotic_genome_evaluation" description: | Estimates completeness and contamination of prokaryotic (bacterial and archaeal) genomes using CheckM2. Downloads the CheckM2 database automatically when no pre-built database is provided. diff --git a/subworkflows/local/genome_evaluation_proks/tests/main.nf.test b/subworkflows/local/prokaryotic_genome_evaluation/tests/main.nf.test similarity index 98% rename from subworkflows/local/genome_evaluation_proks/tests/main.nf.test rename to subworkflows/local/prokaryotic_genome_evaluation/tests/main.nf.test index bdac14a5..db54291f 100644 --- a/subworkflows/local/genome_evaluation_proks/tests/main.nf.test +++ b/subworkflows/local/prokaryotic_genome_evaluation/tests/main.nf.test @@ -6,7 +6,7 @@ nextflow_workflow { tag "subworkflows" tag "subworkflows_local" - tag "subworkflows/genome_evaluation_proks" + tag "subworkflows/prokaryotic_genome_evaluation" tag "checkm2" tag "checkm2/predict" tag "checkm2/databasedownload" diff --git a/subworkflows/local/genome_evaluation_proks/tests/main.nf.test.snap b/subworkflows/local/prokaryotic_genome_evaluation/tests/main.nf.test.snap similarity index 100% rename from subworkflows/local/genome_evaluation_proks/tests/main.nf.test.snap rename to subworkflows/local/prokaryotic_genome_evaluation/tests/main.nf.test.snap diff --git a/tests/default.nf.test.snap b/tests/default.nf.test.snap index fd8cda70..5589d52b 100644 --- a/tests/default.nf.test.snap +++ b/tests/default.nf.test.snap @@ -1,7 +1,7 @@ { "-profile test": { "content": [ - 22, + 16, { "BARRNAP": { "barrnap": 0.9 @@ -15,11 +15,6 @@ "CAT_DB_UNTAR": { "untar": 1.34 }, - "CONCAT_ACCESSIONS": { - "coreutils": 9.4, - "find": "4.6.0", - "pigz": 2.8 - }, "CONCAT_METADATA": { "coreutils": 9.4, "find": "4.6.0", @@ -34,23 +29,12 @@ "CREATE_GENOME_METADATA_TSV": { "bash": "5.2.37(1)-release" }, - "CREATE_MANIFESTS": { - "genome_uploader": "3.0.4" - }, "FALINT": { "falint": "1.2.0" }, - "REGISTERSTUDY": { - "mgnify-pipelines-toolkit": "1.5.5" - }, "RENAME_FASTA_FOR_CATPACK": { "bash": "5.2.37(1)-release" }, - "SUBMIT": { - "ena-webin-cli": "9.0.3", - "mgnify-pipelines-toolkit": "1.5.5", - "python": "3.12.16" - }, "TRNASCANSE": { "tRNAscan-SE": "2.0.12" }, @@ -63,9 +47,6 @@ "mags/no_coverage_paired_reads", "mags/no_coverage_paired_reads/coverage", "mags/no_coverage_paired_reads/coverage/no_coverage_paired_reads.depth.tsv", - "mags/no_coverage_paired_reads/upload", - "mags/no_coverage_paired_reads/upload/webin_cli", - "mags/no_coverage_paired_reads/upload/webin_cli/no_coverage_paired_reads_accessions.tsv", "mags/no_rna_presence", "mags/no_rna_presence/rna", "mags/no_rna_presence/rna/barrnap", @@ -74,51 +55,29 @@ "mags/no_rna_presence/rna/trnascanse/no_rna_presence.log", "mags/no_rna_presence/rna/trnascanse/no_rna_presence.stats", "mags/no_rna_presence/rna/trnascanse/no_rna_presence.tsv", - "mags/no_rna_presence/upload", - "mags/no_rna_presence/upload/webin_cli", - "mags/no_rna_presence/upload/webin_cli/no_rna_presence_accessions.tsv", "mags/no_taxonomy", "mags/no_taxonomy/taxonomy", "mags/no_taxonomy/taxonomy/no_taxonomy.bin2classification.txt", "mags/no_taxonomy/taxonomy/no_taxonomy.txt", - "mags/no_taxonomy/upload", - "mags/no_taxonomy/upload/webin_cli", - "mags/no_taxonomy/upload/webin_cli/no_taxonomy_accessions.tsv", "mags/upload", - "mags/upload/genomes_accessions.tsv", "mags/upload/genomes_metadata.tsv", - "mags/upload/manifests", - "mags/upload/manifests/results", - "mags/upload/manifests/results/MAG_upload", - "mags/upload/manifests/results/MAG_upload/ENA_backup.json", - "mags/upload/manifests/results/MAG_upload/genome_samples.xml", - "mags/upload/manifests/results/MAG_upload/manifests_test", - "mags/upload/manifests/results/MAG_upload/registered_MAGs_test.tsv", "multiqc", "multiqc/multiqc_data", "multiqc/multiqc_data/llms-full.txt", "multiqc/multiqc_data/multiqc.log", "multiqc/multiqc_data/multiqc.parquet", - "multiqc/multiqc_data/multiqc_Genomes assigned accessions.txt", "multiqc/multiqc_data/multiqc_citations.txt", "multiqc/multiqc_data/multiqc_data.json", "multiqc/multiqc_data/multiqc_genome_metadata.txt", - "multiqc/multiqc_data/multiqc_sample_registration.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/Genomes assigned accessions.pdf", "multiqc/multiqc_plots/pdf/genome_metadata.pdf", - "multiqc/multiqc_plots/pdf/sample_registration.pdf", "multiqc/multiqc_plots/png", - "multiqc/multiqc_plots/png/Genomes assigned accessions.png", "multiqc/multiqc_plots/png/genome_metadata.png", - "multiqc/multiqc_plots/png/sample_registration.png", "multiqc/multiqc_plots/svg", - "multiqc/multiqc_plots/svg/Genomes assigned accessions.svg", "multiqc/multiqc_plots/svg/genome_metadata.svg", - "multiqc/multiqc_plots/svg/sample_registration.svg", "multiqc/multiqc_report.html", "pipeline_info", "pipeline_info/nf_core_seqsubmit_software_mqc_versions.yml" @@ -126,7 +85,7 @@ [ "no_coverage_paired_reads.depth.tsv:md5,fb8374996c3bad9ddd296684d8c28628", "no_rna_presence_bac.gff:md5,df19e1b84ba6f691d20c72b397c88abf", - "no_rna_presence.tsv:md5,abd958e8addba39c9e4d7f6b97a1a7c6", + "no_rna_presence.tsv:md5,373265f59324d05128361a34a3edad84", "no_taxonomy.bin2classification.txt:md5,e24c109efe807c7044a866999fd736f1", "no_taxonomy.txt:md5,0f2082d3e397fd630d605dd60993b131", "genomes_metadata.tsv:md5,2d7b5d99cd3058c7e7cd325e184cc7e9", @@ -134,10 +93,10 @@ "multiqc_genome_metadata.txt:md5,2f42824e9296d918b7f944037c27c717" ] ], - "timestamp": "2026-10-19T15:27:49.508151", + "timestamp": "2026-10-30T15:44:32.057076", "meta": { "nf-test": "0.9.5", - "nextflow": "26.04.1" + "nextflow": "26.10.4" } } } \ No newline at end of file diff --git a/tests/mag_missing_metadata.nf.test b/tests/mag_missing_metadata.nf.test new file mode 100644 index 00000000..1e1ddd97 --- /dev/null +++ b/tests/mag_missing_metadata.nf.test @@ -0,0 +1,39 @@ +nextflow_pipeline { + + name "Test genome submission workflow - missing_metadata" + script "../main.nf" + tag "pipeline" + tag "mode_mag" + tag "test_mag_missing_metadata" + profile "test_mag_missing_metadata" + + test("-profile test_mag_missing_metadata") { + + when { + params { + outdir = "$outputDir" + } + } + + 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}', '**/manifests_test/*']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + // Early failure no need to test the rest of snapshots + assert workflow.success + assertAll( + { assert snapshot( + // Number of successful tasks + workflow.trace.succeeded().size(), + // 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_seqsubmit_software_mqc_versions.yml"), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } +} diff --git a/tests/mag_missing_metadata.nf.test.snap b/tests/mag_missing_metadata.nf.test.snap new file mode 100644 index 00000000..72c96102 --- /dev/null +++ b/tests/mag_missing_metadata.nf.test.snap @@ -0,0 +1,143 @@ +{ + "-profile test_mag_missing_metadata": { + "content": [ + 22, + { + "BARRNAP": { + "barrnap": 0.9 + }, + "CATPACK_ADDNAMES_BINS": { + "catpack": 6.0 + }, + "CATPACK_BINS": { + "catpack": 6.0 + }, + "CAT_DB_UNTAR": { + "untar": 1.34 + }, + "CONCAT_ACCESSIONS": { + "coreutils": 9.4, + "find": "4.6.0", + "pigz": 2.8 + }, + "CONCAT_METADATA": { + "coreutils": 9.4, + "find": "4.6.0", + "pigz": 2.8 + }, + "COUNT_RNA": { + "python": "3.12.12" + }, + "COVERM_GENOME": { + "coverm": "0.7.0" + }, + "CREATE_GENOME_METADATA_TSV": { + "bash": "5.2.37(1)-release" + }, + "CREATE_MANIFESTS": { + "genome_uploader": "3.0.4" + }, + "FALINT": { + "falint": "1.2.0" + }, + "REGISTERSTUDY": { + "mgnify-pipelines-toolkit": "1.5.5" + }, + "RENAME_FASTA_FOR_CATPACK": { + "bash": "5.2.37(1)-release" + }, + "SUBMIT": { + "ena-webin-cli": "9.0.3", + "mgnify-pipelines-toolkit": "1.5.5", + "python": "3.12.16" + }, + "TRNASCANSE": { + "tRNAscan-SE": "2.0.12" + }, + "Workflow": { + "nf-core/seqsubmit": "v1.0.0" + } + }, + [ + "mags", + "mags/no_coverage_paired_reads", + "mags/no_coverage_paired_reads/coverage", + "mags/no_coverage_paired_reads/coverage/no_coverage_paired_reads.depth.tsv", + "mags/no_coverage_paired_reads/upload", + "mags/no_coverage_paired_reads/upload/webin_cli", + "mags/no_coverage_paired_reads/upload/webin_cli/no_coverage_paired_reads_accessions.tsv", + "mags/no_rna_presence", + "mags/no_rna_presence/rna", + "mags/no_rna_presence/rna/barrnap", + "mags/no_rna_presence/rna/barrnap/no_rna_presence_bac.gff", + "mags/no_rna_presence/rna/trnascanse", + "mags/no_rna_presence/rna/trnascanse/no_rna_presence.log", + "mags/no_rna_presence/rna/trnascanse/no_rna_presence.stats", + "mags/no_rna_presence/rna/trnascanse/no_rna_presence.tsv", + "mags/no_rna_presence/upload", + "mags/no_rna_presence/upload/webin_cli", + "mags/no_rna_presence/upload/webin_cli/no_rna_presence_accessions.tsv", + "mags/no_taxonomy", + "mags/no_taxonomy/taxonomy", + "mags/no_taxonomy/taxonomy/no_taxonomy.bin2classification.txt", + "mags/no_taxonomy/taxonomy/no_taxonomy.txt", + "mags/no_taxonomy/upload", + "mags/no_taxonomy/upload/webin_cli", + "mags/no_taxonomy/upload/webin_cli/no_taxonomy_accessions.tsv", + "mags/upload", + "mags/upload/genomes_accessions.tsv", + "mags/upload/genomes_metadata.tsv", + "mags/upload/manifests", + "mags/upload/manifests/results", + "mags/upload/manifests/results/MAG_upload", + "mags/upload/manifests/results/MAG_upload/ENA_backup.json", + "mags/upload/manifests/results/MAG_upload/genome_samples.xml", + "mags/upload/manifests/results/MAG_upload/manifests_test", + "mags/upload/manifests/results/MAG_upload/registered_MAGs_test.tsv", + "multiqc", + "multiqc/multiqc_data", + "multiqc/multiqc_data/llms-full.txt", + "multiqc/multiqc_data/multiqc.log", + "multiqc/multiqc_data/multiqc.parquet", + "multiqc/multiqc_data/multiqc_Genomes assigned accessions.txt", + "multiqc/multiqc_data/multiqc_citations.txt", + "multiqc/multiqc_data/multiqc_data.json", + "multiqc/multiqc_data/multiqc_genome_metadata.txt", + "multiqc/multiqc_data/multiqc_sample_registration.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/Genomes assigned accessions.pdf", + "multiqc/multiqc_plots/pdf/genome_metadata.pdf", + "multiqc/multiqc_plots/pdf/sample_registration.pdf", + "multiqc/multiqc_plots/png", + "multiqc/multiqc_plots/png/Genomes assigned accessions.png", + "multiqc/multiqc_plots/png/genome_metadata.png", + "multiqc/multiqc_plots/png/sample_registration.png", + "multiqc/multiqc_plots/svg", + "multiqc/multiqc_plots/svg/Genomes assigned accessions.svg", + "multiqc/multiqc_plots/svg/genome_metadata.svg", + "multiqc/multiqc_plots/svg/sample_registration.svg", + "multiqc/multiqc_report.html", + "pipeline_info", + "pipeline_info/nf_core_seqsubmit_software_mqc_versions.yml" + ], + [ + "no_coverage_paired_reads.depth.tsv:md5,fb8374996c3bad9ddd296684d8c28628", + "no_rna_presence_bac.gff:md5,df19e1b84ba6f691d20c72b397c88abf", + "no_rna_presence.tsv:md5,373265f59324d05128361a34a3edad84", + "no_taxonomy.bin2classification.txt:md5,e24c109efe807c7044a866999fd736f1", + "no_taxonomy.txt:md5,0f2082d3e397fd630d605dd60993b131", + "genomes_metadata.tsv:md5,2d7b5d99cd3058c7e7cd325e184cc7e9", + "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", + "multiqc_genome_metadata.txt:md5,2f42824e9296d918b7f944037c27c717" + ] + ], + "timestamp": "2026-10-30T16:02:47.901797", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.10.4" + } + } +} \ No newline at end of file diff --git a/workflows/genomesubmit.nf b/workflows/genomesubmit.nf index d3665a48..3a3ecc72 100644 --- a/workflows/genomesubmit.nf +++ b/workflows/genomesubmit.nf @@ -16,8 +16,8 @@ include { MULTIQC } from '../modules/nf-core/multi include { paramsSummaryMap } from 'plugin/nf-schema' include { FASTA_VALIDATION } from '../subworkflows/local/fasta_validation/main' -include { EUKARYOTIC_GENOME_EVALUATION } from '../subworkflows/local/genome_evaluation_euks/main' -include { PROKARYOTIC_GENOME_EVALUATION } from '../subworkflows/local/genome_evaluation_proks/main' +include { EUKARYOTIC_GENOME_EVALUATION } from '../subworkflows/local/eukaryotic_genome_evaluation/main' +include { PROKARYOTIC_GENOME_EVALUATION } from '../subworkflows/local/prokaryotic_genome_evaluation/main' include { RNA_DETECTION } from '../subworkflows/local/rna_detection/main' include { FASTA_CLASSIFY_CATPACK } from '../subworkflows/nf-core/fasta_classify_catpack/main'