-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add sativaepang/* modules: reference, lootasks, looplace, looscore #12910
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 5 commits
effded8
d2f1938
4d4aaa9
8cf99d4
df09b4f
adf8590
6be77f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| # yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json | ||
| channels: | ||
| - conda-forge | ||
| - bioconda | ||
| dependencies: | ||
| - bioconda::sativa-epang=0.9.3.4 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| process SATIVAEPANG_LOOPLACE { | ||
| tag "$meta.id" | ||
| label 'process_high' | ||
|
|
||
| conda "${moduleDir}/environment.yml" | ||
| container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? | ||
| 'https://depot.galaxyproject.org/singularity/sativa-epang:0.9.3.4--py314hab16a5f_0' : | ||
| 'quay.io/biocontainers/sativa-epang:0.9.3.4--py314hab16a5f_0' }" | ||
|
|
||
| input: | ||
| tuple val(meta), path(taskdir) | ||
|
|
||
| output: | ||
| tuple val(meta), path(taskdir), emit: taskdir | ||
| tuple val("${task.process}"), val('sativaepang'), eval("sed -n 's#.*share/sativa-epang-\\([0-9.]*\\)-.*#\\1#p' \$(command -v sativa-epang)"), topic: versions, emit: versions_sativaepang | ||
|
|
||
| when: | ||
| task.ext.when == null || task.ext.when | ||
|
|
||
| script: | ||
| def args = task.ext.args ?: '' | ||
| """ | ||
| # \$taskdir is staged from sativaepang/lootasks's own output -- a symlink under | ||
| # local/shared-filesystem staging, but a real copy under stageInMode 'copy' (the | ||
| # default for cloud storage without Fusion). loo-place writes a jplace (and logs) | ||
| # inside every fold directory, which would mutate that other task's output in place | ||
| # and make this task uncacheable across -resume (same class of bug as | ||
| # nf-core/modules#12799). Give it a private, writable directory tree instead: fold | ||
| # subdirectories are real (new) directories here, their read-only contents | ||
| # (ref.nwk/ref.fasta/query.fasta) stay symlinks to avoid copying large alignments, | ||
| # and manifest.json at the top level is a plain symlink since loo-place never writes | ||
| # there. mv handles both staging modes: it moves a symlink as a symlink, and renames | ||
| # a real directory in place, so nothing is deleted either way. | ||
| mv "$taskdir" "${taskdir}.staged" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Surely just stage the original with this name instead.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same reasoning as in my reply above — happy to take another look if you still see room to trim further once you've seen the shrunk version. |
||
| real_taskdir=\$(readlink -f "${taskdir}.staged") | ||
| mkdir "$taskdir" | ||
| find "\$real_taskdir" -mindepth 1 -maxdepth 1 | while read -r entry; do | ||
| name=\$(basename "\$entry") | ||
| if [ -d "\$entry" ]; then | ||
| mkdir "$taskdir/\$name" | ||
| find "\$entry" -mindepth 1 -maxdepth 1 -exec ln -s {} "$taskdir/\$name"/ \\; | ||
| else | ||
| ln -s "\$entry" "$taskdir/\$name" | ||
| fi | ||
| done | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a lot of code, is it really required?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some form of private writable staging is required: sativa-epang writes results into every fold directory, and You're right that the generic version was overkill though: it was walking an arbitrary file/directory tree, but |
||
|
|
||
| sativa-epang \\ | ||
| -stage loo-place \\ | ||
| -taskdir $taskdir \\ | ||
| -T ${task.cpus} \\ | ||
| ${args} | ||
| """ | ||
|
|
||
| stub: | ||
| """ | ||
| mv "$taskdir" "${taskdir}.staged" | ||
| real_taskdir=\$(readlink -f "${taskdir}.staged") | ||
| mkdir "$taskdir" | ||
| find "\$real_taskdir" -mindepth 1 -maxdepth 1 | while read -r entry; do | ||
| name=\$(basename "\$entry") | ||
| if [ -d "\$entry" ]; then | ||
| mkdir "$taskdir/\$name" | ||
| touch "$taskdir/\$name/epa_result.jplace" | ||
| else | ||
| ln -s "\$entry" "$taskdir/\$name" | ||
| fi | ||
| done | ||
| """ | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| name: "sativaepang_looplace" | ||
| description: Place every leave-one-out fold with EPA-ng via -stage loo-place, writing a jplace into each fold directory | ||
| keywords: | ||
| - phylogenetics | ||
| - taxonomy | ||
| - mislabelling | ||
| - placement | ||
| - leave-one-out | ||
| tools: | ||
| - "sativaepang": | ||
| description: "SATIVA with EPA-ng as the placement engine" | ||
| homepage: "https://github.com/Aaramis/sativa-epang" | ||
| documentation: "https://github.com/Aaramis/sativa-epang/blob/main/CHANGES-epa-ng.md" | ||
| tool_dev_url: "https://github.com/Aaramis/sativa-epang" | ||
| doi: "10.1093/nar/gkw396" | ||
| licence: | ||
| - "GPL-3.0-or-later" | ||
| identifier: "" | ||
| input: | ||
| - - meta: | ||
| type: map | ||
| description: Groovy Map containing sample information. e.g. `[ id:'sample1' ]` | ||
| - taskdir: | ||
| type: directory | ||
| description: | | ||
| The `*.l1o_tasks` directory produced by `sativaepang/lootasks`: one | ||
| subdirectory per fold (`ref.nwk`, `ref.fasta`, `query.fasta`) plus a | ||
| `manifest.json`. | ||
| pattern: "*.l1o_tasks" | ||
| output: | ||
| taskdir: | ||
| - - meta: | ||
| type: map | ||
| description: Groovy Map containing sample information. e.g. `[ id:'sample1' ]` | ||
| - taskdir: | ||
| type: directory | ||
| description: | | ||
| The same taskdir, with an `epa_result.jplace` (plus `epang.log` and | ||
| `epa_info.log`) added to every fold subdirectory. Input to | ||
| `sativaepang/looscore`. | ||
| pattern: "*.l1o_tasks" | ||
| versions_sativaepang: | ||
| - - ${task.process}: | ||
| type: string | ||
| description: The name of the process | ||
| - sativaepang: | ||
| type: string | ||
| description: The name of the tool | ||
| - sed -n 's#.*share/sativa-epang-\([0-9.]*\)-.*#\1#p' \$(command -v sativa-epang): | ||
| type: eval | ||
| description: The expression to obtain the version of the tool | ||
|
|
||
| topics: | ||
| versions: | ||
| - - ${task.process}: | ||
| type: string | ||
| description: The name of the process | ||
| - sativaepang: | ||
| type: string | ||
| description: The name of the tool | ||
| - sed -n 's#.*share/sativa-epang-\([0-9.]*\)-.*#\1#p' \$(command -v sativa-epang): | ||
| type: eval | ||
| description: The expression to obtain the version of the tool | ||
|
|
||
| authors: | ||
| - "@erikrikarddaniel" | ||
| maintainers: | ||
| - "@erikrikarddaniel" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| nextflow_process { | ||
|
|
||
| name "Test Process SATIVAEPANG_LOOPLACE" | ||
| script "../main.nf" | ||
| process "SATIVAEPANG_LOOPLACE" | ||
|
|
||
| tag "modules" | ||
| tag "modules_nfcore" | ||
| tag "sativaepang" | ||
| tag "sativaepang/lootasks" | ||
| tag "sativaepang/looplace" | ||
|
|
||
| test("sativa-epang tiny example") { | ||
|
|
||
| setup { | ||
| run("SATIVAEPANG_LOOTASKS") { | ||
| script "../../lootasks/main.nf" | ||
| process { | ||
| """ | ||
| input[0] = [ | ||
| [ id:'test' ], | ||
| file(params.modules_testdata_base_path + 'delete_me/sativaepang/sativaepang_tiny.refjson', checkIfExists: true), | ||
| file(params.modules_testdata_base_path + 'delete_me/sativaepang/sativaepang_tiny.model', checkIfExists: true) | ||
| ] | ||
| """ | ||
| } | ||
| } | ||
| } | ||
|
|
||
| when { | ||
| process { | ||
| """ | ||
| input[0] = SATIVAEPANG_LOOTASKS.out.taskdir | ||
| """ | ||
| } | ||
| } | ||
|
|
||
| then { | ||
| // Every fold in the returned taskdir must have a jplace, not just process.success. | ||
| // (Separately verified by hand, not expressible cleanly here: the upstream | ||
| // SATIVAEPANG_LOOTASKS task's own directory on disk is left untouched -- this | ||
| // module stages a private, writable copy rather than mutating the upstream | ||
| // task's output in place, the same class of -resume-breaking bug fixed in | ||
| // nf-core/modules#12799.) | ||
| // EPA-ng's placement likelihoods aren't byte-reproducible between the conda | ||
| // environment and the container builds (confirmed: identical logs/inputs, | ||
| // differing epa_result.jplace content). epa_info.log/epang.log also embed a | ||
| // wall-clock "Elapsed Time: Ns" line that flips between runs under load, on any | ||
| // engine. Mask all three in the snapshot -- same precedent as | ||
| // sigprofiler/snapaligner's unstablePatterns usage -- and rely on the structural | ||
| // asserts below for the guarantee this module actually makes. | ||
| def taskdir = file(process.out.taskdir[0][1]) | ||
| def foldDirs = taskdir.listFiles().findAll { it.isDirectory() && it.name.startsWith("fold_") } | ||
| assertAll( | ||
| { assert process.success }, | ||
| { assert foldDirs.size() > 0 }, | ||
| { assert foldDirs.every { new File(it.toString(), "epa_result.jplace").exists() } }, | ||
| { assert snapshot(sanitizeOutput(process.out, unstablePatterns: ["**/epa_result.jplace", "**/epa_info.log", "**/epang.log"])).match() } | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| test("gtdb archaea 16S") { | ||
|
|
||
| setup { | ||
| run("SATIVAEPANG_LOOTASKS") { | ||
| script "../../lootasks/main.nf" | ||
| process { | ||
| """ | ||
| input[0] = [ | ||
| [ id:'test' ], | ||
| file(params.modules_testdata_base_path + 'delete_me/sativaepang/gtdb_archaea_16s.refjson', checkIfExists: true), | ||
| file(params.modules_testdata_base_path + 'delete_me/sativaepang/gtdb_archaea_16s.model', checkIfExists: true) | ||
| ] | ||
| """ | ||
| } | ||
| } | ||
| } | ||
|
|
||
| when { | ||
| process { | ||
| """ | ||
| input[0] = SATIVAEPANG_LOOTASKS.out.taskdir | ||
| """ | ||
| } | ||
| } | ||
|
|
||
| then { | ||
| def taskdir = file(process.out.taskdir[0][1]) | ||
| def foldDirs = taskdir.listFiles().findAll { it.isDirectory() && it.name.startsWith("fold_") } | ||
| assertAll( | ||
| { assert process.success }, | ||
| { assert foldDirs.size() > 0 }, | ||
| { assert foldDirs.every { new File(it.toString(), "epa_result.jplace").exists() } }, | ||
| { assert snapshot(sanitizeOutput(process.out, unstablePatterns: ["**/epa_result.jplace", "**/epa_info.log", "**/epang.log"])).match() } | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| test("sativa-epang tiny example - stub") { | ||
|
|
||
| options "-stub" | ||
|
|
||
| setup { | ||
| run("SATIVAEPANG_LOOTASKS") { | ||
| script "../../lootasks/main.nf" | ||
| process { | ||
| """ | ||
| input[0] = [ | ||
| [ id:'test' ], | ||
| file(params.modules_testdata_base_path + 'delete_me/sativaepang/sativaepang_tiny.refjson', checkIfExists: true), | ||
| file(params.modules_testdata_base_path + 'delete_me/sativaepang/sativaepang_tiny.model', checkIfExists: true) | ||
| ] | ||
| """ | ||
| } | ||
| } | ||
| } | ||
|
|
||
| when { | ||
| process { | ||
| """ | ||
| input[0] = SATIVAEPANG_LOOTASKS.out.taskdir | ||
| """ | ||
| } | ||
| } | ||
|
|
||
| then { | ||
| assertAll( | ||
| { assert process.success }, | ||
| { assert snapshot(process.out).match() } | ||
| ) | ||
| } | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.