From 7ebe536d0ff1161ab3966cee0cf3393462bc6073 Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Fri, 6 Mar 2026 10:09:32 +0100 Subject: [PATCH 01/14] add saltshaker classify module and tests --- .../saltshaker/classify/environment.yml | 6 + modules/nf-core/saltshaker/classify/main.nf | 56 +++++++ modules/nf-core/saltshaker/classify/meta.yml | 100 ++++++++++++ .../saltshaker/classify/tests/main.nf.test | 104 ++++++++++++ .../classify/tests/main.nf.test.snap | 148 ++++++++++++++++++ .../saltshaker/classify/tests/nextflow.config | 5 + 6 files changed, 419 insertions(+) create mode 100644 modules/nf-core/saltshaker/classify/environment.yml create mode 100644 modules/nf-core/saltshaker/classify/main.nf create mode 100644 modules/nf-core/saltshaker/classify/meta.yml create mode 100644 modules/nf-core/saltshaker/classify/tests/main.nf.test create mode 100644 modules/nf-core/saltshaker/classify/tests/main.nf.test.snap create mode 100644 modules/nf-core/saltshaker/classify/tests/nextflow.config diff --git a/modules/nf-core/saltshaker/classify/environment.yml b/modules/nf-core/saltshaker/classify/environment.yml new file mode 100644 index 000000000000..4e7a14a64c86 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/environment.yml @@ -0,0 +1,6 @@ +channels: + - conda-forge + - bioconda +dependencies: + - pip: + - saltshaker==1.0.0 diff --git a/modules/nf-core/saltshaker/classify/main.nf b/modules/nf-core/saltshaker/classify/main.nf new file mode 100644 index 000000000000..576d97b6272f --- /dev/null +++ b/modules/nf-core/saltshaker/classify/main.nf @@ -0,0 +1,56 @@ +process SALTSHAKER_CLASSIFY { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/e9/e93d703b195dd27cd920cee46669d3f51043216c12fd05168c937e93adf170e8/data': + 'community.wave.seqera.io/library/pip_saltshaker:e08e38a6d45f8f32' }" + + input: + tuple val(meta), path(call) + val dom_frac + val group_radius + val high_het + val mult_thresh + val noise_thresh + + output: + tuple val(meta), path("*_classify_metadata.tsv"), emit: classify + tuple val(meta), path("*_classify.txt") , emit: txt + tuple val(meta), path("*saltshaker.vcf") , emit: vcf + tuple val("${task.process}"), val('saltshaker'), val("1.0.0"), topic: versions, emit: versions_saltshaker + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + saltshaker classify \\ + --prefix $prefix \\ + --input-dir . \\ + --vcf \\ + --dominant-fraction $dom_frac \\ + --radius $group_radius \\ + --high-het $high_het \\ + --multiple-threshold $mult_thresh \\ + --noise $noise_thresh \\ + $args + + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + echo $args + + touch ${prefix}.saltshaker.vcf + touch ${prefix}.saltshaker_classify.txt + touch ${prefix}.saltshaker_classify_metadata.tsv + """ +} diff --git a/modules/nf-core/saltshaker/classify/meta.yml b/modules/nf-core/saltshaker/classify/meta.yml new file mode 100644 index 000000000000..b1ebbac60783 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/meta.yml @@ -0,0 +1,100 @@ +name: "saltshaker_classify" +description: mtDNA deletion and duplication classification downstream of mitosalt +keywords: + - saltshaker + - mitosalt + - mtDNA + - structural-variant calling +tools: + - "saltshaker": + description: "A Python package for classifying and visualizing mitochondrial structural variants from MitoSAlt pipeline output." + homepage: "https://github.com/aksenia/saltshaker" + documentation: "https://github.com/aksenia/saltshaker/tree/main/saltshaker/docs" + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - call: + type: file + description: call metadata file from saltshaker_call + pattern: "*_call_metadata.tsv" + ontologies: [] + - dominant_fraction: + type: float + description: Minimum fraction required for a call to be considered dominant + - group_radius: + type: integer + description: Spatial clustering radius for saltshaker grouping + - high_heteroplasmy: + type: integer + description: High heteroplasmy threshold for saltshaker classification + - multiple_threshold: + type: integer + description: Heteroplasmy threshold for multiple classification in saltshaker + - noise_threshold: + type: float + description: Heteroplasmy threshold for noise in saltshaker classification + +output: + classify: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*_classify_metadata.tsv": + type: file + description: tsv with classified call metadata to be used in saltshaker_plot + pattern: "*_classify_metadata.tsv" + ontologies: [] + txt: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*_classify.txt": + type: file + description: txt file with case classification + pattern: "*_classify.txt" + ontologies: [] + vcf: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*_classify.vcf": + type: file + description: vcf file with variant calls + pattern: "*saltshaker.vcf" + ontologies: [] + versions_saltshaker: + - - "${task.process}": + type: string + description: The name of the process + - "saltshaker": + type: string + description: The name of the tool + - "1.0.0": + type: string + description: Hardcoded version of saltshaker used in the module + +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - saltshaker: + type: string + description: The name of the tool + - 1.0.0: + type: string + description: Hardcoded version of saltshaker used in the module +authors: + - "@ieduba" +maintainers: + - "@ieduba" diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test b/modules/nf-core/saltshaker/classify/tests/main.nf.test new file mode 100644 index 000000000000..6f5000c4304a --- /dev/null +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test @@ -0,0 +1,104 @@ +// TODO nf-core: Once you have added the required tests, please run the following command to build this file: +// nf-core modules test saltshaker/classify +nextflow_process { + + name "Test Process SALTSHAKER_CLASSIFY" + script "../main.nf" + process "SALTSHAKER_CLASSIFY" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "saltshaker" + tag "saltshaker/classify" + + // TODO nf-core: Change the test name preferably indicating the test-data and file-format used + + setup { + run("SALTSHAKER_CALL") { + script "../../call/main.nf" + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'delete_me/saltshaker/test_mitosalt.breakpoint', checkIfExists: true), + ] + + input[1] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'delete_me/saltshaker/test_mitosalt.cluster', checkIfExists: true), + ] + + input[2] = [ + [ id:'hg38' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/human_mt_rCRS.fasta', checkIfExists: true), + ] + + input[3] = 15 + input[4] = 0.01 + input[5] = 16569 + input[6] = 16081 + input[7] = 407 + input[8] = 5730 + input[9] = 5763 + """ + } + } + } + + test("classify - vcf") { + + when { + process { + """ + input[0] = SALTSHAKER_CALL.out.call + input[1] = 0.5 + input[2] = 600 + input[3] = 10 + input[4] = 5 + input[5] = 0.3 + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + ).match() } + + ) + } + + } + + test("classify - vcf - stub") { + + options "-stub" + + when { + process { + """ + input[0] = SALTSHAKER_CALL.out.call + input[1] = 0.5 + input[2] = 600 + input[3] = 10 + input[4] = 5 + input[5] = 0.3 + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + ).match() } + ) + } + + } + +} diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap new file mode 100644 index 000000000000..6acee0acbf51 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap @@ -0,0 +1,148 @@ +{ + "classify - vcf - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ], + "classify": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "txt": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "vcf": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_saltshaker": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ] + } + ], + "timestamp": "2026-03-05T16:08:21.537713", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.0" + } + }, + "classify - vcf": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,e0a91b9e11b71222cf0bc892eba25114" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,8e11ad30539d0b5e0ab9a42b4d68b208" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,c2ca8c445a41a311453afb9a787dd5fb" + ] + ], + "3": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ], + "classify": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,e0a91b9e11b71222cf0bc892eba25114" + ] + ], + "txt": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,8e11ad30539d0b5e0ab9a42b4d68b208" + ] + ], + "vcf": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,c2ca8c445a41a311453afb9a787dd5fb" + ] + ], + "versions_saltshaker": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ] + } + ], + "timestamp": "2026-03-05T16:08:13.862273", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.0" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/saltshaker/classify/tests/nextflow.config b/modules/nf-core/saltshaker/classify/tests/nextflow.config new file mode 100644 index 000000000000..6d4db8d027a2 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: 'SALTSHAKER_CLASSIFY' { + ext.args = '--blacklist' + } +} From 64385746207de03f58fedcd1b75e7db33ef9ae5f Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Mon, 9 Mar 2026 09:01:06 +0100 Subject: [PATCH 02/14] pin pip version --- modules/nf-core/saltshaker/classify/environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/nf-core/saltshaker/classify/environment.yml b/modules/nf-core/saltshaker/classify/environment.yml index 4e7a14a64c86..f76c4bf5a598 100644 --- a/modules/nf-core/saltshaker/classify/environment.yml +++ b/modules/nf-core/saltshaker/classify/environment.yml @@ -2,5 +2,6 @@ channels: - conda-forge - bioconda dependencies: + - pip==26.0.1 - pip: - saltshaker==1.0.0 From eff22aceee73d4b577150401f5bff4443fb891e6 Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Fri, 6 Mar 2026 10:09:32 +0100 Subject: [PATCH 03/14] add saltshaker classify module and tests --- .../saltshaker/classify/environment.yml | 6 + modules/nf-core/saltshaker/classify/main.nf | 56 +++++++ modules/nf-core/saltshaker/classify/meta.yml | 100 ++++++++++++ .../saltshaker/classify/tests/main.nf.test | 104 ++++++++++++ .../classify/tests/main.nf.test.snap | 148 ++++++++++++++++++ .../saltshaker/classify/tests/nextflow.config | 5 + 6 files changed, 419 insertions(+) create mode 100644 modules/nf-core/saltshaker/classify/environment.yml create mode 100644 modules/nf-core/saltshaker/classify/main.nf create mode 100644 modules/nf-core/saltshaker/classify/meta.yml create mode 100644 modules/nf-core/saltshaker/classify/tests/main.nf.test create mode 100644 modules/nf-core/saltshaker/classify/tests/main.nf.test.snap create mode 100644 modules/nf-core/saltshaker/classify/tests/nextflow.config diff --git a/modules/nf-core/saltshaker/classify/environment.yml b/modules/nf-core/saltshaker/classify/environment.yml new file mode 100644 index 000000000000..4e7a14a64c86 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/environment.yml @@ -0,0 +1,6 @@ +channels: + - conda-forge + - bioconda +dependencies: + - pip: + - saltshaker==1.0.0 diff --git a/modules/nf-core/saltshaker/classify/main.nf b/modules/nf-core/saltshaker/classify/main.nf new file mode 100644 index 000000000000..576d97b6272f --- /dev/null +++ b/modules/nf-core/saltshaker/classify/main.nf @@ -0,0 +1,56 @@ +process SALTSHAKER_CLASSIFY { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/e9/e93d703b195dd27cd920cee46669d3f51043216c12fd05168c937e93adf170e8/data': + 'community.wave.seqera.io/library/pip_saltshaker:e08e38a6d45f8f32' }" + + input: + tuple val(meta), path(call) + val dom_frac + val group_radius + val high_het + val mult_thresh + val noise_thresh + + output: + tuple val(meta), path("*_classify_metadata.tsv"), emit: classify + tuple val(meta), path("*_classify.txt") , emit: txt + tuple val(meta), path("*saltshaker.vcf") , emit: vcf + tuple val("${task.process}"), val('saltshaker'), val("1.0.0"), topic: versions, emit: versions_saltshaker + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + saltshaker classify \\ + --prefix $prefix \\ + --input-dir . \\ + --vcf \\ + --dominant-fraction $dom_frac \\ + --radius $group_radius \\ + --high-het $high_het \\ + --multiple-threshold $mult_thresh \\ + --noise $noise_thresh \\ + $args + + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + echo $args + + touch ${prefix}.saltshaker.vcf + touch ${prefix}.saltshaker_classify.txt + touch ${prefix}.saltshaker_classify_metadata.tsv + """ +} diff --git a/modules/nf-core/saltshaker/classify/meta.yml b/modules/nf-core/saltshaker/classify/meta.yml new file mode 100644 index 000000000000..b1ebbac60783 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/meta.yml @@ -0,0 +1,100 @@ +name: "saltshaker_classify" +description: mtDNA deletion and duplication classification downstream of mitosalt +keywords: + - saltshaker + - mitosalt + - mtDNA + - structural-variant calling +tools: + - "saltshaker": + description: "A Python package for classifying and visualizing mitochondrial structural variants from MitoSAlt pipeline output." + homepage: "https://github.com/aksenia/saltshaker" + documentation: "https://github.com/aksenia/saltshaker/tree/main/saltshaker/docs" + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - call: + type: file + description: call metadata file from saltshaker_call + pattern: "*_call_metadata.tsv" + ontologies: [] + - dominant_fraction: + type: float + description: Minimum fraction required for a call to be considered dominant + - group_radius: + type: integer + description: Spatial clustering radius for saltshaker grouping + - high_heteroplasmy: + type: integer + description: High heteroplasmy threshold for saltshaker classification + - multiple_threshold: + type: integer + description: Heteroplasmy threshold for multiple classification in saltshaker + - noise_threshold: + type: float + description: Heteroplasmy threshold for noise in saltshaker classification + +output: + classify: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*_classify_metadata.tsv": + type: file + description: tsv with classified call metadata to be used in saltshaker_plot + pattern: "*_classify_metadata.tsv" + ontologies: [] + txt: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*_classify.txt": + type: file + description: txt file with case classification + pattern: "*_classify.txt" + ontologies: [] + vcf: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*_classify.vcf": + type: file + description: vcf file with variant calls + pattern: "*saltshaker.vcf" + ontologies: [] + versions_saltshaker: + - - "${task.process}": + type: string + description: The name of the process + - "saltshaker": + type: string + description: The name of the tool + - "1.0.0": + type: string + description: Hardcoded version of saltshaker used in the module + +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - saltshaker: + type: string + description: The name of the tool + - 1.0.0: + type: string + description: Hardcoded version of saltshaker used in the module +authors: + - "@ieduba" +maintainers: + - "@ieduba" diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test b/modules/nf-core/saltshaker/classify/tests/main.nf.test new file mode 100644 index 000000000000..6f5000c4304a --- /dev/null +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test @@ -0,0 +1,104 @@ +// TODO nf-core: Once you have added the required tests, please run the following command to build this file: +// nf-core modules test saltshaker/classify +nextflow_process { + + name "Test Process SALTSHAKER_CLASSIFY" + script "../main.nf" + process "SALTSHAKER_CLASSIFY" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "saltshaker" + tag "saltshaker/classify" + + // TODO nf-core: Change the test name preferably indicating the test-data and file-format used + + setup { + run("SALTSHAKER_CALL") { + script "../../call/main.nf" + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'delete_me/saltshaker/test_mitosalt.breakpoint', checkIfExists: true), + ] + + input[1] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'delete_me/saltshaker/test_mitosalt.cluster', checkIfExists: true), + ] + + input[2] = [ + [ id:'hg38' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/human_mt_rCRS.fasta', checkIfExists: true), + ] + + input[3] = 15 + input[4] = 0.01 + input[5] = 16569 + input[6] = 16081 + input[7] = 407 + input[8] = 5730 + input[9] = 5763 + """ + } + } + } + + test("classify - vcf") { + + when { + process { + """ + input[0] = SALTSHAKER_CALL.out.call + input[1] = 0.5 + input[2] = 600 + input[3] = 10 + input[4] = 5 + input[5] = 0.3 + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + ).match() } + + ) + } + + } + + test("classify - vcf - stub") { + + options "-stub" + + when { + process { + """ + input[0] = SALTSHAKER_CALL.out.call + input[1] = 0.5 + input[2] = 600 + input[3] = 10 + input[4] = 5 + input[5] = 0.3 + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + ).match() } + ) + } + + } + +} diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap new file mode 100644 index 000000000000..6acee0acbf51 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap @@ -0,0 +1,148 @@ +{ + "classify - vcf - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ], + "classify": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "txt": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "vcf": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_saltshaker": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ] + } + ], + "timestamp": "2026-03-05T16:08:21.537713", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.0" + } + }, + "classify - vcf": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,e0a91b9e11b71222cf0bc892eba25114" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,8e11ad30539d0b5e0ab9a42b4d68b208" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,c2ca8c445a41a311453afb9a787dd5fb" + ] + ], + "3": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ], + "classify": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,e0a91b9e11b71222cf0bc892eba25114" + ] + ], + "txt": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,8e11ad30539d0b5e0ab9a42b4d68b208" + ] + ], + "vcf": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,c2ca8c445a41a311453afb9a787dd5fb" + ] + ], + "versions_saltshaker": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ] + } + ], + "timestamp": "2026-03-05T16:08:13.862273", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.0" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/saltshaker/classify/tests/nextflow.config b/modules/nf-core/saltshaker/classify/tests/nextflow.config new file mode 100644 index 000000000000..6d4db8d027a2 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: 'SALTSHAKER_CLASSIFY' { + ext.args = '--blacklist' + } +} From c6e9de7554862c98dbb5790cb5e7e74534e61bdf Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Mon, 9 Mar 2026 09:01:06 +0100 Subject: [PATCH 04/14] pin pip version --- modules/nf-core/saltshaker/classify/environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/nf-core/saltshaker/classify/environment.yml b/modules/nf-core/saltshaker/classify/environment.yml index 4e7a14a64c86..f76c4bf5a598 100644 --- a/modules/nf-core/saltshaker/classify/environment.yml +++ b/modules/nf-core/saltshaker/classify/environment.yml @@ -2,5 +2,6 @@ channels: - conda-forge - bioconda dependencies: + - pip==26.0.1 - pip: - saltshaker==1.0.0 From eb6312beb0eb5cb88517e3fab4905ec9ccd640c4 Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Mon, 16 Mar 2026 11:01:42 +0100 Subject: [PATCH 05/14] update test with nf-core saltshaker/call --- .../saltshaker/classify/tests/main.nf.test | 29 +++----- .../classify/tests/main.nf.test.snap | 70 ++----------------- 2 files changed, 15 insertions(+), 84 deletions(-) diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test b/modules/nf-core/saltshaker/classify/tests/main.nf.test index 6f5000c4304a..1a9372148073 100644 --- a/modules/nf-core/saltshaker/classify/tests/main.nf.test +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test @@ -1,5 +1,3 @@ -// TODO nf-core: Once you have added the required tests, please run the following command to build this file: -// nf-core modules test saltshaker/classify nextflow_process { name "Test Process SALTSHAKER_CLASSIFY" @@ -12,7 +10,6 @@ nextflow_process { tag "saltshaker" tag "saltshaker/classify" - // TODO nf-core: Change the test name preferably indicating the test-data and file-format used setup { run("SALTSHAKER_CALL") { @@ -21,26 +18,22 @@ nextflow_process { """ input[0] = [ [ id:'test' ], - file(params.modules_testdata_base_path + 'delete_me/saltshaker/test_mitosalt.breakpoint', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/mitosalt/test_mitosalt.breakpoint', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/mitosalt/test_mitosalt.cluster', checkIfExists: true), ] input[1] = [ - [ id:'test' ], - file(params.modules_testdata_base_path + 'delete_me/saltshaker/test_mitosalt.cluster', checkIfExists: true), - ] - - input[2] = [ [ id:'hg38' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/human_mt_rCRS.fasta', checkIfExists: true), ] - input[3] = 15 - input[4] = 0.01 - input[5] = 16569 - input[6] = 16081 - input[7] = 407 - input[8] = 5730 - input[9] = 5763 + input[2] = 15 + input[3] = 0.01 + input[4] = 16569 + input[5] = 16081 + input[6] = 407 + input[7] = 5730 + input[8] = 5763 """ } } @@ -65,7 +58,7 @@ nextflow_process { assert process.success assertAll( { assert snapshot( - process.out, + sanitizeOutput(process.out), ).match() } ) @@ -94,7 +87,7 @@ nextflow_process { assert process.success assertAll( { assert snapshot( - process.out, + sanitizeOutput(process.out), ).match() } ) } diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap index 6acee0acbf51..a7a9f29e33aa 100644 --- a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap @@ -2,37 +2,6 @@ "classify - vcf - stub": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test.saltshaker_classify_metadata.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "test.saltshaker_classify.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test" - }, - "test.saltshaker.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - [ - "SALTSHAKER_CLASSIFY", - "saltshaker", - "1.0.0" - ] - ], "classify": [ [ { @@ -66,7 +35,7 @@ ] } ], - "timestamp": "2026-03-05T16:08:21.537713", + "timestamp": "2026-03-16T10:53:38.916497", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.0" @@ -75,43 +44,12 @@ "classify - vcf": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test.saltshaker_classify_metadata.tsv:md5,e0a91b9e11b71222cf0bc892eba25114" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "test.saltshaker_classify.txt:md5,8e11ad30539d0b5e0ab9a42b4d68b208" - ] - ], - "2": [ - [ - { - "id": "test" - }, - "test.saltshaker.vcf:md5,c2ca8c445a41a311453afb9a787dd5fb" - ] - ], - "3": [ - [ - "SALTSHAKER_CLASSIFY", - "saltshaker", - "1.0.0" - ] - ], "classify": [ [ { "id": "test" }, - "test.saltshaker_classify_metadata.tsv:md5,e0a91b9e11b71222cf0bc892eba25114" + "test.saltshaker_classify_metadata.tsv:md5,0c86c16ae38a5dc7070ad76e764aee6d" ] ], "txt": [ @@ -127,7 +65,7 @@ { "id": "test" }, - "test.saltshaker.vcf:md5,c2ca8c445a41a311453afb9a787dd5fb" + "test.saltshaker.vcf:md5,2a618d7374fc6c7969690d1db68a9c4c" ] ], "versions_saltshaker": [ @@ -139,7 +77,7 @@ ] } ], - "timestamp": "2026-03-05T16:08:13.862273", + "timestamp": "2026-03-16T10:53:31.946521", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.0" From 8aec224ecc2d499e3b5128bd7a855af0c1f6fb7f Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Mon, 16 Mar 2026 11:28:05 +0100 Subject: [PATCH 06/14] fix linting --- modules/nf-core/saltshaker/classify/meta.yml | 26 +++++++++---------- .../saltshaker/classify/tests/main.nf.test | 1 + 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/modules/nf-core/saltshaker/classify/meta.yml b/modules/nf-core/saltshaker/classify/meta.yml index b1ebbac60783..e3bd91aba0e2 100644 --- a/modules/nf-core/saltshaker/classify/meta.yml +++ b/modules/nf-core/saltshaker/classify/meta.yml @@ -22,22 +22,21 @@ input: description: call metadata file from saltshaker_call pattern: "*_call_metadata.tsv" ontologies: [] - - dominant_fraction: + - dom_frac: type: float - description: Minimum fraction required for a call to be considered dominant + description: Minimum heteroplasmy fraction to classify as dominant in saltshaker - group_radius: type: integer description: Spatial clustering radius for saltshaker grouping - - high_heteroplasmy: - type: integer + - high_het: + type: float description: High heteroplasmy threshold for saltshaker classification - - multiple_threshold: - type: integer + - mult_thresh: + type: float description: Heteroplasmy threshold for multiple classification in saltshaker - - noise_threshold: + - noise_thresh: type: float description: Heteroplasmy threshold for noise in saltshaker classification - output: classify: - - meta: @@ -67,22 +66,21 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'sample1' ]` - - "*_classify.vcf": + - "*saltshaker.vcf": type: file - description: vcf file with variant calls + description: vcf file with classified calls pattern: "*saltshaker.vcf" ontologies: [] versions_saltshaker: - - - "${task.process}": + - - ${task.process}: type: string description: The name of the process - - "saltshaker": + - saltshaker: type: string description: The name of the tool - - "1.0.0": + - 1.0.0: type: string description: Hardcoded version of saltshaker used in the module - topics: versions: - - ${task.process}: diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test b/modules/nf-core/saltshaker/classify/tests/main.nf.test index 1a9372148073..330ab2f95867 100644 --- a/modules/nf-core/saltshaker/classify/tests/main.nf.test +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test @@ -8,6 +8,7 @@ nextflow_process { tag "modules" tag "modules_nfcore" tag "saltshaker" + tag "saltshaker/call" tag "saltshaker/classify" From 60dd84bbd3fbb9d52200eaf67df192e57ac8412f Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Fri, 6 Mar 2026 10:09:32 +0100 Subject: [PATCH 07/14] add saltshaker classify module and tests --- .../saltshaker/classify/environment.yml | 6 + modules/nf-core/saltshaker/classify/main.nf | 56 +++++++ modules/nf-core/saltshaker/classify/meta.yml | 100 ++++++++++++ .../saltshaker/classify/tests/main.nf.test | 104 ++++++++++++ .../classify/tests/main.nf.test.snap | 148 ++++++++++++++++++ .../saltshaker/classify/tests/nextflow.config | 5 + 6 files changed, 419 insertions(+) create mode 100644 modules/nf-core/saltshaker/classify/environment.yml create mode 100644 modules/nf-core/saltshaker/classify/main.nf create mode 100644 modules/nf-core/saltshaker/classify/meta.yml create mode 100644 modules/nf-core/saltshaker/classify/tests/main.nf.test create mode 100644 modules/nf-core/saltshaker/classify/tests/main.nf.test.snap create mode 100644 modules/nf-core/saltshaker/classify/tests/nextflow.config diff --git a/modules/nf-core/saltshaker/classify/environment.yml b/modules/nf-core/saltshaker/classify/environment.yml new file mode 100644 index 000000000000..4e7a14a64c86 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/environment.yml @@ -0,0 +1,6 @@ +channels: + - conda-forge + - bioconda +dependencies: + - pip: + - saltshaker==1.0.0 diff --git a/modules/nf-core/saltshaker/classify/main.nf b/modules/nf-core/saltshaker/classify/main.nf new file mode 100644 index 000000000000..576d97b6272f --- /dev/null +++ b/modules/nf-core/saltshaker/classify/main.nf @@ -0,0 +1,56 @@ +process SALTSHAKER_CLASSIFY { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/e9/e93d703b195dd27cd920cee46669d3f51043216c12fd05168c937e93adf170e8/data': + 'community.wave.seqera.io/library/pip_saltshaker:e08e38a6d45f8f32' }" + + input: + tuple val(meta), path(call) + val dom_frac + val group_radius + val high_het + val mult_thresh + val noise_thresh + + output: + tuple val(meta), path("*_classify_metadata.tsv"), emit: classify + tuple val(meta), path("*_classify.txt") , emit: txt + tuple val(meta), path("*saltshaker.vcf") , emit: vcf + tuple val("${task.process}"), val('saltshaker'), val("1.0.0"), topic: versions, emit: versions_saltshaker + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + saltshaker classify \\ + --prefix $prefix \\ + --input-dir . \\ + --vcf \\ + --dominant-fraction $dom_frac \\ + --radius $group_radius \\ + --high-het $high_het \\ + --multiple-threshold $mult_thresh \\ + --noise $noise_thresh \\ + $args + + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + """ + echo $args + + touch ${prefix}.saltshaker.vcf + touch ${prefix}.saltshaker_classify.txt + touch ${prefix}.saltshaker_classify_metadata.tsv + """ +} diff --git a/modules/nf-core/saltshaker/classify/meta.yml b/modules/nf-core/saltshaker/classify/meta.yml new file mode 100644 index 000000000000..b1ebbac60783 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/meta.yml @@ -0,0 +1,100 @@ +name: "saltshaker_classify" +description: mtDNA deletion and duplication classification downstream of mitosalt +keywords: + - saltshaker + - mitosalt + - mtDNA + - structural-variant calling +tools: + - "saltshaker": + description: "A Python package for classifying and visualizing mitochondrial structural variants from MitoSAlt pipeline output." + homepage: "https://github.com/aksenia/saltshaker" + documentation: "https://github.com/aksenia/saltshaker/tree/main/saltshaker/docs" + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - call: + type: file + description: call metadata file from saltshaker_call + pattern: "*_call_metadata.tsv" + ontologies: [] + - dominant_fraction: + type: float + description: Minimum fraction required for a call to be considered dominant + - group_radius: + type: integer + description: Spatial clustering radius for saltshaker grouping + - high_heteroplasmy: + type: integer + description: High heteroplasmy threshold for saltshaker classification + - multiple_threshold: + type: integer + description: Heteroplasmy threshold for multiple classification in saltshaker + - noise_threshold: + type: float + description: Heteroplasmy threshold for noise in saltshaker classification + +output: + classify: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*_classify_metadata.tsv": + type: file + description: tsv with classified call metadata to be used in saltshaker_plot + pattern: "*_classify_metadata.tsv" + ontologies: [] + txt: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*_classify.txt": + type: file + description: txt file with case classification + pattern: "*_classify.txt" + ontologies: [] + vcf: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*_classify.vcf": + type: file + description: vcf file with variant calls + pattern: "*saltshaker.vcf" + ontologies: [] + versions_saltshaker: + - - "${task.process}": + type: string + description: The name of the process + - "saltshaker": + type: string + description: The name of the tool + - "1.0.0": + type: string + description: Hardcoded version of saltshaker used in the module + +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - saltshaker: + type: string + description: The name of the tool + - 1.0.0: + type: string + description: Hardcoded version of saltshaker used in the module +authors: + - "@ieduba" +maintainers: + - "@ieduba" diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test b/modules/nf-core/saltshaker/classify/tests/main.nf.test new file mode 100644 index 000000000000..6f5000c4304a --- /dev/null +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test @@ -0,0 +1,104 @@ +// TODO nf-core: Once you have added the required tests, please run the following command to build this file: +// nf-core modules test saltshaker/classify +nextflow_process { + + name "Test Process SALTSHAKER_CLASSIFY" + script "../main.nf" + process "SALTSHAKER_CLASSIFY" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "saltshaker" + tag "saltshaker/classify" + + // TODO nf-core: Change the test name preferably indicating the test-data and file-format used + + setup { + run("SALTSHAKER_CALL") { + script "../../call/main.nf" + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'delete_me/saltshaker/test_mitosalt.breakpoint', checkIfExists: true), + ] + + input[1] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'delete_me/saltshaker/test_mitosalt.cluster', checkIfExists: true), + ] + + input[2] = [ + [ id:'hg38' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/human_mt_rCRS.fasta', checkIfExists: true), + ] + + input[3] = 15 + input[4] = 0.01 + input[5] = 16569 + input[6] = 16081 + input[7] = 407 + input[8] = 5730 + input[9] = 5763 + """ + } + } + } + + test("classify - vcf") { + + when { + process { + """ + input[0] = SALTSHAKER_CALL.out.call + input[1] = 0.5 + input[2] = 600 + input[3] = 10 + input[4] = 5 + input[5] = 0.3 + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + ).match() } + + ) + } + + } + + test("classify - vcf - stub") { + + options "-stub" + + when { + process { + """ + input[0] = SALTSHAKER_CALL.out.call + input[1] = 0.5 + input[2] = 600 + input[3] = 10 + input[4] = 5 + input[5] = 0.3 + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + process.out, + ).match() } + ) + } + + } + +} diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap new file mode 100644 index 000000000000..6acee0acbf51 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap @@ -0,0 +1,148 @@ +{ + "classify - vcf - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ], + "classify": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "txt": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "vcf": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_saltshaker": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ] + } + ], + "timestamp": "2026-03-05T16:08:21.537713", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.0" + } + }, + "classify - vcf": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,e0a91b9e11b71222cf0bc892eba25114" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,8e11ad30539d0b5e0ab9a42b4d68b208" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,c2ca8c445a41a311453afb9a787dd5fb" + ] + ], + "3": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ], + "classify": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,e0a91b9e11b71222cf0bc892eba25114" + ] + ], + "txt": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,8e11ad30539d0b5e0ab9a42b4d68b208" + ] + ], + "vcf": [ + [ + { + "id": "test" + }, + "test.saltshaker.vcf:md5,c2ca8c445a41a311453afb9a787dd5fb" + ] + ], + "versions_saltshaker": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ] + } + ], + "timestamp": "2026-03-05T16:08:13.862273", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.0" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/saltshaker/classify/tests/nextflow.config b/modules/nf-core/saltshaker/classify/tests/nextflow.config new file mode 100644 index 000000000000..6d4db8d027a2 --- /dev/null +++ b/modules/nf-core/saltshaker/classify/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: 'SALTSHAKER_CLASSIFY' { + ext.args = '--blacklist' + } +} From 084eb601059ed4c76aa67de6cb3828b4323dd3a6 Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Mon, 9 Mar 2026 09:01:06 +0100 Subject: [PATCH 08/14] pin pip version --- modules/nf-core/saltshaker/classify/environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/nf-core/saltshaker/classify/environment.yml b/modules/nf-core/saltshaker/classify/environment.yml index 4e7a14a64c86..f76c4bf5a598 100644 --- a/modules/nf-core/saltshaker/classify/environment.yml +++ b/modules/nf-core/saltshaker/classify/environment.yml @@ -2,5 +2,6 @@ channels: - conda-forge - bioconda dependencies: + - pip==26.0.1 - pip: - saltshaker==1.0.0 From 36451597ed7b9bea57c0dcc58d52134276eec376 Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Mon, 16 Mar 2026 11:01:42 +0100 Subject: [PATCH 09/14] update test with nf-core saltshaker/call --- .../saltshaker/classify/tests/main.nf.test | 29 +++----- .../classify/tests/main.nf.test.snap | 70 ++----------------- 2 files changed, 15 insertions(+), 84 deletions(-) diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test b/modules/nf-core/saltshaker/classify/tests/main.nf.test index 6f5000c4304a..1a9372148073 100644 --- a/modules/nf-core/saltshaker/classify/tests/main.nf.test +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test @@ -1,5 +1,3 @@ -// TODO nf-core: Once you have added the required tests, please run the following command to build this file: -// nf-core modules test saltshaker/classify nextflow_process { name "Test Process SALTSHAKER_CLASSIFY" @@ -12,7 +10,6 @@ nextflow_process { tag "saltshaker" tag "saltshaker/classify" - // TODO nf-core: Change the test name preferably indicating the test-data and file-format used setup { run("SALTSHAKER_CALL") { @@ -21,26 +18,22 @@ nextflow_process { """ input[0] = [ [ id:'test' ], - file(params.modules_testdata_base_path + 'delete_me/saltshaker/test_mitosalt.breakpoint', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/mitosalt/test_mitosalt.breakpoint', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/mitosalt/test_mitosalt.cluster', checkIfExists: true), ] input[1] = [ - [ id:'test' ], - file(params.modules_testdata_base_path + 'delete_me/saltshaker/test_mitosalt.cluster', checkIfExists: true), - ] - - input[2] = [ [ id:'hg38' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/human_mt_rCRS.fasta', checkIfExists: true), ] - input[3] = 15 - input[4] = 0.01 - input[5] = 16569 - input[6] = 16081 - input[7] = 407 - input[8] = 5730 - input[9] = 5763 + input[2] = 15 + input[3] = 0.01 + input[4] = 16569 + input[5] = 16081 + input[6] = 407 + input[7] = 5730 + input[8] = 5763 """ } } @@ -65,7 +58,7 @@ nextflow_process { assert process.success assertAll( { assert snapshot( - process.out, + sanitizeOutput(process.out), ).match() } ) @@ -94,7 +87,7 @@ nextflow_process { assert process.success assertAll( { assert snapshot( - process.out, + sanitizeOutput(process.out), ).match() } ) } diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap index 6acee0acbf51..a7a9f29e33aa 100644 --- a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap @@ -2,37 +2,6 @@ "classify - vcf - stub": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test.saltshaker_classify_metadata.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "test.saltshaker_classify.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test" - }, - "test.saltshaker.vcf:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - [ - "SALTSHAKER_CLASSIFY", - "saltshaker", - "1.0.0" - ] - ], "classify": [ [ { @@ -66,7 +35,7 @@ ] } ], - "timestamp": "2026-03-05T16:08:21.537713", + "timestamp": "2026-03-16T10:53:38.916497", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.0" @@ -75,43 +44,12 @@ "classify - vcf": { "content": [ { - "0": [ - [ - { - "id": "test" - }, - "test.saltshaker_classify_metadata.tsv:md5,e0a91b9e11b71222cf0bc892eba25114" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "test.saltshaker_classify.txt:md5,8e11ad30539d0b5e0ab9a42b4d68b208" - ] - ], - "2": [ - [ - { - "id": "test" - }, - "test.saltshaker.vcf:md5,c2ca8c445a41a311453afb9a787dd5fb" - ] - ], - "3": [ - [ - "SALTSHAKER_CLASSIFY", - "saltshaker", - "1.0.0" - ] - ], "classify": [ [ { "id": "test" }, - "test.saltshaker_classify_metadata.tsv:md5,e0a91b9e11b71222cf0bc892eba25114" + "test.saltshaker_classify_metadata.tsv:md5,0c86c16ae38a5dc7070ad76e764aee6d" ] ], "txt": [ @@ -127,7 +65,7 @@ { "id": "test" }, - "test.saltshaker.vcf:md5,c2ca8c445a41a311453afb9a787dd5fb" + "test.saltshaker.vcf:md5,2a618d7374fc6c7969690d1db68a9c4c" ] ], "versions_saltshaker": [ @@ -139,7 +77,7 @@ ] } ], - "timestamp": "2026-03-05T16:08:13.862273", + "timestamp": "2026-03-16T10:53:31.946521", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.0" From 2bc1be9224c3cb51908d0dc29b3ea165b22949ed Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Mon, 16 Mar 2026 11:28:05 +0100 Subject: [PATCH 10/14] fix linting --- modules/nf-core/saltshaker/classify/meta.yml | 26 +++++++++---------- .../saltshaker/classify/tests/main.nf.test | 1 + 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/modules/nf-core/saltshaker/classify/meta.yml b/modules/nf-core/saltshaker/classify/meta.yml index b1ebbac60783..e3bd91aba0e2 100644 --- a/modules/nf-core/saltshaker/classify/meta.yml +++ b/modules/nf-core/saltshaker/classify/meta.yml @@ -22,22 +22,21 @@ input: description: call metadata file from saltshaker_call pattern: "*_call_metadata.tsv" ontologies: [] - - dominant_fraction: + - dom_frac: type: float - description: Minimum fraction required for a call to be considered dominant + description: Minimum heteroplasmy fraction to classify as dominant in saltshaker - group_radius: type: integer description: Spatial clustering radius for saltshaker grouping - - high_heteroplasmy: - type: integer + - high_het: + type: float description: High heteroplasmy threshold for saltshaker classification - - multiple_threshold: - type: integer + - mult_thresh: + type: float description: Heteroplasmy threshold for multiple classification in saltshaker - - noise_threshold: + - noise_thresh: type: float description: Heteroplasmy threshold for noise in saltshaker classification - output: classify: - - meta: @@ -67,22 +66,21 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'sample1' ]` - - "*_classify.vcf": + - "*saltshaker.vcf": type: file - description: vcf file with variant calls + description: vcf file with classified calls pattern: "*saltshaker.vcf" ontologies: [] versions_saltshaker: - - - "${task.process}": + - - ${task.process}: type: string description: The name of the process - - "saltshaker": + - saltshaker: type: string description: The name of the tool - - "1.0.0": + - 1.0.0: type: string description: Hardcoded version of saltshaker used in the module - topics: versions: - - ${task.process}: diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test b/modules/nf-core/saltshaker/classify/tests/main.nf.test index 1a9372148073..330ab2f95867 100644 --- a/modules/nf-core/saltshaker/classify/tests/main.nf.test +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test @@ -8,6 +8,7 @@ nextflow_process { tag "modules" tag "modules_nfcore" tag "saltshaker" + tag "saltshaker/call" tag "saltshaker/classify" From 507b6f9874d9973b23457fa7c0ea211b7310115b Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Tue, 17 Mar 2026 10:03:04 +0100 Subject: [PATCH 11/14] edits from review --- modules/nf-core/saltshaker/classify/main.nf | 19 +++++++++---------- modules/nf-core/saltshaker/classify/meta.yml | 16 ++++++++++++---- .../saltshaker/classify/tests/main.nf.test | 7 ++++++- .../saltshaker/classify/tests/nextflow.config | 2 +- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/modules/nf-core/saltshaker/classify/main.nf b/modules/nf-core/saltshaker/classify/main.nf index 576d97b6272f..5e67822516c3 100644 --- a/modules/nf-core/saltshaker/classify/main.nf +++ b/modules/nf-core/saltshaker/classify/main.nf @@ -9,16 +9,16 @@ process SALTSHAKER_CLASSIFY { input: tuple val(meta), path(call) - val dom_frac + val dominant_fraction val group_radius - val high_het - val mult_thresh - val noise_thresh + val high_heteroplasmy + val multiple_threshold + val noise_threshold output: tuple val(meta), path("*_classify_metadata.tsv"), emit: classify tuple val(meta), path("*_classify.txt") , emit: txt - tuple val(meta), path("*saltshaker.vcf") , emit: vcf + tuple val(meta), path("*saltshaker.vcf") , emit: vcf, optional: true tuple val("${task.process}"), val('saltshaker'), val("1.0.0"), topic: versions, emit: versions_saltshaker when: @@ -32,12 +32,11 @@ process SALTSHAKER_CLASSIFY { saltshaker classify \\ --prefix $prefix \\ --input-dir . \\ - --vcf \\ - --dominant-fraction $dom_frac \\ + --dominant-fraction $dominant_fraction \\ --radius $group_radius \\ - --high-het $high_het \\ - --multiple-threshold $mult_thresh \\ - --noise $noise_thresh \\ + --high-het $high_heteroplasmy \\ + --multiple-threshold $multiple_threshold \\ + --noise $noise_threshold \\ $args """ diff --git a/modules/nf-core/saltshaker/classify/meta.yml b/modules/nf-core/saltshaker/classify/meta.yml index e3bd91aba0e2..40dd8f060e15 100644 --- a/modules/nf-core/saltshaker/classify/meta.yml +++ b/modules/nf-core/saltshaker/classify/meta.yml @@ -21,7 +21,9 @@ input: type: file description: call metadata file from saltshaker_call pattern: "*_call_metadata.tsv" - ontologies: [] + ontologies: + - edam: http://edamontology.org/operation_3227 #variant calling + - edam: http://edamontology.org/format_3475 #tsv - dom_frac: type: float description: Minimum heteroplasmy fraction to classify as dominant in saltshaker @@ -48,7 +50,9 @@ output: type: file description: tsv with classified call metadata to be used in saltshaker_plot pattern: "*_classify_metadata.tsv" - ontologies: [] + ontologies: + - edam: http://edamontology.org/operation_3225 #classification + - edam: http://edamontology.org/format_3475 #tsv txt: - - meta: type: map @@ -59,7 +63,9 @@ output: type: file description: txt file with case classification pattern: "*_classify.txt" - ontologies: [] + ontologies: + - edam: http://edamontology.org/operation_3225 #classification + - edam: http://edamontology.org/format_2330 #txt vcf: - - meta: type: map @@ -70,7 +76,9 @@ output: type: file description: vcf file with classified calls pattern: "*saltshaker.vcf" - ontologies: [] + ontologies: + - edam: http://edamontology.org/operation_3225 #classification + - edam: http://edamontology.org/format_3016 #vcf versions_saltshaker: - - ${task.process}: type: string diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test b/modules/nf-core/saltshaker/classify/tests/main.nf.test index 330ab2f95867..010676cd633b 100644 --- a/modules/nf-core/saltshaker/classify/tests/main.nf.test +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test @@ -11,7 +11,6 @@ nextflow_process { tag "saltshaker/call" tag "saltshaker/classify" - setup { run("SALTSHAKER_CALL") { script "../../call/main.nf" @@ -43,6 +42,9 @@ nextflow_process { test("classify - vcf") { when { + params { + module_args = '--blacklist --vcf' + } process { """ input[0] = SALTSHAKER_CALL.out.call @@ -72,6 +74,9 @@ nextflow_process { options "-stub" when { + params { + module_args = '--blacklist --vcf' + } process { """ input[0] = SALTSHAKER_CALL.out.call diff --git a/modules/nf-core/saltshaker/classify/tests/nextflow.config b/modules/nf-core/saltshaker/classify/tests/nextflow.config index 6d4db8d027a2..97d25b454bf2 100644 --- a/modules/nf-core/saltshaker/classify/tests/nextflow.config +++ b/modules/nf-core/saltshaker/classify/tests/nextflow.config @@ -1,5 +1,5 @@ process { withName: 'SALTSHAKER_CLASSIFY' { - ext.args = '--blacklist' + ext.args = params.module_args } } From 146cdf68ccba9b48d61d7fbe2515d5a792987781 Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Tue, 17 Mar 2026 10:20:18 +0100 Subject: [PATCH 12/14] update snaps and meta.yml --- modules/nf-core/saltshaker/classify/meta.yml | 8 ++++---- .../nf-core/saltshaker/classify/tests/main.nf.test.snap | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/nf-core/saltshaker/classify/meta.yml b/modules/nf-core/saltshaker/classify/meta.yml index 40dd8f060e15..182df6566cdd 100644 --- a/modules/nf-core/saltshaker/classify/meta.yml +++ b/modules/nf-core/saltshaker/classify/meta.yml @@ -24,19 +24,19 @@ input: ontologies: - edam: http://edamontology.org/operation_3227 #variant calling - edam: http://edamontology.org/format_3475 #tsv - - dom_frac: + - dominant_fraction: type: float description: Minimum heteroplasmy fraction to classify as dominant in saltshaker - group_radius: type: integer description: Spatial clustering radius for saltshaker grouping - - high_het: + - high_heteroplasmy: type: float description: High heteroplasmy threshold for saltshaker classification - - mult_thresh: + - multiple_threshold: type: float description: Heteroplasmy threshold for multiple classification in saltshaker - - noise_thresh: + - noise_threshold: type: float description: Heteroplasmy threshold for noise in saltshaker classification output: diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap index a7a9f29e33aa..f782527ab2e8 100644 --- a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap @@ -65,7 +65,7 @@ { "id": "test" }, - "test.saltshaker.vcf:md5,2a618d7374fc6c7969690d1db68a9c4c" + "test.saltshaker.vcf:md5,6669688cfb486e6c98f0aadb8e41ed88" ] ], "versions_saltshaker": [ @@ -77,7 +77,7 @@ ] } ], - "timestamp": "2026-03-16T10:53:31.946521", + "timestamp": "2026-03-17T10:17:34.236265", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.0" From 884833835490db9388d9f194f5879f10a4f3f6ea Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Tue, 17 Mar 2026 10:48:15 +0100 Subject: [PATCH 13/14] only make vcf in stub if vcf is in args --- modules/nf-core/saltshaker/classify/main.nf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/nf-core/saltshaker/classify/main.nf b/modules/nf-core/saltshaker/classify/main.nf index 5e67822516c3..290725449065 100644 --- a/modules/nf-core/saltshaker/classify/main.nf +++ b/modules/nf-core/saltshaker/classify/main.nf @@ -48,7 +48,9 @@ process SALTSHAKER_CLASSIFY { """ echo $args - touch ${prefix}.saltshaker.vcf + if [[ "$args" == *"--vcf"* ]]; then + touch ${prefix}.saltshaker.vcf + fi touch ${prefix}.saltshaker_classify.txt touch ${prefix}.saltshaker_classify_metadata.tsv """ From 631f22fa106460c9877871fc33102177c6f245ce Mon Sep 17 00:00:00 2001 From: Irene Duba Date: Tue, 17 Mar 2026 11:03:53 +0100 Subject: [PATCH 14/14] add no-vcf tests --- modules/nf-core/saltshaker/classify/main.nf | 5 +- .../saltshaker/classify/tests/main.nf.test | 61 +++++++++++++++ .../classify/tests/main.nf.test.snap | 74 +++++++++++++++++++ 3 files changed, 137 insertions(+), 3 deletions(-) diff --git a/modules/nf-core/saltshaker/classify/main.nf b/modules/nf-core/saltshaker/classify/main.nf index 290725449065..20931297404a 100644 --- a/modules/nf-core/saltshaker/classify/main.nf +++ b/modules/nf-core/saltshaker/classify/main.nf @@ -44,13 +44,12 @@ process SALTSHAKER_CLASSIFY { stub: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" + def touch_vcf = args.contains('--vcf') ? "touch ${prefix}.saltshaker.vcf" : '' """ echo $args - if [[ "$args" == *"--vcf"* ]]; then - touch ${prefix}.saltshaker.vcf - fi + $touch_vcf touch ${prefix}.saltshaker_classify.txt touch ${prefix}.saltshaker_classify_metadata.tsv """ diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test b/modules/nf-core/saltshaker/classify/tests/main.nf.test index 010676cd633b..12cc1ec945bc 100644 --- a/modules/nf-core/saltshaker/classify/tests/main.nf.test +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test @@ -100,4 +100,65 @@ nextflow_process { } + test("classify - no-vcf") { + + when { + params { + module_args = '--blacklist' + } + process { + """ + input[0] = SALTSHAKER_CALL.out.call + input[1] = 0.5 + input[2] = 600 + input[3] = 10 + input[4] = 5 + input[5] = 0.3 + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + sanitizeOutput(process.out), + ).match() } + + ) + } + + } + + test("classify - no-vcf - stub") { + + options "-stub" + + when { + params { + module_args = '--blacklist' + } + process { + """ + input[0] = SALTSHAKER_CALL.out.call + input[1] = 0.5 + input[2] = 600 + input[3] = 10 + input[4] = 5 + input[5] = 0.3 + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + sanitizeOutput(process.out), + ).match() } + ) + } + + } + } diff --git a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap index f782527ab2e8..ff226554f23f 100644 --- a/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap +++ b/modules/nf-core/saltshaker/classify/tests/main.nf.test.snap @@ -1,4 +1,41 @@ { + "classify - no-vcf": { + "content": [ + { + "classify": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,0c86c16ae38a5dc7070ad76e764aee6d" + ] + ], + "txt": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,8e11ad30539d0b5e0ab9a42b4d68b208" + ] + ], + "vcf": [ + + ], + "versions_saltshaker": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ] + } + ], + "timestamp": "2026-03-17T11:02:38.830976", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.0" + } + }, "classify - vcf - stub": { "content": [ { @@ -82,5 +119,42 @@ "nf-test": "0.9.4", "nextflow": "25.10.0" } + }, + "classify - no-vcf - stub": { + "content": [ + { + "classify": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify_metadata.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "txt": [ + [ + { + "id": "test" + }, + "test.saltshaker_classify.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "vcf": [ + + ], + "versions_saltshaker": [ + [ + "SALTSHAKER_CLASSIFY", + "saltshaker", + "1.0.0" + ] + ] + } + ], + "timestamp": "2026-03-17T11:02:43.86661", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.0" + } } } \ No newline at end of file