diff --git a/modules/nf-core/fastani/environment.yml b/modules/nf-core/fastani/environment.yml index 25c0180f0496..5fd0c120c257 100644 --- a/modules/nf-core/fastani/environment.yml +++ b/modules/nf-core/fastani/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::fastani=1.32 + - bioconda::fastani=1.34 diff --git a/modules/nf-core/fastani/main.nf b/modules/nf-core/fastani/main.nf index 37da20f0bcbf..defe360892c2 100644 --- a/modules/nf-core/fastani/main.nf +++ b/modules/nf-core/fastani/main.nf @@ -4,46 +4,46 @@ process FASTANI { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/fastani:1.32--he1c1bb9_0' : - 'biocontainers/fastani:1.32--he1c1bb9_0' }" + 'https://depot.galaxyproject.org/singularity/fastani:1.34--hb66fcc3_7' : + 'biocontainers/fastani:1.34--hb66fcc3_7' }" input: - tuple val(meta), path(query) - path reference + tuple val(meta), path(query) + tuple val(meta2), path(reference) + path(ql) + path(rl) output: - tuple val(meta), path("*.ani.txt"), emit: ani - path "versions.yml" , emit: versions + tuple val(meta), path("*.txt") , emit: ani + tuple val(meta), path("*.visual"), optional:true, emit: visual + tuple val(meta), path("*.matrix"), optional:true, emit: matrix + tuple val("${task.process}"), val("fastani"), eval('fastANI --version 2>&1 | head -1 | sed "s/version\\ //"'), topic: versions, emit: versions_fastani when: task.ext.when == null || task.ext.when script: - def prefix = task.ext.prefix ?: "${meta.id}" - - if (meta.batch_input) { - """ - fastANI \\ - -ql $query \\ - -rl $reference \\ - -o ${prefix}.ani.txt - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastani: \$(fastANI --version 2>&1 | sed 's/version//;') - END_VERSIONS - """ - } else { - """ - fastANI \\ - -q $query \\ - -r $reference \\ - -o ${prefix}.ani.txt - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastani: \$(fastANI --version 2>&1 | sed 's/version//;') - END_VERSIONS - """ - } + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: ( meta.id ?: 'all' ) + def prefix2 = task.ext.prefix2 ?: ( meta2.id ?: 'all' ) + def input_query = query ? "-q ${query}": "--ql ${ql}" + def input_reference = reference ? "-r ${reference}": "--rl ${rl}" + """ + fastANI \\ + $input_query \\ + $input_reference \\ + --threads $task.cpus \\ + -o ${prefix}.txt + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: ( meta.id ?: 'all') + """ + echo $args + + touch ${prefix}.visual + touch ${prefix}.txt + touch ${prefix}.matrix + """ } diff --git a/modules/nf-core/fastani/meta.yml b/modules/nf-core/fastani/meta.yml index 1b52160b136a..f7a1bd5f2c43 100644 --- a/modules/nf-core/fastani/meta.yml +++ b/modules/nf-core/fastani/meta.yml @@ -1,55 +1,119 @@ name: fastani -description: Alignment-free computation of average nucleotide Identity (ANI) +description: Alignment-free computation of Average Nucleotide Identity (ANI) keywords: - genome - fasta - ANI tools: - fastani: - description: FastANI is developed for fast alignment-free computation of whole-genome - Average Nucleotide Identity (ANI). + description: FastANI is developed for fast alignment-free computation of + whole-genome Average Nucleotide Identity (ANI). homepage: https://github.com/ParBLiSS/FastANI documentation: https://github.com/ParBLiSS/FastANI tool_dev_url: https://github.com/ParBLiSS/FastANI doi: 10.1038/s41467-018-07641-9 - licence: ["Apache-2.0"] + licence: + - "Apache-2.0" identifier: biotools:fastani input: - - meta: type: map description: | Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] + e.g. [ id:'test' ] - query: type: file - description: Fasta file(s) to be queried - pattern: "*.fasta" - ontologies: [] - - reference: + description: Fasta file to be used as the query. If provided, ql will be + ignored. + pattern: "*.{fasta,fna,fa}" + ontologies: + - edam: http://edamontology.org/format_1929 # FASTA + - - meta2: + type: map + description: Groovy Map containing sample information for the reference + - reference: + type: file + description: Fasta file to be used as the reference. If provided, rl will + be ignored. + pattern: "*.{fasta,fna,fa}" + ontologies: + - edam: http://edamontology.org/format_1929 # FASTA + - ql: + type: file + description: File containing a list of query fasta paths. query input takes + precedence over this list if both are provided. + pattern: "*.txt" + ontologies: + - edam: "http://edamontology.org/format_2330" + - rl: type: file - description: Fasta file(s) to be used as reference for the query - pattern: "*.fasta" - ontologies: [] + description: File containing a list of reference fasta paths. reference + input takes precedence over this list if both are provided. + pattern: "*.txt" + ontologies: + - edam: "http://edamontology.org/format_2330" # Textual format output: ani: - - meta: type: map description: | Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.ani.txt": + e.g. [ id:'test' ] + - "*.txt": type: file - description: Results of the query - pattern: "*.ani.txt" - ontologies: [] + description: ANI results file + pattern: "*.txt" + ontologies: + - edam: "http://edamontology.org/format_2330" # Textual format + visual: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*.visual": + type: file + optional: true + description: FastANI visualization output + pattern: "*.visual" + ontologies: + - edam: "http://edamontology.org/format_3475" # TSV + matrix: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*.matrix": + type: file + optional: true + description: ANI matrix output + ontologies: + - edam: "http://edamontology.org/format_3033" + versions_fastani: + - - ${task.process}: + type: string + description: The name of the process + - fastani: + type: string + description: The name of the tool + - fastANI --version 2>&1 | head -1 | sed "s/version\ //": + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - fastani: + type: string + description: The name of the tool + - fastANI --version 2>&1 | head -1 | sed "s/version\ //": + type: eval + description: The expression to obtain the version of the tool authors: - "@abhi18av" + - "@Ethan-Hetrick" maintainers: - "@abhi18av" + - "@Ethan-Hetrick" diff --git a/modules/nf-core/fastani/tests/main.nf.test b/modules/nf-core/fastani/tests/main.nf.test index a4318db49ee3..e0cc590d6c91 100644 --- a/modules/nf-core/fastani/tests/main.nf.test +++ b/modules/nf-core/fastani/tests/main.nf.test @@ -1,13 +1,14 @@ nextflow_process { name "Test Process FASTANI" + script "../main.nf" + process "FASTANI" + config "./nextflow.config" tag "modules_nfcore" tag "modules" tag "fastani" - script "../main.nf" - process "FASTANI" - test("FastANI") { + test("sarscov2 - referece vs contigs - fastANI - 1 v 1 mode") { when { process { @@ -16,13 +17,100 @@ nextflow_process { [ id:'test' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] - input[1] = file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fasta/contigs.fasta', checkIfExists: true) + input[1] = [ + [ id:'test2' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fasta/contigs.fasta', checkIfExists: true) + ] + input[2] = [] + input[3] = [] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.ani, + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() } + ) + } + } + + test("sarscov2 - referece vs contigs - fastANI - all vs all mode") { + + when { + process { + """ + def q_src = file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + def r_src = file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fasta/contigs.fasta', checkIfExists: true) + + // stage into the nf-test execution directory + def q_stage = new File(workDir.toString(), 'query.fasta') + def r_stage = new File(workDir.toString(), 'ref.fasta') + + // Ensures files are staged locally + q_stage.bytes = q_src.bytes + r_stage.bytes = r_src.bytes + + // create ql/rl list files + def ql_file = new File(workDir.toString(), 'query.list') + def rl_file = new File(workDir.toString(), 'reference.list') + + ql_file.text = + q_stage.getAbsolutePath() + System.lineSeparator() + + r_stage.getAbsolutePath() + System.lineSeparator() + + rl_file.text = + q_stage.getAbsolutePath() + System.lineSeparator() + + r_stage.getAbsolutePath() + System.lineSeparator() + + input[0] = [ [], [] ] + input[1] = [ [], [] ] + input[2] = file( ql_file.getAbsolutePath(), checkIfExists: true ) + input[3] = file( rl_file.getAbsolutePath(), checkIfExists: true ) """ } } then { assertAll( + { assert process.success }, + { + def aniFile = path(process.out.ani[0][1]) + assert aniFile.exists() + def lines = aniFile.readLines() + assert lines.size() == 4 : "Expected 4 ANI comparisons but found ${lines.size()}" + }, + { assert snapshot(process.out.findAll { key, val -> key.startsWith("versions") }).match() } + ) + } + } + + test("stub") { + + options '-stub' + + when { + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + input[1] = [ + [ id:'test2' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fasta/contigs.fasta', checkIfExists: true) + ] + input[2] = [] + input[3] = [] + """ + } + } + + then { + assertAll ( { assert process.success }, { assert snapshot(process.out).match() } ) diff --git a/modules/nf-core/fastani/tests/main.nf.test.snap b/modules/nf-core/fastani/tests/main.nf.test.snap index dbb02572949e..cd94a57b9842 100644 --- a/modules/nf-core/fastani/tests/main.nf.test.snap +++ b/modules/nf-core/fastani/tests/main.nf.test.snap @@ -1,5 +1,49 @@ { - "FastANI": { + "sarscov2 - referece vs contigs - fastANI - 1 v 1 mode": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.txt:md5,31d4f04e8cffe13080c86db3f9f3a589" + ] + ], + { + "versions_fastani": [ + [ + "FASTANI", + "fastani", + "1.34" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-02-12T18:20:14.95813302" + }, + "sarscov2 - referece vs contigs - fastANI - all vs all mode": { + "content": [ + { + "versions_fastani": [ + [ + "FASTANI", + "fastani", + "1.34" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-02-13T12:46:56.303203093" + }, + "stub": { "content": [ { "0": [ @@ -7,25 +51,69 @@ { "id": "test" }, - "test.ani.txt:md5,31d4f04e8cffe13080c86db3f9f3a589" + "test.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "1": [ - "versions.yml:md5,6d40b0941a0753738f6c844eb8fc7c73" + [ + { + "id": "test" + }, + "test.visual:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "test.matrix:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + "FASTANI", + "fastani", + "1.34" + ] ], "ani": [ [ { "id": "test" }, - "test.ani.txt:md5,31d4f04e8cffe13080c86db3f9f3a589" + "test.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,6d40b0941a0753738f6c844eb8fc7c73" + "matrix": [ + [ + { + "id": "test" + }, + "test.matrix:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_fastani": [ + [ + "FASTANI", + "fastani", + "1.34" + ] + ], + "visual": [ + [ + { + "id": "test" + }, + "test.visual:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] } ], - "timestamp": "2023-10-18T12:02:08.983912093" + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-02-12T18:20:31.13425659" } } \ No newline at end of file diff --git a/modules/nf-core/fastani/tests/nextflow.config b/modules/nf-core/fastani/tests/nextflow.config new file mode 100644 index 000000000000..ad8804bdb64a --- /dev/null +++ b/modules/nf-core/fastani/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: FASTANI { + ext.args = "--matrix" + } +}