Skip to content

Commit 978985a

Browse files
jonasscheidclaudeLouisLeNezet
authored
New module: parsesdrf/convert (#11514)
* feat(sdrfpipelines/parsesdrf): add module to convert SDRF files via sdrf-pipelines Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(sdrfpipelines/convertmhcquant): rename from parsesdrf, lock to convert-mhcquant subcommand, add meta map and prefix-based outputs Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(sdrfpipelines/convertmhcquant): restore versions emit name and align meta.yml output patterns with main.nf prefix Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(parsesdrf/convert): generalize to all parse_sdrf convert-* subcommands with per-format output tuples * fix(parsesdrf/convert): resolve CI failures, default module_args per-test, emit versions topic, bump sdrf-pipelines 0.1.3->0.1.4 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(parsesdrf/convert): drop md5s from maxquant snapshot (non-deterministic XML output upstream) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(parsesdrf/convert): wrap process.out in sanitizeOutput across all tests to drop duplicate numeric channel keys (-40% snap size, md5 coverage unchanged) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Update modules/nf-core/parsesdrf/convert/environment.yml Co-authored-by: Louis Le Nézet <58640615+LouisLeNezet@users.noreply.github.com> * feat(parsesdrf/convert): promote fasta/raw_folder to input channel, drop module_args plumbing Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Louis Le Nézet <58640615+LouisLeNezet@users.noreply.github.com>
1 parent fc6f777 commit 978985a

5 files changed

Lines changed: 1101 additions & 0 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
3+
channels:
4+
- conda-forge
5+
- bioconda
6+
dependencies:
7+
- bioconda::sdrf-pipelines=0.1.4
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
process PARSESDRF_CONVERT {
2+
tag "${meta.id}"
3+
label 'process_single'
4+
5+
conda "${moduleDir}/environment.yml"
6+
container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ?
7+
'https://depot.galaxyproject.org/singularity/sdrf-pipelines:0.1.4--pyhdfd78af_0':
8+
'quay.io/biocontainers/sdrf-pipelines:0.1.4--pyhdfd78af_0' }"
9+
10+
input:
11+
tuple val(meta), path(sdrf), path(fasta), val(raw_folder)
12+
val format
13+
14+
output:
15+
tuple val(meta), path("${prefix}_samplesheet.tsv"), path("${prefix}_presets.tsv"), emit: mhcquant, optional: true
16+
tuple val(meta), path("${prefix}_samplesheet.tsv"), path("${prefix}_experimental_design.tsv"), emit: openms, optional: true
17+
tuple val(meta), path("${prefix}.xml"), path("${prefix}_design.txt"), emit: maxquant, optional: true
18+
tuple val(meta), path("${prefix}.csv"), emit: msstats, optional: true
19+
tuple val(meta), path("${prefix}_design.csv"), path("${prefix}_comparisons.csv"), emit: normalyzerde, optional: true
20+
tuple val(meta), path("${prefix}.cfg"), path("${prefix}_design.tsv"), emit: diann, optional: true
21+
tuple val("${task.process}"), val('sdrf-pipelines'), eval("parse_sdrf --version | cut -d ' ' -f 2"), topic: versions, emit: versions_sdrfpipelines
22+
23+
when:
24+
task.ext.when == null || task.ext.when
25+
26+
script:
27+
prefix = task.ext.prefix ?: "${meta.id}"
28+
def args = task.ext.args ?: ''
29+
def output_args = ''
30+
def post = ''
31+
32+
if (format == 'mhcquant') {
33+
output_args = "-os ${prefix}_samplesheet.tsv -op ${prefix}_presets.tsv"
34+
} else if (format == 'openms') {
35+
// convert-openms writes openms.tsv + (optionally) experimental_design.tsv
36+
post = "mv openms.tsv ${prefix}_samplesheet.tsv ; [ -f experimental_design.tsv ] && mv experimental_design.tsv ${prefix}_experimental_design.tsv || true"
37+
} else if (format == 'maxquant') {
38+
if (!fasta || !raw_folder) {
39+
error "PARSESDRF_CONVERT: format 'maxquant' requires both `fasta` (path) and `raw_folder` (string) inputs"
40+
}
41+
// fasta is staged into the work dir; raw_folder is a literal string embedded into mqpar.xml's <filePaths>
42+
output_args = "-f ${fasta} -r ${raw_folder} -o1 ${prefix}.xml -o2 ${prefix}_design.txt"
43+
} else if (format == 'msstats') {
44+
output_args = "-o ${prefix}.csv"
45+
} else if (format == 'normalyzerde') {
46+
output_args = "-o ${prefix}_design.csv -oc ${prefix}_comparisons.csv"
47+
} else if (format == 'diann') {
48+
// convert-diann writes diann_config.cfg + diann_design.tsv with fixed names
49+
post = "mv diann_config.cfg ${prefix}.cfg && mv diann_design.tsv ${prefix}_design.tsv"
50+
} else {
51+
error "PARSESDRF_CONVERT: unsupported format '${format}' (expected one of: mhcquant, openms, maxquant, msstats, normalyzerde, diann)"
52+
}
53+
54+
"""
55+
parse_sdrf convert-${format} \\
56+
-s ${sdrf} \\
57+
${output_args} \\
58+
${args}
59+
${post}
60+
"""
61+
62+
stub:
63+
prefix = task.ext.prefix ?: "${meta.id}"
64+
def stub_files
65+
if (format == 'mhcquant') {
66+
stub_files = ["${prefix}_samplesheet.tsv", "${prefix}_presets.tsv"]
67+
} else if (format == 'openms') {
68+
stub_files = ["${prefix}_samplesheet.tsv", "${prefix}_experimental_design.tsv"]
69+
} else if (format == 'maxquant') {
70+
stub_files = ["${prefix}.xml", "${prefix}_design.txt"]
71+
} else if (format == 'msstats') {
72+
stub_files = ["${prefix}.csv"]
73+
} else if (format == 'normalyzerde') {
74+
stub_files = ["${prefix}_design.csv", "${prefix}_comparisons.csv"]
75+
} else if (format == 'diann') {
76+
stub_files = ["${prefix}.cfg", "${prefix}_design.tsv"]
77+
} else {
78+
error "PARSESDRF_CONVERT: unsupported format '${format}'"
79+
}
80+
def touches = stub_files.collect { f -> "touch ${f}" }.join('\n ')
81+
"""
82+
${touches}
83+
"""
84+
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
name: "parsesdrf_convert"
2+
description: |
3+
Convert an SDRF (Sample and Data Relationship Format) file into a
4+
pipeline-specific samplesheet/configuration using the `parse_sdrf
5+
convert-<format>` subcommands of the sdrf-pipelines package. The chosen
6+
`format` selects the subcommand; the module owns the output filenames and
7+
emits one tuple per supported format (mhcquant, openms, maxquant, msstats,
8+
normalyzerde, diann).
9+
keywords:
10+
- sdrf
11+
- sdrf-pipelines
12+
- samplesheet
13+
- proteomics
14+
- immunopeptidomics
15+
- mhcquant
16+
- openms
17+
- maxquant
18+
- msstats
19+
- normalyzerde
20+
- diann
21+
- metadata
22+
tools:
23+
- "sdrf-pipelines":
24+
description: "A set of tools to validate and convert SDRF files for proteomics
25+
pipelines."
26+
homepage: "https://github.com/bigbio/sdrf-pipelines"
27+
documentation: "https://github.com/bigbio/sdrf-pipelines"
28+
tool_dev_url: "https://github.com/bigbio/sdrf-pipelines"
29+
doi: "10.1021/acs.jproteome.1c00505"
30+
licence:
31+
- "Apache-2.0"
32+
identifier: "biotools:sdrf-pipelines"
33+
input:
34+
- - meta:
35+
type: map
36+
description: |
37+
Groovy Map containing sample/run information
38+
e.g. `[ id:'PXD009752' ]`
39+
- sdrf:
40+
type: file
41+
description: SDRF file describing the experimental design and sample metadata.
42+
pattern: "*.{tsv,sdrf.tsv}"
43+
ontologies:
44+
- edam: http://edamontology.org/format_3475
45+
- fasta:
46+
type: file
47+
description: |
48+
Protein database FASTA. Required when `format == 'maxquant'`
49+
(passed to `-f`); pass `[]` otherwise.
50+
pattern: "*.{fasta,fa,fasta.gz,fa.gz}"
51+
ontologies:
52+
- edam: http://edamontology.org/format_1929
53+
- raw_folder:
54+
type: string
55+
description: |
56+
Directory prefix embedded as a literal string into the
57+
`<filePaths>` block of the generated MaxQuant `mqpar.xml`; must
58+
resolve on the host that later runs MaxQuant. Required when
59+
`format == 'maxquant'`; pass `''` otherwise.
60+
- format:
61+
type: string
62+
description: |
63+
Target converter. One of: `mhcquant`, `openms`, `maxquant`,
64+
`msstats`, `normalyzerde`, `diann`. Selects the
65+
`parse_sdrf convert-<format>` subcommand.
66+
output:
67+
mhcquant:
68+
- - meta:
69+
type: map
70+
description: Groovy Map containing sample/run information
71+
- "${prefix}_samplesheet.tsv":
72+
type: file
73+
description: MHCquant samplesheet TSV (`-os`).
74+
pattern: "*_samplesheet.tsv"
75+
ontologies:
76+
- edam: http://edamontology.org/format_3475
77+
- "${prefix}_presets.tsv":
78+
type: file
79+
description: MHCquant search-preset TSV (`-op`).
80+
pattern: "*_presets.tsv"
81+
ontologies:
82+
- edam: http://edamontology.org/format_3475
83+
openms:
84+
- - meta:
85+
type: map
86+
description: Groovy Map containing sample/run information
87+
- "${prefix}_samplesheet.tsv":
88+
type: file
89+
description: OpenMS samplesheet TSV (renamed from `openms.tsv`).
90+
pattern: "*_samplesheet.tsv"
91+
ontologies:
92+
- edam: http://edamontology.org/format_3475
93+
- "${prefix}_experimental_design.tsv":
94+
type: file
95+
description: OpenMS experimental design TSV.
96+
pattern: "*_experimental_design.tsv"
97+
ontologies:
98+
- edam: http://edamontology.org/format_3475
99+
maxquant:
100+
- - meta:
101+
type: map
102+
description: Groovy Map containing sample/run information
103+
- "${prefix}.xml":
104+
type: file
105+
description: MaxQuant `mqpar.xml` (`-o1`).
106+
pattern: "*.xml"
107+
ontologies:
108+
- edam: http://edamontology.org/format_2332
109+
- "${prefix}_design.txt":
110+
type: file
111+
description: MaxQuant experimental design TXT (`-o2`).
112+
pattern: "*_design.txt"
113+
ontologies:
114+
- edam: http://edamontology.org/format_3475
115+
msstats:
116+
- - meta:
117+
type: map
118+
description: Groovy Map containing sample/run information
119+
- "${prefix}.csv":
120+
type: file
121+
description: MSstats annotation CSV (`-o`).
122+
pattern: "*.csv"
123+
ontologies:
124+
- edam: http://edamontology.org/format_3752
125+
normalyzerde:
126+
- - meta:
127+
type: map
128+
description: Groovy Map containing sample/run information
129+
- "${prefix}_design.csv":
130+
type: file
131+
description: NormalyzerDE design CSV (`-o`).
132+
pattern: "*_design.csv"
133+
ontologies:
134+
- edam: http://edamontology.org/format_3752
135+
- "${prefix}_comparisons.csv":
136+
type: file
137+
description: NormalyzerDE comparisons CSV (`-oc`).
138+
pattern: "*_comparisons.csv"
139+
ontologies:
140+
- edam: http://edamontology.org/format_3752
141+
diann:
142+
- - meta:
143+
type: map
144+
description: Groovy Map containing sample/run information
145+
- "${prefix}.cfg":
146+
type: file
147+
description: DIA-NN config (renamed from `diann_config.cfg`).
148+
pattern: "*.cfg"
149+
ontologies:
150+
- edam: http://edamontology.org/format_2330
151+
- "${prefix}_design.tsv":
152+
type: file
153+
description: DIA-NN experimental design TSV (renamed from `diann_design.tsv`).
154+
pattern: "*_design.tsv"
155+
ontologies:
156+
- edam: http://edamontology.org/format_3475
157+
versions_sdrfpipelines:
158+
- - "${task.process}":
159+
type: string
160+
description: The name of the process
161+
- "sdrf-pipelines":
162+
type: string
163+
description: The name of the tool
164+
- "parse_sdrf --version | cut -d ' ' -f 2":
165+
type: eval
166+
description: The expression to obtain the version of the tool
167+
topics:
168+
versions:
169+
- - "${task.process}":
170+
type: string
171+
description: The name of the process
172+
- "sdrf-pipelines":
173+
type: string
174+
description: The name of the tool
175+
- "parse_sdrf --version | cut -d ' ' -f 2":
176+
type: eval
177+
description: The expression to obtain the version of the tool
178+
authors:
179+
- "@jonasscheid"
180+
maintainers:
181+
- "@jonasscheid"

0 commit comments

Comments
 (0)