From 67aaa31f5c6c39b318740cfb72e9c3423c782aad Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Mon, 18 May 2026 16:21:45 +0100 Subject: [PATCH 1/3] feat(ribotish/predict): add optional secondary reference GTF for -a Carried in nf-core/riboseq#174 and split out of the bundled PR nf-core/modules#11684. **Breaking signature change.** The third input tuple gains an optional fourth element, `reference_gtf`, plumbed through to `ribotish predict` as `-a ` when populated: tuple val(meta3), path(fasta), path(gtf), path(reference_gtf, stageAs: 'secondary.gtf') Callers must supply a fourth element on every emit. Pass `[]` for the no-op case (no secondary annotation). The existing test cases in this PR are migrated that way; positive-coverage tests for the populated path will land in a follow-up. Why: Ribo-TISH's `-a` argument is the documented hook for layering a secondary annotation (e.g. MANE/RefSeq) on top of the primary GTF, and we want to expose it from the module without a second optional input tuple. Source: nf-core/riboseq#174 Co-Authored-By: Claude Opus 4.7 (1M context) --- modules/nf-core/ribotish/predict/main.nf | 4 +++- modules/nf-core/ribotish/predict/meta.yml | 7 +++++++ modules/nf-core/ribotish/predict/tests/main.nf.test | 12 ++++++++---- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/modules/nf-core/ribotish/predict/main.nf b/modules/nf-core/ribotish/predict/main.nf index eafe4568b71a..ca6b2ccef6fd 100644 --- a/modules/nf-core/ribotish/predict/main.nf +++ b/modules/nf-core/ribotish/predict/main.nf @@ -10,7 +10,7 @@ process RIBOTISH_PREDICT { input: tuple val(meta), path(bam_ribo), path(bai_ribo) tuple val(meta2), path(bam_ti), path(bai_ti) - tuple val(meta3), path(fasta), path(gtf) + tuple val(meta3), path(fasta), path(gtf), path(reference_gtf, stageAs: 'secondary.gtf') tuple val(meta4), path(candidate_orfs) tuple val(meta5), path(para_ribo) tuple val(meta6), path(para_ti) @@ -27,6 +27,7 @@ process RIBOTISH_PREDICT { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" + def reference_gtf_arg = reference_gtf ? "-a ${reference_gtf}" : '' ribo_bam_cmd = '' ti_bam_cmd = '' @@ -48,6 +49,7 @@ process RIBOTISH_PREDICT { $ti_bam_cmd \\ -f $fasta \\ -g $gtf \\ + $reference_gtf_arg \\ -o ${prefix}_pred.txt \\ --allresult ${prefix}_all.txt \\ --transprofile ${prefix}_transprofile.py \\ diff --git a/modules/nf-core/ribotish/predict/meta.yml b/modules/nf-core/ribotish/predict/meta.yml index a0cb0b93aeb4..98957a9b141e 100644 --- a/modules/nf-core/ribotish/predict/meta.yml +++ b/modules/nf-core/ribotish/predict/meta.yml @@ -64,6 +64,13 @@ input: GTF-format annotation file for reference sequences used in the bam file pattern: "*.gtf" ontologies: [] + - reference_gtf: + type: file + description: | + Optional secondary GTF annotation passed to ribotish as `-a` (e.g. a + MANE/RefSeq overlay). Pass `[]` to omit. + pattern: "*.gtf" + ontologies: [] - - meta4: type: map description: | diff --git a/modules/nf-core/ribotish/predict/tests/main.nf.test b/modules/nf-core/ribotish/predict/tests/main.nf.test index e20e29820735..3b0c96707e39 100644 --- a/modules/nf-core/ribotish/predict/tests/main.nf.test +++ b/modules/nf-core/ribotish/predict/tests/main.nf.test @@ -38,7 +38,8 @@ nextflow_process { input[2] = GUNZIP.out.gunzip.map{[ [id:'homo_sapiens_chr20'], it[1], - file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true) + file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true), + [] ]} input[3] = Channel.of([[],[]]) input[4] = Channel.of([[],[]]) @@ -74,7 +75,8 @@ nextflow_process { input[2] = GUNZIP.out.gunzip.map{[ [id:'homo_sapiens_chr20'], it[1], - file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true) + file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true), + [] ]} input[3] = Channel.of([[],[]]) input[4] = Channel.of([[],[]]) @@ -114,7 +116,8 @@ nextflow_process { input[2] = GUNZIP.out.gunzip.map{[ [id:'homo_sapiens_chr20'], it[1], - file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true) + file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true), + [] ]} input[3] = Channel.of([[],[]]) input[4] = Channel.of([[],[]]) @@ -156,7 +159,8 @@ nextflow_process { input[2] = GUNZIP.out.gunzip.map{[ [id:'homo_sapiens_chr20'], it[1], - file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true) + file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true), + [] ]} input[3] = Channel.of([[],[]]) input[4] = Channel.of([[],[]]) From e0f80b652d132acacd00e1b6f5b1d37c546f1014 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Mon, 18 May 2026 17:48:39 +0100 Subject: [PATCH 2/3] refactor(ribotish/predict): optional reference_gtf in its own tuple + topics versions + bump 0.2.8 Three coupled cleanups in response to the lint feedback on PR #11686: 1. Move the new `reference_gtf` input out of the existing fasta/gtf tuple and into its own optional input tuple (meta7) - the convention this module already uses for `bam_ti`, `candidate_orfs`, `para_ribo`, and `para_ti`. The existing `(meta3, fasta, gtf)` signature is preserved, so callers no longer need to grow that tuple; they wire a separate `Channel.of([[], []])` (or a populated channel) into the new slot. 2. Migrate version reporting from the legacy `versions.yml` heredoc to the new topic-based emission (`tuple val("${task.process}"), val('ribotish'), eval('...'), topic: versions, emit: versions_ribotish`). The `versions.yml` heredoc is removed from both `script:` and `stub:`. `meta.yml` regenerated by `nf-core modules lint --fix` to add the `topics:` block and reshape the `versions_ribotish` output entry. 3. Bump ribotish from 0.2.7 to 0.2.8 (bioconda; build hash unchanged). Test snapshot regenerated under `--update`: versions snapshot key renamed from `versions_*` to `versions_ribotish_*`, version string updated to `0.2.8`. Prediction-table assertions unchanged - 0.2.8 is a patch release. Source: nf-core/riboseq#174 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../nf-core/ribotish/predict/environment.yml | 2 +- modules/nf-core/ribotish/predict/main.nf | 19 +-- modules/nf-core/ribotish/predict/meta.yml | 57 ++++--- .../ribotish/predict/tests/main.nf.test | 24 +-- .../ribotish/predict/tests/main.nf.test.snap | 148 ++++++++++-------- 5 files changed, 138 insertions(+), 112 deletions(-) diff --git a/modules/nf-core/ribotish/predict/environment.yml b/modules/nf-core/ribotish/predict/environment.yml index 65bb256c5398..b026ccaaf1ef 100644 --- a/modules/nf-core/ribotish/predict/environment.yml +++ b/modules/nf-core/ribotish/predict/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::ribotish=0.2.7 + - bioconda::ribotish=0.2.8 diff --git a/modules/nf-core/ribotish/predict/main.nf b/modules/nf-core/ribotish/predict/main.nf index ca6b2ccef6fd..962de407a19e 100644 --- a/modules/nf-core/ribotish/predict/main.nf +++ b/modules/nf-core/ribotish/predict/main.nf @@ -4,22 +4,23 @@ process RIBOTISH_PREDICT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/ribotish:0.2.7--pyhdfd78af_0': - 'quay.io/biocontainers/ribotish:0.2.7--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/ribotish:0.2.8--pyhdfd78af_0': + 'quay.io/biocontainers/ribotish:0.2.8--pyhdfd78af_0' }" input: tuple val(meta), path(bam_ribo), path(bai_ribo) tuple val(meta2), path(bam_ti), path(bai_ti) - tuple val(meta3), path(fasta), path(gtf), path(reference_gtf, stageAs: 'secondary.gtf') + tuple val(meta3), path(fasta), path(gtf) tuple val(meta4), path(candidate_orfs) tuple val(meta5), path(para_ribo) tuple val(meta6), path(para_ti) + tuple val(meta7), path(reference_gtf, stageAs: 'secondary.gtf') output: tuple val(meta), path("*_pred.txt") , emit: predictions tuple val(meta), path("*_all.txt") , emit: all tuple val(meta), path("*_transprofile.py") , emit: transprofile - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('ribotish'), eval("ribotish --version | sed 's/ribotish //'"), topic: versions, emit: versions_ribotish when: task.ext.when == null || task.ext.when @@ -55,11 +56,6 @@ process RIBOTISH_PREDICT { --transprofile ${prefix}_transprofile.py \\ -p $task.cpus \\ $args - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - ribotish: \$(ribotish --version | sed 's/ribotish //') - END_VERSIONS """ stub: @@ -68,10 +64,5 @@ process RIBOTISH_PREDICT { touch ${prefix}_pred.txt touch ${prefix}_all.txt touch ${prefix}_transprofile.py - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - ribotish: \$(ribotish --version | sed 's/ribotish //') - END_VERSIONS """ } diff --git a/modules/nf-core/ribotish/predict/meta.yml b/modules/nf-core/ribotish/predict/meta.yml index 98957a9b141e..97fecde0ac65 100644 --- a/modules/nf-core/ribotish/predict/meta.yml +++ b/modules/nf-core/ribotish/predict/meta.yml @@ -1,4 +1,3 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json name: "ribotish_predict" description: Quality control of riboseq bam data keywords: @@ -13,9 +12,9 @@ tools: documentation: "https://github.com/zhpn1024/ribotish" tool_dev_url: "https://github.com/zhpn1024/ribotish" doi: "10.1038/s41467-017-01981-8" - licence: ["GPL v3"] + licence: + - "GPL v3" identifier: "" - input: - - meta: type: map @@ -64,13 +63,6 @@ input: GTF-format annotation file for reference sequences used in the bam file pattern: "*.gtf" ontologies: [] - - reference_gtf: - type: file - description: | - Optional secondary GTF annotation passed to ribotish as `-a` (e.g. a - MANE/RefSeq overlay). Pass `[]` to omit. - pattern: "*.gtf" - ontologies: [] - - meta4: type: map description: | @@ -92,7 +84,7 @@ input: Input P-site offset parameter files for riboseq bam files pattern: "*.py" ontologies: - - edam: http://edamontology.org/format_3996 # Python script + - edam: http://edamontology.org/format_3996 - - meta6: type: map description: | @@ -104,7 +96,20 @@ input: Input P-site offset parameter files for TI-seq bam files pattern: "*.py" ontologies: - - edam: http://edamontology.org/format_3996 # Python script + - edam: http://edamontology.org/format_3996 + - - meta7: + type: map + description: | + Groovy Map containing reference information for the secondary + annotation file + - reference_gtf: + type: file + description: | + Optional secondary GTF annotation passed to ribotish as + `-a ` (e.g. a MANE/RefSeq overlay applied on + top of the primary GTF). Pass `[]` to omit. + pattern: "*.gtf" + ontologies: [] output: predictions: - - meta: @@ -144,14 +149,28 @@ output: positions on transcript. pattern: "*.{py}" ontologies: - - edam: http://edamontology.org/format_3996 # Python script + - edam: http://edamontology.org/format_3996 + versions_ribotish: + - - ${task.process}: + type: string + description: The name of the process + - ribotish: + type: string + description: The name of the tool + - ribotish --version | sed 's/ribotish //': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - ribotish: + type: string + description: The name of the tool + - ribotish --version | sed 's/ribotish //': + type: eval + description: The expression to obtain the version of the tool authors: - "@pinin4fjords" maintainers: diff --git a/modules/nf-core/ribotish/predict/tests/main.nf.test b/modules/nf-core/ribotish/predict/tests/main.nf.test index 3b0c96707e39..51d471e7aa6c 100644 --- a/modules/nf-core/ribotish/predict/tests/main.nf.test +++ b/modules/nf-core/ribotish/predict/tests/main.nf.test @@ -38,12 +38,12 @@ nextflow_process { input[2] = GUNZIP.out.gunzip.map{[ [id:'homo_sapiens_chr20'], it[1], - file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true), - [] + file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true) ]} input[3] = Channel.of([[],[]]) input[4] = Channel.of([[],[]]) input[5] = Channel.of([[],[]]) + input[6] = Channel.of([[],[]]) """ } } @@ -54,7 +54,7 @@ nextflow_process { { assert path(process.out.predictions[0][1]).getText().contains("ENSG00000132640\tENST00000254977\tBTBD3\tprotein_coding\t20:11890767-11923666:+\tATG\t45\t1743\tExtended\t0\t0\tNone\t0.013377070461772932\tT\tNone\tNone\t0.02118962148347") }, { assert path(process.out.all[0][1]).getText().contains("ENSG00000132640\tENST00000254977\tBTBD3\tprotein_coding\t20:11890767-11923666:+\tATG\t45\t1743\tExtended\t0\t0\tNone\t0.013377070461772932\tT\tNone\tNone\t0.02118962148347") }, { assert snapshot(process.out.transprofile).match("transprofile_single_end_single_ribo_bam") }, - { assert snapshot(process.out.versions).match("versions_single_end_single_ribo_bam") } + { assert snapshot(process.out.versions_ribotish).match("versions_ribotish_single_end_single_ribo_bam") } ) } } @@ -75,12 +75,12 @@ nextflow_process { input[2] = GUNZIP.out.gunzip.map{[ [id:'homo_sapiens_chr20'], it[1], - file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true), - [] + file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true) ]} input[3] = Channel.of([[],[]]) input[4] = Channel.of([[],[]]) input[5] = Channel.of([[],[]]) + input[6] = Channel.of([[],[]]) """ } } @@ -91,7 +91,7 @@ nextflow_process { { assert snapshot(process.out.predictions).match("predictions_single_end_single_ribo_bam_stub") }, { assert snapshot(process.out.all).match("all_single_end_single_ribo_bam_stub") }, { assert snapshot(process.out.transprofile).match("transprofile_single_end_single_ribo_bam_stub") }, - { assert snapshot(process.out.versions).match("versions_single_end_single_ribo_bam_stub") } + { assert snapshot(process.out.versions_ribotish).match("versions_ribotish_single_end_single_ribo_bam_stub") } ) } } @@ -116,12 +116,12 @@ nextflow_process { input[2] = GUNZIP.out.gunzip.map{[ [id:'homo_sapiens_chr20'], it[1], - file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true), - [] + file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true) ]} input[3] = Channel.of([[],[]]) input[4] = Channel.of([[],[]]) input[5] = Channel.of([[],[]]) + input[6] = Channel.of([[],[]]) """ } } @@ -132,7 +132,7 @@ nextflow_process { { assert path(process.out.predictions[0][1]).getText().contains("ENSG00000284776\tENST00000618693\t\tprotein_coding\t20:18567478-18744216:+\tATG\t26\t695\tAnnotated\t0\t0\tNone\t0.0006123183014212") }, { assert path(process.out.all[0][1]).getText().contains("ENSG00000284776\tENST00000618693\t\tprotein_coding\t20:18567478-18744216:+\tATG\t26\t695\tAnnotated\t0\t0\tNone\t0.0006123183014212") }, { assert snapshot(process.out.transprofile).match("transprofile_single_end_multi_ribo_bam") }, - { assert snapshot(process.out.versions).match("versions_single_end_multi_ribo_bam") } + { assert snapshot(process.out.versions_ribotish).match("versions_ribotish_single_end_multi_ribo_bam") } ) } } @@ -159,12 +159,12 @@ nextflow_process { input[2] = GUNZIP.out.gunzip.map{[ [id:'homo_sapiens_chr20'], it[1], - file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true), - [] + file(params.modules_testdata_base_path + "genomics/homo_sapiens/riboseq_expression/Homo_sapiens.GRCh38.111_chr20.gtf", checkIfExists: true) ]} input[3] = Channel.of([[],[]]) input[4] = Channel.of([[],[]]) input[5] = Channel.of([[],[]]) + input[6] = Channel.of([[],[]]) """ } } @@ -175,7 +175,7 @@ nextflow_process { { assert snapshot(process.out.predictions).match("predictions_single_end_multi_ribo_bam_stub") }, { assert snapshot(process.out.all).match("all_single_end_multi_ribo_bam_stub") }, { assert snapshot(process.out.transprofile).match("transprofile_single_end_multi_ribo_bam_stub") }, - { assert snapshot(process.out.versions).match("versions_single_end_multi_ribo_bam_stub") } + { assert snapshot(process.out.versions_ribotish).match("versions_ribotish_single_end_multi_ribo_bam_stub") } ) } } diff --git a/modules/nf-core/ribotish/predict/tests/main.nf.test.snap b/modules/nf-core/ribotish/predict/tests/main.nf.test.snap index 7716ecd2526f..ffa760f11702 100644 --- a/modules/nf-core/ribotish/predict/tests/main.nf.test.snap +++ b/modules/nf-core/ribotish/predict/tests/main.nf.test.snap @@ -1,16 +1,4 @@ { - "versions_single_end_multi_ribo_bam_stub": { - "content": [ - [ - "versions.yml:md5,48e727a11954fb4c3de5a0eb2576951c" - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-03-04T11:28:24.897805" - }, "transprofile_single_end_single_ribo_bam_stub": { "content": [ [ @@ -24,32 +12,29 @@ ] ] ], + "timestamp": "2024-03-04T11:27:04.019058", "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" - }, - "timestamp": "2024-03-04T11:27:04.019058" + } }, - "transprofile_single_end_multi_ribo_bam_stub": { + "versions_ribotish_single_end_multi_ribo_bam": { "content": [ [ [ - { - "id": "test", - "single_end": true, - "strandedness": "forward" - }, - "test_transprofile.py:md5,d41d8cd98f00b204e9800998ecf8427e" + "RIBOTISH_PREDICT", + "ribotish", + "0.2.8" ] ] ], + "timestamp": "2026-05-18T16:42:56.345570295", "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-03-04T11:28:24.874123" + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } }, - "all_single_end_single_ribo_bam_stub": { + "all_single_end_multi_ribo_bam_stub": { "content": [ [ [ @@ -62,37 +47,51 @@ ] ] ], + "timestamp": "2024-03-04T11:28:24.849804", "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" - }, - "timestamp": "2024-03-04T11:27:04.007006" + } }, - "versions_single_end_single_ribo_bam_stub": { + "transprofile_single_end_multi_ribo_bam": { "content": [ [ - "versions.yml:md5,48e727a11954fb4c3de5a0eb2576951c" + [ + { + "id": "test", + "single_end": true, + "strandedness": "forward" + }, + "test_transprofile.py:md5,202a5b5983806e8d9f242c6157736357" + ] ] ], + "timestamp": "2024-03-14T12:26:32.447969", "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" - }, - "timestamp": "2024-03-04T11:27:04.031448" + } }, - "versions_single_end_multi_ribo_bam": { + "predictions_single_end_multi_ribo_bam_stub": { "content": [ [ - "versions.yml:md5,48e727a11954fb4c3de5a0eb2576951c" + [ + { + "id": "test", + "single_end": true, + "strandedness": "forward" + }, + "test_pred.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], + "timestamp": "2024-03-04T11:28:24.825927", "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" - }, - "timestamp": "2024-03-04T09:47:34.863391" + } }, - "transprofile_single_end_single_ribo_bam": { + "transprofile_single_end_multi_ribo_bam_stub": { "content": [ [ [ @@ -101,17 +100,17 @@ "single_end": true, "strandedness": "forward" }, - "test_transprofile.py:md5,3e6aaa9ec9f3346ae8c838da2d415924" + "test_transprofile.py:md5,d41d8cd98f00b204e9800998ecf8427e" ] ] ], + "timestamp": "2024-03-04T11:28:24.874123", "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" - }, - "timestamp": "2024-03-14T12:20:15.166081" + } }, - "all_single_end_multi_ribo_bam_stub": { + "all_single_end_single_ribo_bam_stub": { "content": [ [ [ @@ -124,25 +123,29 @@ ] ] ], + "timestamp": "2024-03-04T11:27:04.007006", "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" - }, - "timestamp": "2024-03-04T11:28:24.849804" + } }, - "versions_single_end_single_ribo_bam": { + "versions_ribotish_single_end_multi_ribo_bam_stub": { "content": [ [ - "versions.yml:md5,48e727a11954fb4c3de5a0eb2576951c" + [ + "RIBOTISH_PREDICT", + "ribotish", + "0.2.8" + ] ] ], + "timestamp": "2026-05-18T16:43:04.293934651", "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-03-04T09:46:34.409406" + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } }, - "transprofile_single_end_multi_ribo_bam": { + "transprofile_single_end_single_ribo_bam": { "content": [ [ [ @@ -151,34 +154,47 @@ "single_end": true, "strandedness": "forward" }, - "test_transprofile.py:md5,202a5b5983806e8d9f242c6157736357" + "test_transprofile.py:md5,3e6aaa9ec9f3346ae8c838da2d415924" ] ] ], + "timestamp": "2024-03-14T12:20:15.166081", "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" - }, - "timestamp": "2024-03-14T12:26:32.447969" + } }, - "predictions_single_end_multi_ribo_bam_stub": { + "versions_ribotish_single_end_single_ribo_bam": { "content": [ [ [ - { - "id": "test", - "single_end": true, - "strandedness": "forward" - }, - "test_pred.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + "RIBOTISH_PREDICT", + "ribotish", + "0.2.8" ] ] ], + "timestamp": "2026-05-18T16:42:09.742242601", "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-03-04T11:28:24.825927" + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "versions_ribotish_single_end_single_ribo_bam_stub": { + "content": [ + [ + [ + "RIBOTISH_PREDICT", + "ribotish", + "0.2.8" + ] + ] + ], + "timestamp": "2026-05-18T16:42:17.695252803", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } }, "predictions_single_end_single_ribo_bam_stub": { "content": [ @@ -193,10 +209,10 @@ ] ] ], + "timestamp": "2024-03-04T11:27:03.99362", "meta": { "nf-test": "0.8.4", "nextflow": "23.10.1" - }, - "timestamp": "2024-03-04T11:27:03.99362" + } } } \ No newline at end of file From 5516eb15430f290d59872255a19423620e841d89 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Tue, 19 May 2026 11:07:21 +0100 Subject: [PATCH 3/3] test(ribotish/predict): consolidate to one unnamed snapshot per test Per SPPearce's review comment on nf-core/modules#11686: each test should have a single anonymous snapshot() call rather than multiple named ones. Non-stub tests roll `transprofile` + the topic-versions findAll into one snapshot; the existing `predictions` / `all` contains() row checks are kept as separate assertions (they pin specific known-good output rows and aren't redundant with the snapshot). Stub tests roll `predictions` + `all` + `transprofile` + versions into one snapshot. Versions are referenced via the canonical `process.out.findAll { key, val -> key.startsWith('versions') }` pattern (653 modules in nf-core/modules use it vs 53 with explicit `process.out.versions_`). Snapshot keys are now the test names directly. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ribotish/predict/tests/main.nf.test | 32 +-- .../ribotish/predict/tests/main.nf.test.snap | 184 ++++++------------ 2 files changed, 80 insertions(+), 136 deletions(-) diff --git a/modules/nf-core/ribotish/predict/tests/main.nf.test b/modules/nf-core/ribotish/predict/tests/main.nf.test index 51d471e7aa6c..a2924ce02aa3 100644 --- a/modules/nf-core/ribotish/predict/tests/main.nf.test +++ b/modules/nf-core/ribotish/predict/tests/main.nf.test @@ -53,8 +53,10 @@ nextflow_process { { assert process.success }, { assert path(process.out.predictions[0][1]).getText().contains("ENSG00000132640\tENST00000254977\tBTBD3\tprotein_coding\t20:11890767-11923666:+\tATG\t45\t1743\tExtended\t0\t0\tNone\t0.013377070461772932\tT\tNone\tNone\t0.02118962148347") }, { assert path(process.out.all[0][1]).getText().contains("ENSG00000132640\tENST00000254977\tBTBD3\tprotein_coding\t20:11890767-11923666:+\tATG\t45\t1743\tExtended\t0\t0\tNone\t0.013377070461772932\tT\tNone\tNone\t0.02118962148347") }, - { assert snapshot(process.out.transprofile).match("transprofile_single_end_single_ribo_bam") }, - { assert snapshot(process.out.versions_ribotish).match("versions_ribotish_single_end_single_ribo_bam") } + { assert snapshot( + process.out.transprofile, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } } @@ -88,10 +90,12 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.predictions).match("predictions_single_end_single_ribo_bam_stub") }, - { assert snapshot(process.out.all).match("all_single_end_single_ribo_bam_stub") }, - { assert snapshot(process.out.transprofile).match("transprofile_single_end_single_ribo_bam_stub") }, - { assert snapshot(process.out.versions_ribotish).match("versions_ribotish_single_end_single_ribo_bam_stub") } + { assert snapshot( + process.out.predictions, + process.out.all, + process.out.transprofile, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } } @@ -131,8 +135,10 @@ nextflow_process { { assert process.success }, { assert path(process.out.predictions[0][1]).getText().contains("ENSG00000284776\tENST00000618693\t\tprotein_coding\t20:18567478-18744216:+\tATG\t26\t695\tAnnotated\t0\t0\tNone\t0.0006123183014212") }, { assert path(process.out.all[0][1]).getText().contains("ENSG00000284776\tENST00000618693\t\tprotein_coding\t20:18567478-18744216:+\tATG\t26\t695\tAnnotated\t0\t0\tNone\t0.0006123183014212") }, - { assert snapshot(process.out.transprofile).match("transprofile_single_end_multi_ribo_bam") }, - { assert snapshot(process.out.versions_ribotish).match("versions_ribotish_single_end_multi_ribo_bam") } + { assert snapshot( + process.out.transprofile, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } } @@ -172,10 +178,12 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.predictions).match("predictions_single_end_multi_ribo_bam_stub") }, - { assert snapshot(process.out.all).match("all_single_end_multi_ribo_bam_stub") }, - { assert snapshot(process.out.transprofile).match("transprofile_single_end_multi_ribo_bam_stub") }, - { assert snapshot(process.out.versions_ribotish).match("versions_ribotish_single_end_multi_ribo_bam_stub") } + { assert snapshot( + process.out.predictions, + process.out.all, + process.out.transprofile, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } } diff --git a/modules/nf-core/ribotish/predict/tests/main.nf.test.snap b/modules/nf-core/ribotish/predict/tests/main.nf.test.snap index ffa760f11702..30d6c5e21793 100644 --- a/modules/nf-core/ribotish/predict/tests/main.nf.test.snap +++ b/modules/nf-core/ribotish/predict/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "transprofile_single_end_single_ribo_bam_stub": { + "sarscov2 [bam] - single_end - single ribo bam - stub": { "content": [ [ [ @@ -8,34 +8,9 @@ "single_end": true, "strandedness": "forward" }, - "test_transprofile.py:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - ], - "timestamp": "2024-03-04T11:27:04.019058", - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - } - }, - "versions_ribotish_single_end_multi_ribo_bam": { - "content": [ - [ - [ - "RIBOTISH_PREDICT", - "ribotish", - "0.2.8" + "test_pred.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] - ] - ], - "timestamp": "2026-05-18T16:42:56.345570295", - "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.1" - } - }, - "all_single_end_multi_ribo_bam_stub": { - "content": [ + ], [ [ { @@ -45,16 +20,7 @@ }, "test_all.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] - ] - ], - "timestamp": "2024-03-04T11:28:24.849804", - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - } - }, - "transprofile_single_end_multi_ribo_bam": { - "content": [ + ], [ [ { @@ -62,17 +28,26 @@ "single_end": true, "strandedness": "forward" }, - "test_transprofile.py:md5,202a5b5983806e8d9f242c6157736357" + "test_transprofile.py:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + { + "versions_ribotish": [ + [ + "RIBOTISH_PREDICT", + "ribotish", + "0.2.8" + ] ] - ] + } ], - "timestamp": "2024-03-14T12:26:32.447969", + "timestamp": "2026-05-19T10:03:51.7008198", "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.5", + "nextflow": "26.04.1" } }, - "predictions_single_end_multi_ribo_bam_stub": { + "sarscov2 [bam] - single_end - multi ribo bam - stub": { "content": [ [ [ @@ -83,16 +58,7 @@ }, "test_pred.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] - ] - ], - "timestamp": "2024-03-04T11:28:24.825927", - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - } - }, - "transprofile_single_end_multi_ribo_bam_stub": { - "content": [ + ], [ [ { @@ -100,18 +66,9 @@ "single_end": true, "strandedness": "forward" }, - "test_transprofile.py:md5,d41d8cd98f00b204e9800998ecf8427e" + "test_all.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] - ] - ], - "timestamp": "2024-03-04T11:28:24.874123", - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - } - }, - "all_single_end_single_ribo_bam_stub": { - "content": [ + ], [ [ { @@ -119,33 +76,26 @@ "single_end": true, "strandedness": "forward" }, - "test_all.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + "test_transprofile.py:md5,d41d8cd98f00b204e9800998ecf8427e" ] - ] - ], - "timestamp": "2024-03-04T11:27:04.007006", - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - } - }, - "versions_ribotish_single_end_multi_ribo_bam_stub": { - "content": [ - [ - [ - "RIBOTISH_PREDICT", - "ribotish", - "0.2.8" + ], + { + "versions_ribotish": [ + [ + "RIBOTISH_PREDICT", + "ribotish", + "0.2.8" + ] ] - ] + } ], - "timestamp": "2026-05-18T16:43:04.293934651", + "timestamp": "2026-05-19T10:04:37.952263709", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" } }, - "transprofile_single_end_single_ribo_bam": { + "sarscov2 [bam] - single_end - multi ribo bam": { "content": [ [ [ @@ -154,49 +104,26 @@ "single_end": true, "strandedness": "forward" }, - "test_transprofile.py:md5,3e6aaa9ec9f3346ae8c838da2d415924" - ] - ] - ], - "timestamp": "2024-03-14T12:20:15.166081", - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - } - }, - "versions_ribotish_single_end_single_ribo_bam": { - "content": [ - [ - [ - "RIBOTISH_PREDICT", - "ribotish", - "0.2.8" + "test_transprofile.py:md5,202a5b5983806e8d9f242c6157736357" ] - ] - ], - "timestamp": "2026-05-18T16:42:09.742242601", - "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.1" - } - }, - "versions_ribotish_single_end_single_ribo_bam_stub": { - "content": [ - [ - [ - "RIBOTISH_PREDICT", - "ribotish", - "0.2.8" + ], + { + "versions_ribotish": [ + [ + "RIBOTISH_PREDICT", + "ribotish", + "0.2.8" + ] ] - ] + } ], - "timestamp": "2026-05-18T16:42:17.695252803", + "timestamp": "2026-05-19T10:04:30.097163994", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" } }, - "predictions_single_end_single_ribo_bam_stub": { + "sarscov2 [bam] - single_end - single ribo bam": { "content": [ [ [ @@ -205,14 +132,23 @@ "single_end": true, "strandedness": "forward" }, - "test_pred.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + "test_transprofile.py:md5,3e6aaa9ec9f3346ae8c838da2d415924" + ] + ], + { + "versions_ribotish": [ + [ + "RIBOTISH_PREDICT", + "ribotish", + "0.2.8" + ] ] - ] + } ], - "timestamp": "2024-03-04T11:27:03.99362", + "timestamp": "2026-05-19T10:03:43.377664597", "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.5", + "nextflow": "26.04.1" } } } \ No newline at end of file