From 36b2e41eb98f4335342e577ad800a71e5fefc1f0 Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:13:45 +1000 Subject: [PATCH 01/13] Ignore branch.yml in files_unchanged lint The 4.0.3 template renders `HEAD_REPO:` with two spaces while the prettier pin used by prek collapses it to one, so the file can never match the template and CI lint fails. Also drops the stale linting_comment.yml entry, replaced by pr-comment.yml in the 4.0.3 template. --- .nf-core.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.nf-core.yml b/.nf-core.yml index d33098c..de98ff1 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -3,7 +3,9 @@ lint: - assets/nf-core-funcprofiler_logo_light.png - .github/PULL_REQUEST_TEMPLATE.md - .github/workflows/linting.yml - - .github/workflows/linting_comment.yml + # The 4.0.3 template renders `HEAD_REPO:` with two spaces, which the prettier + # pin used by prek collapses to one, so this file can never match the template. + - .github/workflows/branch.yml - .gitignore nf_core_version: 4.0.3 repository_type: pipeline From 10f037d1bd7eaecdde69d6af6903a029ea12c940 Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:16:15 +1000 Subject: [PATCH 02/13] Document local subworkflows in meta.yml (#58) All three still described a samtools sort subworkflow copied from the template. --- subworkflows/local/dataprep/meta.yml | 62 ++++++++++++---------------- subworkflows/local/dbprep/meta.yml | 59 ++++++++++---------------- subworkflows/local/profile/meta.yml | 49 +++++++++++++--------- 3 files changed, 79 insertions(+), 91 deletions(-) diff --git a/subworkflows/local/dataprep/meta.yml b/subworkflows/local/dataprep/meta.yml index 40b2a5f..915faa4 100644 --- a/subworkflows/local/dataprep/meta.yml +++ b/subworkflows/local/dataprep/meta.yml @@ -1,50 +1,42 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json name: "dataprep" -## TODO nf-core: Add a description of the subworkflow and list keywords -description: Sort SAM/BAM/CRAM file +description: | + Validate the input samplesheet and prepare read channels for profiling. Sets + `single_end`, `run_accession` and `instrument_platform` on the meta map, merges + multiple runs belonging to the same sample, and produces an additional channel + in which read pairs are concatenated into a single file for tools that cannot + take paired input. keywords: - - sort - - bam - - sam - - cram -## TODO nf-core: Add a list of the modules and/or subworkflows used in the subworkflow + - samplesheet + - fastq + - merging + - concatenation + - metagenome components: - - samtools/sort - - samtools/index -## TODO nf-core: List all of the channels used as input with a description and their structure + - cat/fastq input: - - ch_bam: + - samplesheet: type: file description: | - The input channel containing the BAM/CRAM/SAM files - Structure: [ val(meta), path(bam) ] - pattern: "*.{bam/cram/sam}" -## TODO nf-core: List all of the channels used as output with a descriptions and their structure + Channel of validated samplesheet rows. Long-read (`OXFORD_NANOPORE`) + platforms and FASTA input are rejected, and `fastq_1` is required. + Structure: [ val(meta), val(run_accession), val(instrument_platform), path(fastq_1), path(fastq_2), path(fasta) ] + pattern: "*.{fq,fastq}{,.gz}" output: - - bam: + - reads: type: file description: | - Channel containing BAM files - Structure: [ val(meta), path(bam) ] - pattern: "*.bam" - - bai: + Channel of reads per sample, with runs merged where a sample has more + than one. Paired-end samples carry two files, single-end samples one. + Structure: [ val(meta), [ path(reads) ] ] + pattern: "*.{fq,fastq}{,.gz}" + - reads_concat: type: file description: | - Channel containing indexed BAM (BAI) files - Structure: [ val(meta), path(bai) ] - pattern: "*.bai" - - csi: - type: file - description: | - Channel containing CSI files - Structure: [ val(meta), path(csi) ] - pattern: "*.csi" - - versions: - type: file - description: | - File containing software versions - Structure: [ path(versions.yml) ] - pattern: "versions.yml" + Channel of the same reads concatenated into a single file per sample, + with `single_end` forced to `true`, for tools that accept only one FASTQ. + Structure: [ val(meta), [ path(reads) ] ] + pattern: "*.{fq,fastq}{,.gz}" authors: - "@nickp60" maintainers: diff --git a/subworkflows/local/dbprep/meta.yml b/subworkflows/local/dbprep/meta.yml index c915730..89e987e 100644 --- a/subworkflows/local/dbprep/meta.yml +++ b/subworkflows/local/dbprep/meta.yml @@ -1,50 +1,35 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json name: "dbprep" -## TODO nf-core: Add a description of the subworkflow and list keywords -description: Sort SAM/BAM/CRAM file +description: | + Prepare the databases declared in the database sheet. Archives are decompressed + once per file and only for tools the user has enabled, then all entities + belonging to the same database are grouped so that each profiler receives a + single entry per database name and parameter combination. keywords: - - sort - - bam - - sam - - cram -## TODO nf-core: Add a list of the modules and/or subworkflows used in the subworkflow + - database + - untar + - decompression + - metagenome components: - - samtools/sort - - samtools/index -## TODO nf-core: List all of the channels used as input with a description and their structure + - untar input: - - ch_bam: + - databases: type: file description: | - The input channel containing the BAM/CRAM/SAM files - Structure: [ val(meta), path(bam) ] - pattern: "*.{bam/cram/sam}" -## TODO nf-core: List all of the channels used as output with a descriptions and their structure + Channel of database entries from the database sheet. `meta.tool` selects + which profiler the database belongs to, `meta.db_entity` names the part + of a multi-file database, and `meta.db_params` carries tool-specific + arguments. Entries ending in `.tar`, `.tar.gz`, `.tar.bz2` or `.tar.xz` + are decompressed, the rest are passed through untouched. + Structure: [ val(meta), path(database) ] + pattern: "*.{tar,tar.gz,tar.bz2,tar.xz}" output: - - bam: + - dbs: type: file description: | - Channel containing BAM files - Structure: [ val(meta), path(bam) ] - pattern: "*.bam" - - bai: - type: file - description: | - Channel containing indexed BAM (BAI) files - Structure: [ val(meta), path(bai) ] - pattern: "*.bai" - - csi: - type: file - description: | - Channel containing CSI files - Structure: [ val(meta), path(csi) ] - pattern: "*.csi" - - versions: - type: file - description: | - File containing software versions - Structure: [ path(versions.yml) ] - pattern: "versions.yml" + Channel of databases grouped by tool, name and parameters. The second + element is a list of maps, each holding the entity name and its path. + Structure: [ val(meta), [ [ db_entity: val(entity), db_path: path(db) ] ] ] authors: - "@nickp60" maintainers: diff --git a/subworkflows/local/profile/meta.yml b/subworkflows/local/profile/meta.yml index 78bc923..b1ede4a 100644 --- a/subworkflows/local/profile/meta.yml +++ b/subworkflows/local/profile/meta.yml @@ -1,45 +1,56 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json name: "profile" -## -description: Execute functional profiling tools +description: | + Run the enabled read-based functional profilers. Reads are combined with every + database matching the tool, so a sample is profiled once per database name and + parameter combination. Tools that take paired input read from `reads`, tools + that take a single FASTQ read from `reads_concat`, and each profiler runs only + when its `run_` parameter is set. keywords: - microbiome - metagenome - fastq - - function + - functional profiling components: - - humann/humann - fmhfunprofiler - mifaser + - humann3/humann + - humann3/regroup + - metaphlan/metaphlan + - diamond/blastx - rgi/bwt - -## TODO nf-core: List all of the channels used as input with a description and their structure + - rgi/cardannotation + - eggnogmapper + - seqkit/fq2fa + - gunzip input: - reads: type: file description: | - The input channel containing paired fastq files - Structure: [ val(meta), path(fastq) ] - pattern: "*.{.fastq}*" + Channel of paired-end (or single-end) reads, used by the profilers that + accept a read pair. + Structure: [ val(meta), [ path(reads) ] ] + pattern: "*.{fq,fastq}{,.gz}" - reads_concat: type: file description: | - The input channel containing concatenated fastq pairs as a single fastq - Structure: [ val(meta), path(fastq) ] - pattern: "*.{.fastq}*" + Channel of reads concatenated into a single file per sample, used by the + profilers that accept only one FASTQ. + Structure: [ val(meta), [ path(reads) ] ] + pattern: "*.{fq,fastq}{,.gz}" - databases: type: file description: | - The input channel containing the database files - Structure: [ val(meta), path(file) ] -## TODO nf-core: List all of the channels used as output with a descriptions and their structure + Channel of grouped databases as emitted by the `dbprep` subworkflow. + Structure: [ val(meta), [ [ db_entity: val(entity), db_path: path(db) ] ] ] output: - profiles: type: file description: | - Channel containing tabular profiling results - Structure: [ val(meta), path(paths) ] - pattern: "*.bam" + Channel of the tabular profiles produced by each enabled tool. The meta + map identifies the sample, the tool and the database used. + Structure: [ val(meta), path(profile) ] + pattern: "*.{tsv,csv,txt}" - versions: type: file description: | @@ -49,7 +60,7 @@ output: - mqc: type: file description: | - File containing MultiQC files + Channel of files to be passed on to MultiQC Structure: [ path(file) ] pattern: "*" authors: From 42b0e3aa377ab42625a03f869ee529f196fb2f09 Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:16:55 +1000 Subject: [PATCH 03/13] Drop template TODO comments (#58) Adds real pipeline-specific contribution guidelines in place of the docs/CONTRIBUTING.md placeholder. --- .github/workflows/awsfulltest.yml | 1 - assets/methods_description_template.yml | 1 - conf/base.config | 2 -- docs/CONTRIBUTING.md | 7 ++++++- tests/nextflow.config | 2 -- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 91f761d..4f60919 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -24,7 +24,6 @@ jobs: - name: Launch workflow via Seqera Platform uses: seqeralabs/action-tower-launch@51565b514bff1827cf34620de25d0055759f1fc9 # v2 - # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters with: diff --git a/assets/methods_description_template.yml b/assets/methods_description_template.yml index d1de92d..7900625 100644 --- a/assets/methods_description_template.yml +++ b/assets/methods_description_template.yml @@ -3,7 +3,6 @@ description: "Suggested text and references to use when describing pipeline usag section_name: "nf-core/funcprofiler Methods Description" section_href: "https://github.com/nf-core/funcprofiler" plot_type: "html" -## TODO nf-core: Update the HTML below to your preferred methods description, e.g. add publication citation for this pipeline ## You inject any metadata in the Nextflow '${workflow}' object data: |

Methods

diff --git a/conf/base.config b/conf/base.config index f61c036..49af73f 100644 --- a/conf/base.config +++ b/conf/base.config @@ -10,7 +10,6 @@ process { - // TODO nf-core: Check the defaults for all processes cpus = { 1 * task.attempt } memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } @@ -24,7 +23,6 @@ process { // These labels are used and recognised by default in DSL2 files hosted on nf-core/modules. // If possible, it would be nice to keep the same label naming convention when // adding in your local modules too. - // TODO nf-core: Customise requirements for specific processes. // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors withLabel:process_single { cpus = { 1 } diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 30309b6..95b80c6 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -182,4 +182,9 @@ If you update images or graphics, follow the nf-core [style guidelines](https:// ## Pipeline specific contribution guidelines - +When adding a new profiler: + +- Add it to [nf-core/modules](https://github.com/nf-core/modules) rather than to `modules/local`. A local module is only a stopgap for tools that are not yet packaged on Bioconda. +- Gate it behind a `run_` parameter, and take its database from the database sheet so it is grouped by `dbprep` like every other tool. +- Add it to the `profile` subworkflow, to `docs/output.md`, and to `CITATIONS.md`. +- Cover it with an nf-test, and regenerate snapshots with `nf-test test --update-snapshot`. diff --git a/tests/nextflow.config b/tests/nextflow.config index 3dc70e4..25639c6 100644 --- a/tests/nextflow.config +++ b/tests/nextflow.config @@ -4,8 +4,6 @@ ======================================================================================== */ -// TODO nf-core: Specify any additional parameters here -// Or any resources requirements params { modules_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/' pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' From cd5a90e70bc6a9a1066f69db861e1cee24174c88 Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:19:37 +1000 Subject: [PATCH 04/13] Format nf files with nextflow lint -format (#52) Review point 3 from jfy133. Restores the inline comments the formatter drops. --- main.nf | 2 +- modules/local/humann4/humann/main.nf | 19 +- subworkflows/local/profile/main.nf | 302 +++++++++--------- .../main.nf | 50 +-- workflows/funcprofiler.nf | 52 ++- 5 files changed, 199 insertions(+), 226 deletions(-) diff --git a/main.nf b/main.nf index cfb7114..d45ad6e 100644 --- a/main.nf +++ b/main.nf @@ -38,7 +38,7 @@ workflow NFCORE_FUNCPROFILER { // // WORKFLOW: Run pipeline // - FUNCPROFILER ( + FUNCPROFILER( samplesheet, databases, params.multiqc_config, diff --git a/modules/local/humann4/humann/main.nf b/modules/local/humann4/humann/main.nf index ad5b87d..861ef5e 100644 --- a/modules/local/humann4/humann/main.nf +++ b/modules/local/humann4/humann/main.nf @@ -1,6 +1,6 @@ // Taken 98% from https://github.com/nf-core/modules/pull/1089/files process HUMANN4 { - tag "$meta.id" + tag "${meta.id}" label 'process_high' conda "${moduleDir}/environment.yml" @@ -14,10 +14,10 @@ process HUMANN4 { path utility_db output: - tuple val(meta), path("*_genefamilies.tsv.gz") , emit: genefamilies + tuple val(meta), path("*_genefamilies.tsv.gz"), emit: genefamilies tuple val(meta), path("*_pathabundance.tsv.gz"), emit: pathabundance - tuple val(meta), path("*_reactions.tsv.gz") , emit: reactions - tuple val(meta), path("*.log") , emit: log + tuple val(meta), path("*_reactions.tsv.gz"), emit: reactions + tuple val(meta), path("*.log"), emit: log tuple val("${task.process}"), val('HUMAnN'), eval("humann --version 2>&1 | sed 's/humann v//'"), emit: versions_humann, topic: versions tuple val("${task.process}"), val('MetaPHLan'), eval("metaphlan --version 2>&1 | sed 's/metaphlan v//'"), emit: versions_metaphlan, topic: versions @@ -39,13 +39,13 @@ process HUMANN4 { find \${NUCS_DB} humann \\ - $args \\ + ${args} \\ --threads ${task.cpus} \\ - --input $input \\ + --input ${input} \\ --protein-database \${PROTS_DB} \\ --nucleotide-database \${NUCS_DB} \\ - --output-basename $prefix \\ - $pangenome_string \\ + --output-basename ${prefix} \\ + ${pangenome_string} \\ ${args} \\ --o-log ${prefix}.log \\ --output . @@ -54,11 +54,12 @@ process HUMANN4 { gzip -n *.tsv """ + stub: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" """ - echo $args + echo ${args} for suf in genefamilies.tsv.gz pathabundance.tsv.gz reactions.tsv.gz do diff --git a/subworkflows/local/profile/main.nf b/subworkflows/local/profile/main.nf index 931005b..15c53a7 100644 --- a/subworkflows/local/profile/main.nf +++ b/subworkflows/local/profile/main.nf @@ -2,21 +2,23 @@ // Run profiling // -include { MIFASER } from '../../../modules/nf-core/mifaser/main' -include { HUMANN3_HUMANN } from '../../../modules/nf-core/humann3/humann/main' -include { HUMANN4 } from '../../../modules/local/humann4/humann/main' -include { HUMANN3_REGROUP } from '../../../modules/nf-core/humann3/regroup/main' -include { HUMANN4_REGROUP } from '../../../modules/local/humann4/regroup/main' +include { MIFASER } from '../../../modules/nf-core/mifaser/main' +include { HUMANN3_HUMANN } from '../../../modules/nf-core/humann3/humann/main' +include { HUMANN4 } from '../../../modules/local/humann4/humann/main' +include { HUMANN3_REGROUP } from '../../../modules/nf-core/humann3/regroup/main' +include { HUMANN4_REGROUP } from '../../../modules/local/humann4/regroup/main' //include { FMHFUNPROFILER } from '../../../modules/local/fmhfunprofiler/main' -include { FMHFUNPROFILER } from '../../../modules/nf-core/fmhfunprofiler/main' -include { METAPHLAN_METAPHLAN as MPAHUMANN3; - METAPHLAN_METAPHLAN as MPAHUMANN4 } from '../../../modules/nf-core/metaphlan/metaphlan/main' -include { DIAMOND_BLASTX } from '../../../modules/nf-core/diamond/blastx/main' -include { RGI_BWT } from '../../../modules/nf-core/rgi/bwt/main' -include { RGI_CARDANNOTATION } from '../../../modules/nf-core/rgi/cardannotation/main' -include { EGGNOGMAPPER } from '../../../modules/nf-core/eggnogmapper/main' -include { SEQKIT_FQ2FA } from '../../../modules/nf-core/seqkit/fq2fa/main' -include { GUNZIP } from '../../../modules/nf-core/gunzip/main' +include { FMHFUNPROFILER } from '../../../modules/nf-core/fmhfunprofiler/main' +include { + METAPHLAN_METAPHLAN as MPAHUMANN3 ; + METAPHLAN_METAPHLAN as MPAHUMANN4 +} from '../../../modules/nf-core/metaphlan/metaphlan/main' +include { DIAMOND_BLASTX } from '../../../modules/nf-core/diamond/blastx/main' +include { RGI_BWT } from '../../../modules/nf-core/rgi/bwt/main' +include { RGI_CARDANNOTATION } from '../../../modules/nf-core/rgi/cardannotation/main' +include { EGGNOGMAPPER } from '../../../modules/nf-core/eggnogmapper/main' +include { SEQKIT_FQ2FA } from '../../../modules/nf-core/seqkit/fq2fa/main' +include { GUNZIP } from '../../../modules/nf-core/gunzip/main' // Custom Functions @@ -31,11 +33,13 @@ include { GUNZIP } from '../../../modules * @return A multiMap'ed output channel with two sub channels, one with the profile and the other with the db */ def sanitizeId(str) { - return str.toString() - .replaceAll(/_/, '-') // underscore to hyphens - .replaceAll(/\s+/, '-') // spaces to hyphens - .replaceAll(/[^\w\-.]/, '') // remove special chars - .replaceAll(/-+/, '-') // collapse multiple hyphens + return str + .toString() + // underscores to hyphens, spaces to hyphens, drop special chars, collapse hyphens + .replaceAll(/_/, '-') + .replaceAll(/\s+/, '-') + .replaceAll(/[^\w\-.]/, '') + .replaceAll(/-+/, '-') } def prepareInputs(pairedreads, databases, tool_name, singleFqTool = false) { /* @@ -53,52 +57,45 @@ def prepareInputs(pairedreads, databases, tool_name, singleFqTool = false) { */ // Step 1: Filter databases to only the requested tool, then group by db_name and db_params def ch_dbs_grouped = databases - .flatMap { meta_db, file_list -> + .flatMap { meta_db, file_list -> // Flatten: emit one tuple per file object file_list.collect { file_obj -> - // Merge the file object's db_entity into the metadata - def meta_with_entity = meta_db + [db_entity: file_obj.db_entity] - [meta_with_entity, file_obj] + // Merge the file object's db_entity into the metadata + def meta_with_entity = meta_db + [db_entity: file_obj.db_entity] + [meta_with_entity, file_obj] } - } - .filter { meta_db, file -> + } + .filter { meta_db, file -> meta_db.tool == tool_name - } - .map { meta_db, file -> + } + .map { meta_db, file -> // Create grouping key: [tool, db_name, db_params] - def group_key = [ - meta_db.tool, - meta_db.db_name ?: '', - meta_db.db_params ?: '' - ] + def group_key = [meta_db.tool, meta_db.db_name ?: '', meta_db.db_params ?: ''] [group_key, meta_db, file] - } - .groupTuple() // Group all files for same tool+db_name+db_params - .map { group_key, meta_db_list, files -> - def tool = group_key[0] - def db_name = group_key[1] - def db_params = group_key[2] - - // Convert files list to Map keyed by db_entity for deterministic snapshots - // Map structure: entity_name -> db_path (entity is already in the key) - def files_map = [:] - [meta_db_list, files].transpose().each { meta_db, file -> - files_map[meta_db.db_entity] = file.db_path // Store only the path } - - // Create consolidated metadata with db_entities as a Set - def meta_db_grouped = [ - id: sanitizeId("${tool}--${db_name}--${db_params}"), - tool: tool, - db_name: db_name, - db_params: db_params, - db_entities: files_map.keySet() as Set, // Set of entity names - num_files: files_map.size() - ] - - // Return files as map + // Group all files for same tool+db_name+db_params + .groupTuple() + .map { group_key, meta_db_list, files -> + def tool = group_key[0] + def db_name = group_key[1] + def db_params = group_key[2] + + // Convert files list to Map keyed by db_entity for deterministic snapshots + // Map structure: entity_name -> db_path (entity is already in the key) + def files_map = [:] + [meta_db_list, files] + .transpose() + .each { meta_db, file -> + // Store only the path + files_map[meta_db.db_entity] = file.db_path + } + + // Create consolidated metadata with db_entities as a Set + def meta_db_grouped = [id: sanitizeId("${tool}--${db_name}--${db_params}"), tool: tool, db_name: db_name, db_params: db_params, db_entities: files_map.keySet() as Set, num_files: files_map.size()] + + // Return files as map [meta_db_grouped, files_map.toSorted()] - } + } // Step 2: Combine reads with ALL grouped databases (cartesian product) // Each sample will get one entry per unique db_name+db_params combination for this tool def reads_with_dbs = pairedreads @@ -120,44 +117,45 @@ def prepareInputs(pairedreads, databases, tool_name, singleFqTool = false) { } [meta, reads, db_meta, db_files] } - .multiMap { it -> - reads: [it[0] , it[1]] - db: [ it[2], it[3]] + .multiMap { it -> + reads: [it[0], it[1]] + db: [it[2], it[3]] } return result - } -def getDbPath(groupeddb, entity='main', asTuple=false){ +def getDbPath(groupeddb, entity = 'main', asTuple = false) { // Extract the relevant database file path by entity key from the files map - def dbpath = groupeddb - .map { meta_db, files_map -> - // files_map is now a Map[entity -> db_path], so direct lookup - if (!files_map.containsKey(entity)) { - error("No entity '${entity}' file found in database ${meta_db.id}") - } + def dbpath = groupeddb.map { meta_db, files_map -> + // files_map is now a Map[entity -> db_path], so direct lookup + if (!files_map.containsKey(entity)) { + error("No entity '${entity}' file found in database ${meta_db.id}") + } - def db_path = files_map[entity] // Direct access to path + def db_path = files_map[entity] + // Direct access to path - if (asTuple){ - return [meta_db, db_path] - } else { - return db_path - } + if (asTuple) { + return [meta_db, db_path] + } + else { + return db_path } + } return dbpath } workflow PROFILING { take: - reads // [ [ meta ], [ reads ] ] - reads_concat // [ [ meta ], [ reads ] ] - databases // [ [ meta ], path ] + reads // [ [ meta ], [ reads ] ] + reads_concat // [ [ meta ], [ reads ] ] + databases // [ [ meta ], path ] main: - ch_versions = Channel.empty() - ch_multiqc_files = Channel.empty() - ch_raw_profiles = Channel.empty() // These are count tables + ch_versions = Channel.empty() + ch_multiqc_files = Channel.empty() + ch_raw_profiles = Channel.empty() + // These are count tables /* COMBINE READS WITH POSSIBLE DATABASES @@ -178,109 +176,110 @@ workflow PROFILING { ch_input_for_humann_v4 = prepareInputs(reads_concat, databases, 'humann_v4', true) ch_input_for_mifaser = prepareInputs(reads_concat, databases, 'mifaser', true) - if ( params.run_fmhfunprofiler ) { - // this tool needs the db_params at runtime, so it takes a [[meta], path] tuple instead of just a path - getDbPath(ch_input_for_fmhfunprofiler.db, "main", true) - .multiMap { db_meta, db_path -> - def args = db_meta.db_params.split(" ") - - if (args.size() != 2) { - throw new IllegalArgumentException("fmh-funcprofiler's db_params must be configured with 2 ints (kmer and sketch db args) , but got ${args.size()}: ${db_meta.db_params}") - } - db_path: db_path - kmer: args[0] - sketch: args[1] - } - .set {fmh_db} - FMHFUNPROFILER ( + if (params.run_fmhfunprofiler) { + // this tool needs the db_params at runtime, so it takes a [[meta], path] tuple instead of just a path + getDbPath(ch_input_for_fmhfunprofiler.db, "main", true) + .multiMap { db_meta, db_path -> + def args = db_meta.db_params.split(" ") + + if (args.size() != 2) { + throw new IllegalArgumentException("fmh-funcprofiler's db_params must be configured with 2 ints (kmer and sketch db args) , but got ${args.size()}: ${db_meta.db_params}") + } + db_path: db_path + kmer: args[0] + sketch: args[1] + } + .set { fmh_db } + FMHFUNPROFILER( ch_input_for_fmhfunprofiler.reads, fmh_db.db_path, fmh_db.kmer, - fmh_db.sketch - - ) - ch_raw_profiles = ch_raw_profiles.mix( FMHFUNPROFILER.out.csv ) + fmh_db.sketch, + ) + ch_raw_profiles = ch_raw_profiles.mix(FMHFUNPROFILER.out.csv) } - if ( params.run_mifaser ) { - ch_input_for_mifaser = prepareInputs(reads_concat, databases, 'mifaser', true) - MIFASER ( ch_input_for_mifaser.reads, getDbPath(ch_input_for_mifaser.db, 'main')) - ch_raw_profiles = ch_raw_profiles.mix( MIFASER.out.ec_counts ) + if (params.run_mifaser) { + ch_input_for_mifaser = prepareInputs(reads_concat, databases, 'mifaser', true) + MIFASER(ch_input_for_mifaser.reads, getDbPath(ch_input_for_mifaser.db, 'main')) + ch_raw_profiles = ch_raw_profiles.mix(MIFASER.out.ec_counts) } - if ( params.run_humann_v3 ) { - MPAHUMANN3 ( - ch_input_for_humann_v3.reads, - getDbPath(ch_input_for_humann_v3.db, 'humann_metaphlan'),false - ) - // JOIN the original reads with the profile output - ch_humann3_input = ch_input_for_humann_v3.reads - .join(MPAHUMANN3.out.profile, by: 0) // Join on meta map + if (params.run_humann_v3) { + MPAHUMANN3( + ch_input_for_humann_v3.reads, + getDbPath(ch_input_for_humann_v3.db, 'humann_metaphlan'), + false, + ) + // JOIN the original reads with the profile output + ch_humann3_input = ch_input_for_humann_v3.reads.join(MPAHUMANN3.out.profile, by: 0) + // Join on meta map HUMANN3_HUMANN( - ch_humann3_input.map { it -> [it[0], it[1]] }, // Extract reads - ch_humann3_input.map { it -> [it[0], it[2]] }, // Extract profile + ch_humann3_input.map { it -> [it[0], it[1]] }, + ch_humann3_input.map { it -> [it[0], it[2]] }, getDbPath(ch_input_for_humann_v3.db, 'humann_nucleotide'), getDbPath(ch_input_for_humann_v3.db, 'humann_protein'), getDbPath(ch_input_for_humann_v3.db, 'humann_utility'), ) - HUMANN3_REGROUP(HUMANN3_HUMANN.out.genefamilies, "uniref90_level4ec", getDbPath(ch_input_for_humann_v3.db, 'humann_utility')) - ch_raw_profiles = ch_raw_profiles.mix( MPAHUMANN3.out.profile ) - ch_raw_profiles = ch_raw_profiles.mix( HUMANN3_HUMANN.out.pathabundance ) - .mix( HUMANN3_HUMANN.out.genefamilies ) - .mix( HUMANN3_HUMANN.out.pathcoverage ) + HUMANN3_REGROUP(HUMANN3_HUMANN.out.genefamilies, "uniref90_level4ec", getDbPath(ch_input_for_humann_v3.db, 'humann_utility')) + ch_raw_profiles = ch_raw_profiles.mix(MPAHUMANN3.out.profile) + ch_raw_profiles = ch_raw_profiles + .mix(HUMANN3_HUMANN.out.pathabundance) + .mix(HUMANN3_HUMANN.out.genefamilies) + .mix(HUMANN3_HUMANN.out.pathcoverage) } - if ( params.run_humann_v4 ) { - MPAHUMANN4 ( - ch_input_for_humann_v4.reads, - getDbPath(ch_input_for_humann_v4.db, 'humann_metaphlan'),false - ) - ch_humann4_input = ch_input_for_humann_v4.reads - .join(MPAHUMANN4.out.profile, by: 0) // Join on meta map + if (params.run_humann_v4) { + MPAHUMANN4( + ch_input_for_humann_v4.reads, + getDbPath(ch_input_for_humann_v4.db, 'humann_metaphlan'), + false, + ) + ch_humann4_input = ch_input_for_humann_v4.reads.join(MPAHUMANN4.out.profile, by: 0) + // Join on meta map HUMANN4( - ch_humann4_input.map { it -> [it[0], it[1]] }, // Extract reads - ch_humann4_input.map { it -> [it[0], it[2]] }, // Extract profile + ch_humann4_input.map { it -> [it[0], it[1]] }, + ch_humann4_input.map { it -> [it[0], it[2]] }, getDbPath(ch_input_for_humann_v4.db, 'humann_nucleotide'), getDbPath(ch_input_for_humann_v4.db, 'humann_protein'), getDbPath(ch_input_for_humann_v4.db, 'humann_utility'), ) - HUMANN4_REGROUP(HUMANN4.out.genefamilies, "uniclust90_level4ec", getDbPath(ch_input_for_humann_v4.db, 'humann_utility')) - ch_raw_profiles = ch_raw_profiles.mix( HUMANN4.out.pathabundance ) - .mix( HUMANN4.out.genefamilies ) - .mix( HUMANN4.out.reactions ) + HUMANN4_REGROUP(HUMANN4.out.genefamilies, "uniclust90_level4ec", getDbPath(ch_input_for_humann_v4.db, 'humann_utility')) + ch_raw_profiles = ch_raw_profiles + .mix(HUMANN4.out.pathabundance) + .mix(HUMANN4.out.genefamilies) + .mix(HUMANN4.out.reactions) } - if ( params.run_diamond ) { - DIAMOND_BLASTX ( ch_input_for_diamond.reads, getDbPath(ch_input_for_diamond.db, "main"), 'tsv', '' ) - ch_raw_profiles = ch_raw_profiles.mix( DIAMOND_BLASTX.out.tsv ) + if (params.run_diamond) { + DIAMOND_BLASTX(ch_input_for_diamond.reads, getDbPath(ch_input_for_diamond.db, "main"), 'tsv', '') + ch_raw_profiles = ch_raw_profiles.mix(DIAMOND_BLASTX.out.tsv) } - if ( params.run_rgi ) { + if (params.run_rgi) { RGI_CARDANNOTATION(getDbPath(ch_input_for_rgi.db, "main")) - RGI_BWT( ch_input_for_rgi.reads, RGI_CARDANNOTATION.out.db, [] ) - ch_raw_profiles = ch_raw_profiles.mix( RGI_BWT.out.tsv ) + RGI_BWT(ch_input_for_rgi.reads, RGI_CARDANNOTATION.out.db, []) + ch_raw_profiles = ch_raw_profiles.mix(RGI_BWT.out.tsv) } - if ( params.run_eggnogmapper ) { - SEQKIT_FQ2FA(ch_input_for_eggnogmapper.reads) - GUNZIP(SEQKIT_FQ2FA.out.fasta) - EGGNOGMAPPER ( + if (params.run_eggnogmapper) { + SEQKIT_FQ2FA(ch_input_for_eggnogmapper.reads) + GUNZIP(SEQKIT_FQ2FA.out.fasta) + EGGNOGMAPPER( GUNZIP.out.gunzip, - getDbPath(ch_input_for_eggnogmapper.db, "eggnogmapper_db"), - getDbPath(ch_input_for_eggnogmapper.db, "") + getDbPath(ch_input_for_eggnogmapper.db, "eggnogmapper_db"), + getDbPath(ch_input_for_eggnogmapper.db, ""), ) - ch_raw_profiles = ch_raw_profiles.mix( EGGNOGMAPPER.out.annotations ) - + ch_raw_profiles = ch_raw_profiles.mix(EGGNOGMAPPER.out.annotations) } - emit: - profiles = ch_raw_profiles // channel: [ val(meta), [ reads ] ] - should be text files or biom - versions = ch_versions // channel: [ versions.yml ] - mqc = ch_multiqc_files + profiles = ch_raw_profiles // channel: [ val(meta), [ reads ] ] - should be text files or biom + versions = ch_versions // channel: [ versions.yml ] + mqc = ch_multiqc_files } +// due to https://github.com/askimed/nf-test/issues/309 workflow TEST_PREPAREINPUTS_WRAPPER { - // due to https://github.com/askimed/nf-test/issues/309) take: reads databases @@ -289,7 +288,8 @@ workflow TEST_PREPAREINPUTS_WRAPPER { main: testresult = prepareInputs(reads, databases, tool_name, singleFqTool) + emit: reads = testresult.reads - db = testresult.db + db = testresult.db } diff --git a/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf b/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf index 9d65ed8..a261053 100644 --- a/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf @@ -99,13 +99,15 @@ workflow PIPELINE_INITIALISATION { // Create channel from input file provided through params.input // - Channel.fromList(samplesheetToList(params.input, "assets/schema_input.json")) + Channel + .fromList(samplesheetToList(params.input, "assets/schema_input.json")) .set { ch_samplesheet } // // Create channel from databases file provided through params.databases // - Channel.fromList(samplesheetToList(params.databases, "assets/schema_database.json")) + Channel + .fromList(samplesheetToList(params.databases, "assets/schema_database.json")) .set { ch_databases } emit: @@ -182,9 +184,7 @@ def validateInputSamplesheet(input) { // def toolCitationText() { - def text_qc = [ - "Sequencing quality control was performed with FastQC (Andrews 2010)." - ].join(' ').trim() + def text_qc = ["Sequencing quality control was performed with FastQC (Andrews 2010)."].join(' ').trim() def text_humann = [ "Functional profiling was performed with", @@ -196,25 +196,15 @@ def toolCitationText() { "using MetaPhlAn (Blanco-Míguez et al. 2023) for taxonomic marker-based profiling.", ].join(' ').trim() - def text_diamond = [ - "Protein-level sequence alignment was performed with DIAMOND (Buchfink et al. 2021)." - ].join(' ').trim() + def text_diamond = ["Protein-level sequence alignment was performed with DIAMOND (Buchfink et al. 2021)."].join(' ').trim() - def text_fmhfunprofiler = [ - "Functional profiling was additionally performed with fmhfunprofiler (Hera et al. 2024)." - ].join(' ').trim() + def text_fmhfunprofiler = ["Functional profiling was additionally performed with fmhfunprofiler (Hera et al. 2024)."].join(' ').trim() - def text_mifaser = [ - "Enzyme function annotation was performed with mi-faser (Zhu et al. 2017)." - ].join(' ').trim() + def text_mifaser = ["Enzyme function annotation was performed with mi-faser (Zhu et al. 2017)."].join(' ').trim() - def text_eggnogmapper = [ - "Functional Annotation, Orthology Assignments, and Domain Prediction was performed with eggNOG-mapper v2 (Cantalapiedra et. al 2021)" - ].join(' ').trim() + def text_eggnogmapper = ["Functional Annotation, Orthology Assignments, and Domain Prediction was performed with eggNOG-mapper v2 (Cantalapiedra et. al 2021)"].join(' ').trim() - def text_rgi = [ - "Resistome prediction was performed using RGI (Alcock et. al 2023)" - ].join(' ').trim() + def text_rgi = ["Resistome prediction was performed using RGI (Alcock et. al 2023)"].join(' ').trim() def citation_text = [ "Tools used in the workflow included:", @@ -233,22 +223,16 @@ def toolCitationText() { def toolBibliographyText() { - def text_qc = [ - !params.skip_preprocessing_qc ? "
  • Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. Available at: http://www.bioinformatics.babraham.ac.uk/projects/fastqc/
  • " : "" - ].join(' ').trim() + def text_qc = [!params.skip_preprocessing_qc ? "
  • Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. Available at: http://www.bioinformatics.babraham.ac.uk/projects/fastqc/
  • " : ""].join(' ').trim() def text_humann = [ params.run_humann_v3 || params.run_humann_v4 ? "
  • Beghini, F., McIver, L. J., Blanco-M\u00edguez, A., Dubois, L., Asnicar, F., Maharjan, S., Mailyan, A., Thomas, A. M., Manghi, P., Valles-Colomer, M., Weingart, G., Zhang, Y., Zolfo, M., Huttenhower, C., Franzosa, E. A., & Segata, N. (2021). Integrating taxonomic, functional, and strain-level profiling of diverse microbial communities with bioBakery 3. eLife, 10, e65088. 10.7554/eLife.65088
  • " : "", params.run_humann_v3 || params.run_humann_v4 ? "
  • Blanco-M\u00edguez, A., Beghini, F., Cumbo, F., McIver, L. J., Thompson, K. N., Zolfo, M., Manghi, P., Dubois, L., Huang, K. D., Thomas, A. M., Nickols, W. A., Piccinno, G., Piperni, E., Pun\u010doch\u00e1\u0159, M., Valles-Colomer, M., Tett, A., Giordano, F., Davies, R., Wolf, J., \u2026 Segata, N. (2023). Extending and improving metagenomic taxonomic profiling with uncharacterized species using MetaPhlAn 4. Nature Biotechnology, 41, 1633\u20131645. 10.1038/s41587-023-01688-w
  • " : "", ].join(' ').trim() - def text_diamond = [ - params.run_diamond ? "
  • Buchfink, B., Reuter, K., & Drost, H.-G. (2021). Sensitive protein alignments at tree-of-life scale using DIAMOND. Nature Methods, 18(4), 366–368. 10.1038/s41592-021-01101-x
  • " : "" - ].join(' ').trim() + def text_diamond = [params.run_diamond ? "
  • Buchfink, B., Reuter, K., & Drost, H.-G. (2021). Sensitive protein alignments at tree-of-life scale using DIAMOND. Nature Methods, 18(4), 366–368. 10.1038/s41592-021-01101-x
  • " : ""].join(' ').trim() - def text_fmhfunprofiler = [ - params.run_fmhfunprofiler ? "
  • Hera, M. R., Liu, S., Wei, W., Rodriguez, J. S., Ma, C., & Koslicki, D. (2024). Metagenomic functional profiling: to sketch or not to sketch? Bioinformatics, 40(Suppl 2), ii165–ii173. 10.1093/bioinformatics/btae397
  • " : "" - ].join(' ').trim() + def text_fmhfunprofiler = [params.run_fmhfunprofiler ? "
  • Hera, M. R., Liu, S., Wei, W., Rodriguez, J. S., Ma, C., & Koslicki, D. (2024). Metagenomic functional profiling: to sketch or not to sketch? Bioinformatics, 40(Suppl 2), ii165–ii173. 10.1093/bioinformatics/btae397
  • " : ""].join(' ').trim() def text_mifaser = [ params.run_mifaser ? "
  • Zhu, C., Miller, M., Marpaka, S., Vaysberg, P., R\u00fchlemann, M. C., Wu, G., Heinsen, F.-A., Tempel, M., Woodhouse, L., Burkhardt, L., Tams, R., Knecht, C., Heinig, M., Franke, A., Huser, T., & Bromberg, Y. (2017). Functional sequencing read annotation for high precision microbiome analysis. Nucleic Acids Research, 46(4), e23. 10.1093/nar/gkx1209
  • " : "", @@ -256,13 +240,9 @@ def toolBibliographyText() { params.run_mifaser ? "
  • Zhu, C., Delmont, T. O., Vogel, T. M., & Bromberg, Y. (2015). Functional basis of microorganism classification. PLoS Computational Biology, 11(8), e1004472. 10.1371/journal.pcbi.1004472
  • " : "", ].join(' ').trim() - def text_eggnggmapper = [ - params.run_eggnogmapper ? "
  • Carlos P Cantalapiedra, Ana Hernández-Plaza, Ivica Letunic, Peer Bork, Jaime Huerta-Cepas, eggNOG-mapper v2: Functional Annotation, Orthology Assignments, and Domain Prediction at the Metagenomic Scale, Molecular Biology and Evolution, Volume 38, Issue 12, December 2021, 0.1093/molbev/msab293
  • " : "" - ].join(' ').trim() + def text_eggnggmapper = [params.run_eggnogmapper ? "
  • Carlos P Cantalapiedra, Ana Hernández-Plaza, Ivica Letunic, Peer Bork, Jaime Huerta-Cepas, eggNOG-mapper v2: Functional Annotation, Orthology Assignments, and Domain Prediction at the Metagenomic Scale, Molecular Biology and Evolution, Volume 38, Issue 12, December 2021, 0.1093/molbev/msab293
  • " : ""].join(' ').trim() - def text_rgi = [ - params.run_rgi ? "
  • Alcock et al. 2023. CARD 2023: expanded curation, support for machine learning, and resistome prediction at the Comprehensive Antibiotic Resistance Database. Nucleic Acids Researchpubmed.ncbi.nlm.nih.gov/36263822
  • " : "" - ].join(' ').trim() + def text_rgi = [params.run_rgi ? "
  • Alcock et al. 2023. CARD 2023: expanded curation, support for machine learning, and resistome prediction at the Comprehensive Antibiotic Resistance Database. Nucleic Acids Researchpubmed.ncbi.nlm.nih.gov/36263822
  • " : ""].join(' ').trim() def reference_text = [ text_qc, diff --git a/workflows/funcprofiler.nf b/workflows/funcprofiler.nf index cebaf4b..d3ea1bd 100644 --- a/workflows/funcprofiler.nf +++ b/workflows/funcprofiler.nf @@ -3,9 +3,9 @@ IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { MULTIQC } from '../modules/nf-core/multiqc/main' -include { paramsSummaryMap } from 'plugin/nf-schema' -include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { MULTIQC } from '../modules/nf-core/multiqc/main' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_funcprofiler_pipeline' @@ -35,16 +35,15 @@ include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_func // // MODULE: Installed directly from nf-core/modules // -include { UNTAR } from '../modules/nf-core/untar/main' -include { PROFILING } from '../subworkflows/local/profile/main' -include { DATAPREP } from '../subworkflows/local/dataprep/main' -include { DBPREP } from '../subworkflows/local/dbprep/main' +include { UNTAR } from '../modules/nf-core/untar/main' +include { PROFILING } from '../subworkflows/local/profile/main' +include { DATAPREP } from '../subworkflows/local/dataprep/main' +include { DBPREP } from '../subworkflows/local/dbprep/main' workflow FUNCPROFILER { - take: samplesheet // channel: samplesheet read in from --input databases // channel: databases from --databases @@ -58,26 +57,25 @@ workflow FUNCPROFILER { ch_versions = Channel.empty() ch_multiqc_files = Channel.empty() - DATAPREP ( - samplesheet + DATAPREP( + samplesheet ) - DBPREP ( - databases + DBPREP( + databases ) - PROFILING ( - DATAPREP.out.reads, - DATAPREP.out.reads_concat, - DBPREP.out.dbs + PROFILING( + DATAPREP.out.reads, + DATAPREP.out.reads_concat, + DBPREP.out.dbs, ) - def ch_collated_versions = softwareVersionsToYAML(ch_versions) - .collectFile( - storeDir: "${outdir}/pipeline_info", - name: 'nf_core_' + 'funcprofiler_software_' + 'mqc_' + 'versions.yml', - sort: true, - newLine: true - ) + def ch_collated_versions = softwareVersionsToYAML(ch_versions).collectFile( + storeDir: "${outdir}/pipeline_info", + name: 'nf_core_' + 'funcprofiler_software_' + 'mqc_' + 'versions.yml', + sort: true, + newLine: true, + ) // // MODULE: MultiQC @@ -108,11 +106,5 @@ workflow FUNCPROFILER { emit: multiqc_report = MULTIQC.out.report.map { _meta, report -> [report] }.toList() // channel: /path/to/multiqc_report.html - versions = ch_versions // channel: [ path(versions.yml) ] + versions = ch_versions // channel: [ path(versions.yml) ] } - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - THE END -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ From d86c3a70e82e852c146052bc3c9079c9e0ad670e Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:24:28 +1000 Subject: [PATCH 05/13] Tidy test_full config (#58) Drops commented-out placeholders, plus outdir (set by awsfulltest) and cleanup (not a param, and unused). --- conf/test_full.config | 4 ---- 1 file changed, 4 deletions(-) diff --git a/conf/test_full.config b/conf/test_full.config index 340f238..1edc8bf 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -13,12 +13,8 @@ params { config_profile_name = 'Full test profile' config_profile_description = 'Full test dataset to check pipeline function' -// input = params.pipelines_testdata_base_path + 'samplesheets/test.csv' -// databases = params.pipelines_testdata_base_path + 'database_full.csv' input = 'https://raw.githubusercontent.com/nf-core/test-datasets/refs/heads/taxprofiler/samplesheet_shortreadsonly.csv' databases = 'https://raw.githubusercontent.com/nickp60/test-datasets/refs/heads/funcprofiler/database_full.csv' - outdir = "fulltest_results" - cleanup = false run_fmhfunprofiler = true run_humann_v3 = true run_mifaser = true From 25709f95fa1ddd4dedd892d46e61c7950af75cfd Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:25:05 +1000 Subject: [PATCH 06/13] Rebuild schema to drop false defaults (#58) --- nextflow_schema.json | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index f63b96f..e855d7e 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -129,19 +129,16 @@ }, "run_rgi": { "type": "boolean", - "description": "Turn on profiling with RGI. Requires database to be present CSV file passed to --databases", - "default": false + "description": "Turn on profiling with RGI. Requires database to be present CSV file passed to --databases" }, "run_mifaser": { "type": "boolean", - "description": "Turn on profiling with mi-faser. Requires database to be present CSV file passed to --databases", - "default": false + "description": "Turn on profiling with mi-faser. Requires database to be present CSV file passed to --databases" }, "run_eggnogmapper": { "type": "boolean", "fa_icon": "fas fa-toggle-on", - "description": "Turn on functional annotation with EggNOG-mapper. Requires `eggnogmapper`-tagged database entries in the CSV file passed to --databases", - "default": false + "description": "Turn on functional annotation with EggNOG-mapper. Requires `eggnogmapper`-tagged database entries in the CSV file passed to --databases" } } }, From 6caf2a396f868c88c089f13720faeb9991bff05b Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:28:08 +1000 Subject: [PATCH 07/13] Fix singularity CI: bump apptainer, allow user namespaces All singularity shards fail with 'Failed to create user namespace: Permission denied'; latest-everything only looks green because it is continue-on-error. Apptainer 1.1.2 (action default) is non-suid and the runner image blocks unprivileged userns. --- .github/actions/nf-test/action.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/actions/nf-test/action.yml b/.github/actions/nf-test/action.yml index c024d3a..96e748c 100644 --- a/.github/actions/nf-test/action.yml +++ b/.github/actions/nf-test/action.yml @@ -38,11 +38,16 @@ runs: - name: Setup apptainer if: contains(inputs.profile, 'singularity') uses: eWaterCycle/setup-apptainer@4bb22c52d4f63406c49e94c804632975787312b3 # v2.0.0 + with: + apptainer-version: 1.5.3 - name: Set up Singularity if: contains(inputs.profile, 'singularity') shell: bash run: | + # The runner image restricts unprivileged user namespaces, which non-suid + # apptainer needs to start a container at all. + sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true mkdir -p $NXF_SINGULARITY_CACHEDIR mkdir -p $NXF_SINGULARITY_LIBRARYDIR From bea9f7723b29ee473168407ecc7c75f620a713c1 Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:47:01 +1000 Subject: [PATCH 08/13] Collect software versions from the versions topic (#52) Modules publish to the topic but nothing consumed it, so the MultiQC software versions section was empty. Restores the template's collection block and drops the unused versions/mqc emits from PROFILING. --- subworkflows/local/profile/main.nf | 9 +++----- subworkflows/local/profile/meta.yml | 14 ++---------- workflows/funcprofiler.nf | 35 ++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/subworkflows/local/profile/main.nf b/subworkflows/local/profile/main.nf index 15c53a7..21ddf47 100644 --- a/subworkflows/local/profile/main.nf +++ b/subworkflows/local/profile/main.nf @@ -152,10 +152,8 @@ workflow PROFILING { databases // [ [ meta ], path ] main: - ch_versions = Channel.empty() - ch_multiqc_files = Channel.empty() - ch_raw_profiles = Channel.empty() // These are count tables + ch_raw_profiles = channel.empty() /* COMBINE READS WITH POSSIBLE DATABASES @@ -272,9 +270,8 @@ workflow PROFILING { } emit: - profiles = ch_raw_profiles // channel: [ val(meta), [ reads ] ] - should be text files or biom - versions = ch_versions // channel: [ versions.yml ] - mqc = ch_multiqc_files + profiles = ch_raw_profiles // channel: [ val(meta), path(profile) ] + // Software versions are published to the `versions` topic by each module } diff --git a/subworkflows/local/profile/meta.yml b/subworkflows/local/profile/meta.yml index b1ede4a..2a88dbb 100644 --- a/subworkflows/local/profile/meta.yml +++ b/subworkflows/local/profile/meta.yml @@ -51,18 +51,8 @@ output: map identifies the sample, the tool and the database used. Structure: [ val(meta), path(profile) ] pattern: "*.{tsv,csv,txt}" - - versions: - type: file - description: | - File containing software versions - Structure: [ path(versions.yml) ] - pattern: "versions.yml" - - mqc: - type: file - description: | - Channel of files to be passed on to MultiQC - Structure: [ path(file) ] - pattern: "*" +# Software versions are published to the `versions` topic by each module rather +# than emitted as a channel. authors: - "@nickp60" maintainers: diff --git a/workflows/funcprofiler.nf b/workflows/funcprofiler.nf index d3ea1bd..a68d6f6 100644 --- a/workflows/funcprofiler.nf +++ b/workflows/funcprofiler.nf @@ -70,12 +70,35 @@ workflow FUNCPROFILER { DBPREP.out.dbs, ) - def ch_collated_versions = softwareVersionsToYAML(ch_versions).collectFile( - storeDir: "${outdir}/pipeline_info", - name: 'nf_core_' + 'funcprofiler_software_' + 'mqc_' + 'versions.yml', - sort: true, - newLine: true, - ) + // + // Collate and save software versions + // + def topic_versions = channel + .topic("versions") + .distinct() + .branch { entry -> + versions_file: entry instanceof Path + versions_tuple: true + } + + def topic_versions_string = topic_versions.versions_tuple + .map { process, tool, version -> + [process[process.lastIndexOf(':') + 1..-1], " ${tool}: ${version}"] + } + .groupTuple(by: 0) + .map { process, tool_versions -> + tool_versions.unique().sort() + "${process}:\n${tool_versions.join('\n')}" + } + + def ch_collated_versions = softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + .mix(topic_versions_string) + .collectFile( + storeDir: "${outdir}/pipeline_info", + name: 'nf_core_' + 'funcprofiler_software_' + 'mqc_' + 'versions.yml', + sort: true, + newLine: true, + ) // // MODULE: MultiQC From b8a8fa783dc7463e1d13b0973824682e2ea638bc Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:55:52 +1000 Subject: [PATCH 09/13] Point test configs at nf-core test-datasets nf-core/test-datasets#2172 is merged, so samplesheets/test.csv and database_full.csv now resolve under pipelines_testdata_base_path. Also drops outdir and cleanup from test.config: both sat inside params, so cleanup never reached the Nextflow directive and outdir is supplied by the caller. --- conf/test.config | 5 +---- conf/test_full.config | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/conf/test.config b/conf/test.config index 347dec0..7d055c2 100644 --- a/conf/test.config +++ b/conf/test.config @@ -21,11 +21,8 @@ process { params { config_profile_name = 'Test profile' config_profile_description = 'Minimal test dataset to check pipeline function' - //input = params.pipelines_testdata_base_path + 'samplesheets/test.csv' - input = 'https://github.com/nickp60/test-datasets/raw/refs/heads/funcprofiler/samplesheets/test.csv' + input = params.pipelines_testdata_base_path + 'samplesheets/test.csv' databases = params.pipelines_testdata_base_path + 'database.csv' - outdir = "tmp" - cleanup = false run_fmhfunprofiler = true run_humann_v3 = true run_mifaser = true diff --git a/conf/test_full.config b/conf/test_full.config index 1edc8bf..148780b 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -14,7 +14,7 @@ params { config_profile_name = 'Full test profile' config_profile_description = 'Full test dataset to check pipeline function' input = 'https://raw.githubusercontent.com/nf-core/test-datasets/refs/heads/taxprofiler/samplesheet_shortreadsonly.csv' - databases = 'https://raw.githubusercontent.com/nickp60/test-datasets/refs/heads/funcprofiler/database_full.csv' + databases = params.pipelines_testdata_base_path + 'database_full.csv' run_fmhfunprofiler = true run_humann_v3 = true run_mifaser = true From 83a8416faf5234805666c62c57a2354fdd241cfa Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:55:52 +1000 Subject: [PATCH 10/13] List humann4 modules in profile meta.yml --- subworkflows/local/profile/meta.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subworkflows/local/profile/meta.yml b/subworkflows/local/profile/meta.yml index 2a88dbb..d69de4d 100644 --- a/subworkflows/local/profile/meta.yml +++ b/subworkflows/local/profile/meta.yml @@ -16,6 +16,8 @@ components: - mifaser - humann3/humann - humann3/regroup + - humann4 + - humann4/regroup - metaphlan/metaphlan - diamond/blastx - rgi/bwt From 4b219cf9c9d889fee7bae2c1fe577c9a55a3911d Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Wed, 29 Jul 2026 16:28:25 +1000 Subject: [PATCH 11/13] Update fmhfunprofiler snapshot for new sketch database nf-core/test-datasets#2172 replaced KOs_sketched_scaled_1000_demo.sig.zip on the funcprofiler branch, which is where tests/nextflow.config points pipelines_testdata_base_path. The pipeline-level snapshot already carried the new md5 because it resolves the database through database.csv. --- subworkflows/local/profile/tests/main.nf.test.snap | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/subworkflows/local/profile/tests/main.nf.test.snap b/subworkflows/local/profile/tests/main.nf.test.snap index d34209d..071f27e 100644 --- a/subworkflows/local/profile/tests/main.nf.test.snap +++ b/subworkflows/local/profile/tests/main.nf.test.snap @@ -48,26 +48,26 @@ "content": [ [ "minigut.merged.fastq.gz:md5,1fbae8f5fe6fdfa6552cfca32d9c3129", - "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,16b7196a90c1d2fd3e3109c8d252cd08" + "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,1081039ab9e9b378d2dfd3206e96e917" ] ], - "timestamp": "2026-07-23T16:38:21.384784", + "timestamp": "2026-07-29T16:20:47.621463", "meta": { "nf-test": "0.9.5", - "nextflow": "26.04.4" + "nextflow": "26.04.6" } }, "run multisampleinputs - grouped databases (humann_v3)": { "content": [ [ "minigut.merged.fastq.gz:md5,1fbae8f5fe6fdfa6552cfca32d9c3129", - "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,16b7196a90c1d2fd3e3109c8d252cd08" + "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,1081039ab9e9b378d2dfd3206e96e917" ] ], - "timestamp": "2026-07-24T09:47:36.521206", + "timestamp": "2026-07-29T16:20:29.367839", "meta": { "nf-test": "0.9.5", - "nextflow": "26.04.4" + "nextflow": "26.04.6" } } } \ No newline at end of file From b3b906cc2d1247af855edd1ea53d8187bee24234 Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Wed, 29 Jul 2026 16:47:08 +1000 Subject: [PATCH 12/13] Update outdated nf-core modules and subworkflow diamond 2.1.24 to 2.2.1 and seqkit 2.9.0 to 2.13.0; metaphlan stays on 4.1.1 but drops the pip/setuptools workaround and reports its version through the versions topic. gunzip and untar only gain the apptainer container-engine check. utils_nfschema_plugin renames option keys that this pipeline never sets, since it passes null for both the parameters schema and the CLI typecast. --- modules.json | 14 +-- .../nf-core/diamond/blastx/environment.yml | 2 +- modules/nf-core/diamond/blastx/main.nf | 4 +- modules/nf-core/diamond/blastx/meta.yml | 1 + .../diamond/blastx/tests/main.nf.test.snap | 20 +-- modules/nf-core/gunzip/main.nf | 12 +- modules/nf-core/gunzip/tests/main.nf.test | 54 ++++++++ .../nf-core/gunzip/tests/main.nf.test.snap | 57 +++++++-- .../metaphlan/metaphlan/environment.yml | 3 - modules/nf-core/metaphlan/metaphlan/main.nf | 16 +-- modules/nf-core/metaphlan/metaphlan/meta.yml | 65 ++++++---- .../metaphlan/metaphlan/tests/main.nf.test | 10 +- .../metaphlan/tests/main.nf.test.snap | 119 +++++++++--------- modules/nf-core/mifaser/tests/main.nf.test | 2 +- modules/nf-core/seqkit/fq2fa/environment.yml | 2 +- modules/nf-core/seqkit/fq2fa/main.nf | 18 +-- .../nf-core/seqkit/fq2fa/tests/main.nf.test | 25 ++-- .../seqkit/fq2fa/tests/main.nf.test.snap | 48 ++----- modules/nf-core/untar/main.nf | 2 +- .../nf-core/utils_nfschema_plugin/main.nf | 8 +- 20 files changed, 274 insertions(+), 208 deletions(-) diff --git a/modules.json b/modules.json index 1189520..10c3366 100644 --- a/modules.json +++ b/modules.json @@ -12,7 +12,7 @@ }, "diamond/blastx": { "branch": "master", - "git_sha": "1b534ad2336876dbe82e9fea2773334cb624b426", + "git_sha": "83ce9b314157a24d9a92f17a07ed5d55f30b78f9", "installed_by": ["modules"] }, "eggnogmapper": { @@ -32,7 +32,7 @@ }, "gunzip": { "branch": "master", - "git_sha": "96c57dfd98a0641886a67bd449fe33ee2ec0e374", + "git_sha": "0902eac3012baaf4f9ab6513c8c55acc9353c96c", "installed_by": ["modules"] }, "humann3/humann": { @@ -52,12 +52,12 @@ }, "metaphlan/metaphlan": { "branch": "master", - "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "git_sha": "98ad2ea364508c5eefa3eee721f5659b3d7585a9", "installed_by": ["modules"] }, "mifaser": { "branch": "master", - "git_sha": "6b43745037429413ca11e0e4a1029d90493c3135", + "git_sha": "522d0a5709833aaa28c58d4464b4348d03316a62", "installed_by": ["modules"] }, "multiqc": { @@ -77,12 +77,12 @@ }, "seqkit/fq2fa": { "branch": "master", - "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "git_sha": "d07a945f421a4a91ce4e5a22db63e0e7f8741607", "installed_by": ["modules"] }, "untar": { "branch": "master", - "git_sha": "447f7bc0fa41dfc2400c8cad4c0291880dc060cf", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", "installed_by": ["modules"] } } @@ -101,7 +101,7 @@ }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "ce3424257de288c0ca25f097a68d3a289da23f12", + "git_sha": "a7b27fd25bfa8dcc07d299e88bd790585901a436", "installed_by": ["subworkflows"] } } diff --git a/modules/nf-core/diamond/blastx/environment.yml b/modules/nf-core/diamond/blastx/environment.yml index cca5cbb..5dc13ad 100644 --- a/modules/nf-core/diamond/blastx/environment.yml +++ b/modules/nf-core/diamond/blastx/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::diamond=2.1.24 + - bioconda::diamond=2.2.1 diff --git a/modules/nf-core/diamond/blastx/main.nf b/modules/nf-core/diamond/blastx/main.nf index 2b03de0..453170c 100644 --- a/modules/nf-core/diamond/blastx/main.nf +++ b/modules/nf-core/diamond/blastx/main.nf @@ -4,8 +4,8 @@ process DIAMOND_BLASTX { conda "${moduleDir}/environment.yml" container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container - ? 'https://depot.galaxyproject.org/singularity/diamond:2.1.24--hf93d47f_0' - : 'quay.io/biocontainers/diamond:2.1.24--hf93d47f_0'}" + ? 'https://depot.galaxyproject.org/singularity/diamond:2.2.1--he361c42_0' + : 'quay.io/biocontainers/diamond:2.2.1--he361c42_0'}" input: tuple val(meta), path(fasta) diff --git a/modules/nf-core/diamond/blastx/meta.yml b/modules/nf-core/diamond/blastx/meta.yml index e00b8fa..019a3e9 100644 --- a/modules/nf-core/diamond/blastx/meta.yml +++ b/modules/nf-core/diamond/blastx/meta.yml @@ -176,3 +176,4 @@ maintainers: - "@jfy133" - "@mjamy" - "@vagkaratzas" + - "@sofstam" diff --git a/modules/nf-core/diamond/blastx/tests/main.nf.test.snap b/modules/nf-core/diamond/blastx/tests/main.nf.test.snap index 80340d2..b3cf211 100644 --- a/modules/nf-core/diamond/blastx/tests/main.nf.test.snap +++ b/modules/nf-core/diamond/blastx/tests/main.nf.test.snap @@ -6,16 +6,16 @@ [ "DIAMOND_BLASTX", "diamond", - "2.1.24" + "2.2.1" ] ] } ], + "timestamp": "2026-06-09T15:06:53.562101168", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.4" - }, - "timestamp": "2026-04-22T15:47:51.928317786" + "nf-test": "0.9.5", + "nextflow": "26.04.3" + } }, "Should search for transcriptome hits against a DIAMOND db and return the default tab separated output file of hits": { "content": [ @@ -32,15 +32,15 @@ [ "DIAMOND_BLASTX", "diamond", - "2.1.24" + "2.2.1" ] ] } ], + "timestamp": "2026-06-09T15:06:47.844654623", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.4" - }, - "timestamp": "2026-04-22T15:47:45.383426326" + "nf-test": "0.9.5", + "nextflow": "26.04.3" + } } } \ No newline at end of file diff --git a/modules/nf-core/gunzip/main.nf b/modules/nf-core/gunzip/main.nf index a8533e7..6edffc5 100644 --- a/modules/nf-core/gunzip/main.nf +++ b/modules/nf-core/gunzip/main.nf @@ -3,7 +3,7 @@ process GUNZIP { label 'process_single' conda "${moduleDir}/environment.yml" - container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + 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'}" @@ -19,8 +19,9 @@ process GUNZIP { script: def args = task.ext.args ?: '' - def extension = (archive.toString() - '.gz').tokenize('.')[-1] - def name = archive.toString() - '.gz' - ".${extension}" + 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}" """ @@ -35,8 +36,9 @@ process GUNZIP { """ stub: - def extension = (archive.toString() - '.gz').tokenize('.')[-1] - def name = archive.toString() - '.gz' - ".${extension}" + 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}" """ diff --git a/modules/nf-core/gunzip/tests/main.nf.test b/modules/nf-core/gunzip/tests/main.nf.test index 776211a..33cb75a 100644 --- a/modules/nf-core/gunzip/tests/main.nf.test +++ b/modules/nf-core/gunzip/tests/main.nf.test @@ -89,6 +89,60 @@ nextflow_process { } + 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' diff --git a/modules/nf-core/gunzip/tests/main.nf.test.snap b/modules/nf-core/gunzip/tests/main.nf.test.snap index 111ba1b..980e95a 100644 --- a/modules/nf-core/gunzip/tests/main.nf.test.snap +++ b/modules/nf-core/gunzip/tests/main.nf.test.snap @@ -1,4 +1,45 @@ { + "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": [ { @@ -34,11 +75,11 @@ ] } ], + "timestamp": "2026-01-19T17:21:56.633550769", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-19T17:21:56.633550769" + } }, "Should run without failures - stub": { "content": [ @@ -75,11 +116,11 @@ ] } ], + "timestamp": "2026-01-19T17:21:51.435621199", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-19T17:21:51.435621199" + } }, "Should run without failures": { "content": [ @@ -116,11 +157,11 @@ ] } ], + "timestamp": "2026-01-19T17:21:40.613975821", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-19T17:21:40.613975821" + } }, "Should run without failures - prefix": { "content": [ @@ -157,10 +198,10 @@ ] } ], + "timestamp": "2026-01-19T17:21:46.086880414", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-19T17:21:46.086880414" + } } } \ No newline at end of file diff --git a/modules/nf-core/metaphlan/metaphlan/environment.yml b/modules/nf-core/metaphlan/metaphlan/environment.yml index 572f03f..9d80006 100644 --- a/modules/nf-core/metaphlan/metaphlan/environment.yml +++ b/modules/nf-core/metaphlan/metaphlan/environment.yml @@ -5,6 +5,3 @@ channels: - bioconda dependencies: - bioconda::metaphlan=4.1.1 - - pip - - pip: - - setuptools diff --git a/modules/nf-core/metaphlan/metaphlan/main.nf b/modules/nf-core/metaphlan/metaphlan/main.nf index 953abfc..a5ce6c5 100644 --- a/modules/nf-core/metaphlan/metaphlan/main.nf +++ b/modules/nf-core/metaphlan/metaphlan/main.nf @@ -9,7 +9,7 @@ process METAPHLAN_METAPHLAN { input: tuple val(meta), path(input) - path metaphlan_db_latest + path db_metaphlan_latest val save_samfile output: @@ -17,7 +17,7 @@ process METAPHLAN_METAPHLAN { tuple val(meta), path("*.biom"), emit: biom tuple val(meta), path('*.bowtie2out.txt'), optional: true, emit: bt2out tuple val(meta), path("*.sam"), optional: true, emit: sam - path "versions.yml", emit: versions + tuple val("${task.process}"), val('metaphlan'), eval("metaphlan --version 2>&1 | cut -d ' ' -f 3"), emit: versions_metaphlan, topic: versions when: task.ext.when == null || task.ext.when @@ -30,8 +30,8 @@ process METAPHLAN_METAPHLAN { def bowtie2_out = "${input_type}" == "--input_type bowtie2out" || "${input_type}" == "--input_type sam" ? '' : "--bowtie2out ${prefix}.bowtie2out.txt" def samfile_out = save_samfile ? "-s ${prefix}.sam" : '' """ - BT2_DB=`find -L "${metaphlan_db_latest}" -name "*rev.1.bt2*" -exec dirname {} \\;` - BT2_DB_INDEX=`find -L ${metaphlan_db_latest} -name "*.rev.1.bt2*" | sed 's/\\.rev.1.bt2.*\$//' | sed 's/.*\\///'` + BT2_DB=`find -L "${db_metaphlan_latest}" -name "*rev.1.bt2*" -exec dirname {} \\;` + BT2_DB_INDEX=`find -L ${db_metaphlan_latest} -name "*.rev.1.bt2*" | sed 's/\\.rev.1.bt2.*\$//' | sed 's/.*\\///'` metaphlan \\ --nproc ${task.cpus} \\ @@ -45,10 +45,6 @@ process METAPHLAN_METAPHLAN { --biom ${prefix}.biom \\ --output_file ${prefix}_profile.txt - cat <<-END_VERSIONS > versions.yml - "${task.process}": - metaphlan: \$(metaphlan --version 2>&1 | awk '{print \$3}') - END_VERSIONS """ stub: @@ -66,9 +62,5 @@ process METAPHLAN_METAPHLAN { ${samfile_cmd} ${bowtie2_cmd} - cat <<-END_VERSIONS > versions.yml - "${task.process}": - metaphlan: \$(metaphlan --version 2>&1 | awk '{print \$3}') - END_VERSIONS """ } diff --git a/modules/nf-core/metaphlan/metaphlan/meta.yml b/modules/nf-core/metaphlan/metaphlan/meta.yml index 8bc6c07..647f138 100644 --- a/modules/nf-core/metaphlan/metaphlan/meta.yml +++ b/modules/nf-core/metaphlan/metaphlan/meta.yml @@ -1,6 +1,6 @@ name: metaphlan_metaphlan -description: MetaPhlAn is a tool for profiling the composition of microbial communities - from metagenomic shotgun sequencing data. +description: MetaPhlAn is a tool for profiling the composition of microbial + communities from metagenomic shotgun sequencing data. keywords: - metagenomics - classification @@ -9,12 +9,13 @@ keywords: - sam tools: - metaphlan: - description: Identify clades (phyla to species) present in the metagenome obtained - from a microbiome sample and their relative abundance + description: Identify clades (phyla to species) present in the metagenome + obtained from a microbiome sample and their relative abundance homepage: https://huttenhower.sph.harvard.edu/metaphlan/ documentation: https://github.com/biobakery/MetaPhlAn doi: "10.1038/s41587-023-01688-w" - licence: ["MIT License"] + licence: + - "MIT License" identifier: biotools:metaphlan input: - - meta: @@ -24,13 +25,13 @@ input: e.g. [ id:'test', single_end:false ] - input: type: file - description: Metaphlan can classify the metagenome from a variety of input data - types, including FASTQ files (single-end and paired-end), FASTA, bowtie2-produced - SAM files (produced from alignments to the MetaPHlAn marker database) and - intermediate bowtie2 alignment files (bowtie2out) + description: Metaphlan can classify the metagenome from a variety of input + data types, including FASTQ files (single-end and paired-end), FASTA, + bowtie2-produced SAM files (produced from alignments to the MetaPHlAn + marker database) and intermediate bowtie2 alignment files (bowtie2out) pattern: "*.{fastq.gz, fasta, fasta.gz, sam, bowtie2out.txt}" ontologies: [] - - metaphlan_db_latest: + - db_metaphlan_latest: type: file description: | Directory containing pre-downloaded and uncompressed MetaPhlAn database downloaded from: http://cmprod1.cibio.unitn.it/biobakery4/metaphlan_databases/. @@ -50,7 +51,8 @@ output: e.g. [ id:'test', single_end:false ] - "*_profile.txt": type: file - description: Tab-separated output file of the predicted taxon relative abundances + description: Tab-separated output file of the predicted taxon relative + abundances pattern: "*.{txt}" ontologies: [] biom: @@ -61,11 +63,11 @@ output: e.g. [ id:'test', single_end:false ] - "*.biom": type: file - description: General-use format for representing biological sample by observation - contingency tables + description: General-use format for representing biological sample by + observation contingency tables pattern: "*.{biom}" ontologies: - - edam: http://edamontology.org/format_3746 # BIOM format + - edam: http://edamontology.org/format_3746 bt2out: - - meta: type: map @@ -74,9 +76,9 @@ output: e.g. [ id:'test', single_end:false ] - "*.bowtie2out.txt": type: file - description: Intermediate Bowtie2 output produced from mapping the metagenome - against the MetaPHlAn marker database ( not compatible with `bowtie2out` - files generated with MetaPhlAn versions below 3 ) + description: Intermediate Bowtie2 output produced from mapping the + metagenome against the MetaPHlAn marker database ( not compatible with + `bowtie2out` files generated with MetaPhlAn versions below 3 ) pattern: "*.{bowtie2out.txt}" ontologies: [] sam: @@ -87,16 +89,31 @@ output: e.g. [ id:'test', single_end:false ] - "*.sam": type: file - description: SAM file produced by MetaPPhlAn of read alignments to MetaPhlAn database gene sequences + description: SAM file produced by MetaPPhlAn of read alignments to + MetaPhlAn database gene sequences pattern: "*.{sam}" ontologies: [] + versions_metaphlan: + - - ${task.process}: + type: string + description: The process the versions were collected from + - metaphlan: + type: string + description: The tool name + - "metaphlan --version 2>&1 | cut -d ' ' -f 3": + type: eval + description: The command used to generate 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 process the versions were collected from + - metaphlan: + type: string + description: The tool name + - "metaphlan --version 2>&1 | cut -d ' ' -f 3": + type: eval + description: The command used to generate the version of the tool authors: - "@MGordon09" - "@LilyAnderssonLee" diff --git a/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test index 606f060..415d171 100644 --- a/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test +++ b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test @@ -47,7 +47,7 @@ nextflow_process { path(process.out.profile[0][1]).readLines()[2..5], path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), process.out.bt2out, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) @@ -77,7 +77,7 @@ nextflow_process { path(process.out.profile[0][1]).readLines()[2..5], path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), process.out.bt2out, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) @@ -106,7 +106,7 @@ nextflow_process { path(process.out.profile[0][1]).readLines()[2..5], path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), process.out.bt2out, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -136,7 +136,7 @@ nextflow_process { path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), process.out.bt2out, sam(process.out.sam.get(0).get(1)).getFileType(), - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) @@ -164,7 +164,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( process.out ).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } } diff --git a/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap index a5b0f9a..26f8d05 100644 --- a/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap +++ b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap @@ -2,39 +2,6 @@ "sarscov2 - illumina pair end [fastq] - stub": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test_profile.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.biom:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bowtie2out.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" - ], "biom": [ [ { @@ -65,15 +32,19 @@ "sam": [ ], - "versions": [ - "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + "versions_metaphlan": [ + [ + "METAPHLAN_METAPHLAN", + "metaphlan", + "4.1.1" + ] ] } ], - "timestamp": "2026-02-16T10:17:01.145927415", + "timestamp": "2026-06-09T17:19:58.375514149", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nf-test": "0.9.5", + "nextflow": "26.04.0" } }, "sarscov2 - illumina pair end [fastq] - save sam": { @@ -95,14 +66,20 @@ ] ], "SAM", - [ - "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" - ] + { + "versions_metaphlan": [ + [ + "METAPHLAN_METAPHLAN", + "metaphlan", + "4.1.1" + ] + ] + } ], - "timestamp": "2025-08-22T07:33:29.981757425", + "timestamp": "2026-06-09T17:19:47.219030947", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.5", + "nextflow": "26.04.0" } }, "sarscov2 - illumina single end [fastq]": { @@ -123,14 +100,20 @@ "test.bowtie2out.txt:md5,ef46a9c6a8ce9cae26fbfd5527116fd5" ] ], - [ - "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" - ] + { + "versions_metaphlan": [ + [ + "METAPHLAN_METAPHLAN", + "metaphlan", + "4.1.1" + ] + ] + } ], - "timestamp": "2024-08-27T10:33:32.269571148", + "timestamp": "2026-06-09T17:19:05.401336447", "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.5", + "nextflow": "26.04.0" } }, "sarscov2 - illumina single end [fasta]": { @@ -151,14 +134,20 @@ "test.bowtie2out.txt:md5,d99d05d6b011c647adf816f10fc6acbe" ] ], - [ - "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" - ] + { + "versions_metaphlan": [ + [ + "METAPHLAN_METAPHLAN", + "metaphlan", + "4.1.1" + ] + ] + } ], - "timestamp": "2024-08-27T10:34:10.262604527", + "timestamp": "2026-06-09T17:19:32.907241155", "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.5", + "nextflow": "26.04.0" } }, "sarscov2 - illumina pair end [fastq]": { @@ -179,14 +168,20 @@ "test.bowtie2out.txt:md5,8c1bc21e1d8484b5551bf46331d61bd8" ] ], - [ - "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" - ] + { + "versions_metaphlan": [ + [ + "METAPHLAN_METAPHLAN", + "metaphlan", + "4.1.1" + ] + ] + } ], - "timestamp": "2024-08-27T10:33:51.829732777", + "timestamp": "2026-06-09T17:19:19.166830424", "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.5", + "nextflow": "26.04.0" } } } \ No newline at end of file diff --git a/modules/nf-core/mifaser/tests/main.nf.test b/modules/nf-core/mifaser/tests/main.nf.test index fa7a239..954ba2b 100644 --- a/modules/nf-core/mifaser/tests/main.nf.test +++ b/modules/nf-core/mifaser/tests/main.nf.test @@ -33,7 +33,7 @@ nextflow_process { [ id:'test', single_end:true ], [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] ] - input[1] = UNTAR.out.untar.map{ meta, dir -> dir.resolve("database/mifaser/GS-24-all") } + input[1] = UNTAR.out.untar.map { it[1] } """ } } diff --git a/modules/nf-core/seqkit/fq2fa/environment.yml b/modules/nf-core/seqkit/fq2fa/environment.yml index b26fb1e..09abb79 100644 --- a/modules/nf-core/seqkit/fq2fa/environment.yml +++ b/modules/nf-core/seqkit/fq2fa/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::seqkit=2.9.0 + - bioconda::seqkit=2.13.0 diff --git a/modules/nf-core/seqkit/fq2fa/main.nf b/modules/nf-core/seqkit/fq2fa/main.nf index 313af89..0722455 100644 --- a/modules/nf-core/seqkit/fq2fa/main.nf +++ b/modules/nf-core/seqkit/fq2fa/main.nf @@ -1,11 +1,11 @@ process SEQKIT_FQ2FA { - tag "$meta.id" + tag "${meta.id}" label 'process_single' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/seqkit:2.9.0--h9ee0642_0' : - 'quay.io/biocontainers/seqkit:2.9.0--h9ee0642_0' }" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/4f/4fe272ab9a519cf418160471a485b5ef50ea3f571a8e4555a826f70a4d8243ae/data' + : 'community.wave.seqera.io/library/seqkit:2.13.0--05c0a96bf9fb2751'}" input: tuple val(meta), path(fastq) @@ -20,19 +20,21 @@ process SEQKIT_FQ2FA { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - """ seqkit \\ fq2fa \\ - $args \\ - -j $task.cpus \\ + ${args} \\ + -j ${task.cpus} \\ -o ${prefix}.fa.gz \\ - $fastq + ${fastq} """ stub: + def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" """ + echo ${args} + echo "" | gzip > ${prefix}.fa.gz """ } diff --git a/modules/nf-core/seqkit/fq2fa/tests/main.nf.test b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test index 08f399e..b20ac23 100644 --- a/modules/nf-core/seqkit/fq2fa/tests/main.nf.test +++ b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test @@ -10,47 +10,44 @@ nextflow_process { tag "seqkit/fq2fa" test("sarscov2 - bam") { - when { process { """ - input[0] = [[ id:'test', single_end:false ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } - } test("sarscov2 - bam - stub") { - - options "-stub" + options '-stub' when { process { """ - input[0] = [[ id:'test', single_end:false ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } - } - } diff --git a/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap index b96e153..ea4763d 100644 --- a/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap +++ b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap @@ -2,22 +2,6 @@ "sarscov2 - bam - stub": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.fa.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] - ], - "1": [ - [ - "SEQKIT_FQ2FA", - "seqkit", - "2.9.0" - ] - ], "fasta": [ [ { @@ -31,36 +15,20 @@ [ "SEQKIT_FQ2FA", "seqkit", - "2.9.0" + "2.13.0" ] ] } ], - "timestamp": "2026-03-12T13:05:56.983767141", + "timestamp": "2026-06-15T10:19:21.836507096", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nf-test": "0.9.5", + "nextflow": "26.04.3" } }, "sarscov2 - bam": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.fa.gz:md5,f0c5c9110ce19e9ebbc9a6b6baf9e105" - ] - ], - "1": [ - [ - "SEQKIT_FQ2FA", - "seqkit", - "2.9.0" - ] - ], "fasta": [ [ { @@ -74,15 +42,15 @@ [ "SEQKIT_FQ2FA", "seqkit", - "2.9.0" + "2.13.0" ] ] } ], - "timestamp": "2026-03-12T13:05:49.874408711", + "timestamp": "2026-06-12T17:24:20.019577498", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nf-test": "0.9.5", + "nextflow": "26.04.3" } } } \ No newline at end of file diff --git a/modules/nf-core/untar/main.nf b/modules/nf-core/untar/main.nf index b9c324d..bf2c056 100644 --- a/modules/nf-core/untar/main.nf +++ b/modules/nf-core/untar/main.nf @@ -3,7 +3,7 @@ process UNTAR { label 'process_single' conda "${moduleDir}/environment.yml" - container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + 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'}" diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf index 0d9d4e0..9ff0681 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -35,7 +35,7 @@ workflow UTILS_NFSCHEMA_PLUGIN { fullHelp: help_full, ] if(parameters_schema) { - help_options << [parametersSchema: parameters_schema] + help_options << [parameters_schema: parameters_schema] } log.info paramsHelp( help_options, @@ -51,7 +51,7 @@ workflow UTILS_NFSCHEMA_PLUGIN { summary_options = [:] if(parameters_schema) { - summary_options << [parametersSchema: parameters_schema] + summary_options << [parameters_schema: parameters_schema] } log.info before_text log.info paramsSummaryLog(summary_options, input_workflow) @@ -64,10 +64,10 @@ workflow UTILS_NFSCHEMA_PLUGIN { if(validate_params) { validateOptions = [:] if(parameters_schema) { - validateOptions << [parametersSchema: parameters_schema] + validateOptions << [parameters_schema: parameters_schema] } if(cli_typecast != null) { - validateOptions << [cliTypecast: cli_typecast] + validateOptions << [cast_cli_params: cli_typecast] } validateParameters(validateOptions) } From d6a6c77df6249660bcccd7f180da235521667214 Mon Sep 17 00:00:00 2001 From: Vini Salazar <17276653+vinisalazar@users.noreply.github.com> Date: Wed, 29 Jul 2026 16:56:21 +1000 Subject: [PATCH 13/13] Revert metaphlan module update, it breaks conda The newer module drops the pip/setuptools dependency, leaving metaphlan on a Python 3.12 env with no distutils. Docker is unaffected. --- modules.json | 2 +- .../metaphlan/metaphlan/environment.yml | 3 + modules/nf-core/metaphlan/metaphlan/main.nf | 16 ++- modules/nf-core/metaphlan/metaphlan/meta.yml | 65 ++++------ .../metaphlan/metaphlan/tests/main.nf.test | 10 +- .../metaphlan/tests/main.nf.test.snap | 119 +++++++++--------- 6 files changed, 107 insertions(+), 108 deletions(-) diff --git a/modules.json b/modules.json index 10c3366..68fa76c 100644 --- a/modules.json +++ b/modules.json @@ -52,7 +52,7 @@ }, "metaphlan/metaphlan": { "branch": "master", - "git_sha": "98ad2ea364508c5eefa3eee721f5659b3d7585a9", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", "installed_by": ["modules"] }, "mifaser": { diff --git a/modules/nf-core/metaphlan/metaphlan/environment.yml b/modules/nf-core/metaphlan/metaphlan/environment.yml index 9d80006..572f03f 100644 --- a/modules/nf-core/metaphlan/metaphlan/environment.yml +++ b/modules/nf-core/metaphlan/metaphlan/environment.yml @@ -5,3 +5,6 @@ channels: - bioconda dependencies: - bioconda::metaphlan=4.1.1 + - pip + - pip: + - setuptools diff --git a/modules/nf-core/metaphlan/metaphlan/main.nf b/modules/nf-core/metaphlan/metaphlan/main.nf index a5ce6c5..953abfc 100644 --- a/modules/nf-core/metaphlan/metaphlan/main.nf +++ b/modules/nf-core/metaphlan/metaphlan/main.nf @@ -9,7 +9,7 @@ process METAPHLAN_METAPHLAN { input: tuple val(meta), path(input) - path db_metaphlan_latest + path metaphlan_db_latest val save_samfile output: @@ -17,7 +17,7 @@ process METAPHLAN_METAPHLAN { tuple val(meta), path("*.biom"), emit: biom tuple val(meta), path('*.bowtie2out.txt'), optional: true, emit: bt2out tuple val(meta), path("*.sam"), optional: true, emit: sam - tuple val("${task.process}"), val('metaphlan'), eval("metaphlan --version 2>&1 | cut -d ' ' -f 3"), emit: versions_metaphlan, topic: versions + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when @@ -30,8 +30,8 @@ process METAPHLAN_METAPHLAN { def bowtie2_out = "${input_type}" == "--input_type bowtie2out" || "${input_type}" == "--input_type sam" ? '' : "--bowtie2out ${prefix}.bowtie2out.txt" def samfile_out = save_samfile ? "-s ${prefix}.sam" : '' """ - BT2_DB=`find -L "${db_metaphlan_latest}" -name "*rev.1.bt2*" -exec dirname {} \\;` - BT2_DB_INDEX=`find -L ${db_metaphlan_latest} -name "*.rev.1.bt2*" | sed 's/\\.rev.1.bt2.*\$//' | sed 's/.*\\///'` + BT2_DB=`find -L "${metaphlan_db_latest}" -name "*rev.1.bt2*" -exec dirname {} \\;` + BT2_DB_INDEX=`find -L ${metaphlan_db_latest} -name "*.rev.1.bt2*" | sed 's/\\.rev.1.bt2.*\$//' | sed 's/.*\\///'` metaphlan \\ --nproc ${task.cpus} \\ @@ -45,6 +45,10 @@ process METAPHLAN_METAPHLAN { --biom ${prefix}.biom \\ --output_file ${prefix}_profile.txt + cat <<-END_VERSIONS > versions.yml + "${task.process}": + metaphlan: \$(metaphlan --version 2>&1 | awk '{print \$3}') + END_VERSIONS """ stub: @@ -62,5 +66,9 @@ process METAPHLAN_METAPHLAN { ${samfile_cmd} ${bowtie2_cmd} + cat <<-END_VERSIONS > versions.yml + "${task.process}": + metaphlan: \$(metaphlan --version 2>&1 | awk '{print \$3}') + END_VERSIONS """ } diff --git a/modules/nf-core/metaphlan/metaphlan/meta.yml b/modules/nf-core/metaphlan/metaphlan/meta.yml index 647f138..8bc6c07 100644 --- a/modules/nf-core/metaphlan/metaphlan/meta.yml +++ b/modules/nf-core/metaphlan/metaphlan/meta.yml @@ -1,6 +1,6 @@ name: metaphlan_metaphlan -description: MetaPhlAn is a tool for profiling the composition of microbial - communities from metagenomic shotgun sequencing data. +description: MetaPhlAn is a tool for profiling the composition of microbial communities + from metagenomic shotgun sequencing data. keywords: - metagenomics - classification @@ -9,13 +9,12 @@ keywords: - sam tools: - metaphlan: - description: Identify clades (phyla to species) present in the metagenome - obtained from a microbiome sample and their relative abundance + description: Identify clades (phyla to species) present in the metagenome obtained + from a microbiome sample and their relative abundance homepage: https://huttenhower.sph.harvard.edu/metaphlan/ documentation: https://github.com/biobakery/MetaPhlAn doi: "10.1038/s41587-023-01688-w" - licence: - - "MIT License" + licence: ["MIT License"] identifier: biotools:metaphlan input: - - meta: @@ -25,13 +24,13 @@ input: e.g. [ id:'test', single_end:false ] - input: type: file - description: Metaphlan can classify the metagenome from a variety of input - data types, including FASTQ files (single-end and paired-end), FASTA, - bowtie2-produced SAM files (produced from alignments to the MetaPHlAn - marker database) and intermediate bowtie2 alignment files (bowtie2out) + description: Metaphlan can classify the metagenome from a variety of input data + types, including FASTQ files (single-end and paired-end), FASTA, bowtie2-produced + SAM files (produced from alignments to the MetaPHlAn marker database) and + intermediate bowtie2 alignment files (bowtie2out) pattern: "*.{fastq.gz, fasta, fasta.gz, sam, bowtie2out.txt}" ontologies: [] - - db_metaphlan_latest: + - metaphlan_db_latest: type: file description: | Directory containing pre-downloaded and uncompressed MetaPhlAn database downloaded from: http://cmprod1.cibio.unitn.it/biobakery4/metaphlan_databases/. @@ -51,8 +50,7 @@ output: e.g. [ id:'test', single_end:false ] - "*_profile.txt": type: file - description: Tab-separated output file of the predicted taxon relative - abundances + description: Tab-separated output file of the predicted taxon relative abundances pattern: "*.{txt}" ontologies: [] biom: @@ -63,11 +61,11 @@ output: e.g. [ id:'test', single_end:false ] - "*.biom": type: file - description: General-use format for representing biological sample by - observation contingency tables + description: General-use format for representing biological sample by observation + contingency tables pattern: "*.{biom}" ontologies: - - edam: http://edamontology.org/format_3746 + - edam: http://edamontology.org/format_3746 # BIOM format bt2out: - - meta: type: map @@ -76,9 +74,9 @@ output: e.g. [ id:'test', single_end:false ] - "*.bowtie2out.txt": type: file - description: Intermediate Bowtie2 output produced from mapping the - metagenome against the MetaPHlAn marker database ( not compatible with - `bowtie2out` files generated with MetaPhlAn versions below 3 ) + description: Intermediate Bowtie2 output produced from mapping the metagenome + against the MetaPHlAn marker database ( not compatible with `bowtie2out` + files generated with MetaPhlAn versions below 3 ) pattern: "*.{bowtie2out.txt}" ontologies: [] sam: @@ -89,31 +87,16 @@ output: e.g. [ id:'test', single_end:false ] - "*.sam": type: file - description: SAM file produced by MetaPPhlAn of read alignments to - MetaPhlAn database gene sequences + description: SAM file produced by MetaPPhlAn of read alignments to MetaPhlAn database gene sequences pattern: "*.{sam}" ontologies: [] - versions_metaphlan: - - - ${task.process}: - type: string - description: The process the versions were collected from - - metaphlan: - type: string - description: The tool name - - "metaphlan --version 2>&1 | cut -d ' ' -f 3": - type: eval - description: The command used to generate the version of the tool -topics: versions: - - - ${task.process}: - type: string - description: The process the versions were collected from - - metaphlan: - type: string - description: The tool name - - "metaphlan --version 2>&1 | cut -d ' ' -f 3": - type: eval - description: The command used to generate the version of the tool + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@MGordon09" - "@LilyAnderssonLee" diff --git a/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test index 415d171..606f060 100644 --- a/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test +++ b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test @@ -47,7 +47,7 @@ nextflow_process { path(process.out.profile[0][1]).readLines()[2..5], path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), process.out.bt2out, - process.out.findAll { key, val -> key.startsWith('versions') } + process.out.versions ).match() } ) @@ -77,7 +77,7 @@ nextflow_process { path(process.out.profile[0][1]).readLines()[2..5], path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), process.out.bt2out, - process.out.findAll { key, val -> key.startsWith('versions') } + process.out.versions ).match() } ) @@ -106,7 +106,7 @@ nextflow_process { path(process.out.profile[0][1]).readLines()[2..5], path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), process.out.bt2out, - process.out.findAll { key, val -> key.startsWith('versions') } + process.out.versions ).match() } ) } @@ -136,7 +136,7 @@ nextflow_process { path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), process.out.bt2out, sam(process.out.sam.get(0).get(1)).getFileType(), - process.out.findAll { key, val -> key.startsWith('versions') } + process.out.versions ).match() } ) @@ -164,7 +164,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(sanitizeOutput(process.out)).match() } + { assert snapshot( process.out ).match() } ) } } diff --git a/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap index 26f8d05..a5b0f9a 100644 --- a/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap +++ b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap @@ -2,6 +2,39 @@ "sarscov2 - illumina pair end [fastq] - stub": { "content": [ { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test_profile.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.biom:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bowtie2out.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + + ], + "4": [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ], "biom": [ [ { @@ -32,19 +65,15 @@ "sam": [ ], - "versions_metaphlan": [ - [ - "METAPHLAN_METAPHLAN", - "metaphlan", - "4.1.1" - ] + "versions": [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" ] } ], - "timestamp": "2026-06-09T17:19:58.375514149", + "timestamp": "2026-02-16T10:17:01.145927415", "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.0" + "nf-test": "0.9.4", + "nextflow": "25.10.4" } }, "sarscov2 - illumina pair end [fastq] - save sam": { @@ -66,20 +95,14 @@ ] ], "SAM", - { - "versions_metaphlan": [ - [ - "METAPHLAN_METAPHLAN", - "metaphlan", - "4.1.1" - ] - ] - } + [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ] ], - "timestamp": "2026-06-09T17:19:47.219030947", + "timestamp": "2025-08-22T07:33:29.981757425", "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.0" + "nf-test": "0.9.2", + "nextflow": "25.04.6" } }, "sarscov2 - illumina single end [fastq]": { @@ -100,20 +123,14 @@ "test.bowtie2out.txt:md5,ef46a9c6a8ce9cae26fbfd5527116fd5" ] ], - { - "versions_metaphlan": [ - [ - "METAPHLAN_METAPHLAN", - "metaphlan", - "4.1.1" - ] - ] - } + [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ] ], - "timestamp": "2026-06-09T17:19:05.401336447", + "timestamp": "2024-08-27T10:33:32.269571148", "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.0" + "nf-test": "0.9.0", + "nextflow": "24.04.4" } }, "sarscov2 - illumina single end [fasta]": { @@ -134,20 +151,14 @@ "test.bowtie2out.txt:md5,d99d05d6b011c647adf816f10fc6acbe" ] ], - { - "versions_metaphlan": [ - [ - "METAPHLAN_METAPHLAN", - "metaphlan", - "4.1.1" - ] - ] - } + [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ] ], - "timestamp": "2026-06-09T17:19:32.907241155", + "timestamp": "2024-08-27T10:34:10.262604527", "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.0" + "nf-test": "0.9.0", + "nextflow": "24.04.4" } }, "sarscov2 - illumina pair end [fastq]": { @@ -168,20 +179,14 @@ "test.bowtie2out.txt:md5,8c1bc21e1d8484b5551bf46331d61bd8" ] ], - { - "versions_metaphlan": [ - [ - "METAPHLAN_METAPHLAN", - "metaphlan", - "4.1.1" - ] - ] - } + [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ] ], - "timestamp": "2026-06-09T17:19:19.166830424", + "timestamp": "2024-08-27T10:33:51.829732777", "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.0" + "nf-test": "0.9.0", + "nextflow": "24.04.4" } } } \ No newline at end of file