Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
mashehu authored Nov 7, 2024
2 parents 20a7c91 + 033f2f2 commit 432351b
Show file tree
Hide file tree
Showing 6 changed files with 369 additions and 42 deletions.
117 changes: 75 additions & 42 deletions .github/scripts/wave_singularity.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,86 @@
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "httpx",
# "requests",
# "rich",
# ]
# ///

import logging

import httpx
import requests
import rich_click as click
from rich.logging import RichHandler

# Replace the basic logger setup with rich logging
logging.basicConfig(
level=logging.INFO,
format="%(message)s",
handlers=[
RichHandler(
rich_tracebacks=True,
show_time=False,
markup=True,
)
],
)
logger = logging.getLogger(__name__)
click.rich_click.SHOW_ARGUMENTS = True

image_url = "oras://community.wave.seqera.io/library/pybedtools_bedtools_htslib_pip_pypints:aa20de1f1b5ddb30"

if image_url.startswith("oras://"):
image_url = image_url.replace("oras://", "")

wave_api_url = "https://wave.seqera.io"
url = f"{wave_api_url}/v1alpha1/inspect"

# if platform_pat:
# data["toweraccesstoken"] = platform_pat
# else:
# TODO
logger.warning("'platform_pat' not set, no auth to wave back end")

try:
logger.info(f"calling image inspect at {url} for image url {image_url}")
response = httpx.post(
url=url,
json={"containerImage": image_url},
headers={"content-type": "application/json"},
)

data = response.json()
logger.debug(data)
layers = data.get("container", {}).get("manifest", {}).get("layers", [])
is_singularity = len(layers) == 1 and layers[0].get("mediaType", "").endswith(".sif")
if not is_singularity:
print(layers)
raise ValueError("not a singularity image")
if "digest" not in layers[0]:
print(layers)
raise ValueError("no 'digest' in first layer found")

digest = layers[0]["digest"].replace("sha256:", "")
container_url = f"https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/{digest[:2]}/{digest}/data"
print(container_url)

except httpx.RequestError as exc:
print(f"An error occurred while requesting {exc.request.url!r}.")
print("No singularity image for you")

@click.command()
@click.option(
"--platform-pat",
envvar="SEQERA_ACCESS_TOKEN",
show_envvar=True,
help="Platform authentication token",
)
@click.argument("image_name")
def main(image_name, platform_pat):
"""Script to return a HTTPS Singularity image URL from Seqera Containers."""

if image_name.startswith("oras://"):
image_name = image_name.replace("oras://", "")

wave_api_url_base = "https://wave.seqera.io"
wave_api_url = f"{wave_api_url_base}/v1alpha1/inspect"
container_url_base = "https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256"

request_data = {"containerImage": image_name}
if platform_pat:
request_data["toweraccesstoken"] = platform_pat
else:
logger.debug("'--platform-pat' / '$TOWER_ACCESS_TOKEN' not set, no auth to wave back end")

try:
logger.debug(f"Calling image inspect at {wave_api_url} for image url '{image_name}'")
response = requests.post(
url=wave_api_url,
json=request_data,
headers={"content-type": "application/json"},
)

data = response.json()
logger.debug(data)
layers = data.get("container", {}).get("manifest", {}).get("layers", [])
is_singularity = len(layers) == 1 and layers[0].get("mediaType", "").endswith(".sif")
logger.debug(layers)
if not is_singularity:
raise ValueError("Not a singularity image")
if "digest" not in layers[0]:
raise ValueError("no 'digest' in first layer found")

digest = layers[0]["digest"].replace("sha256:", "")
container_url = f"{container_url_base}/{digest[:2]}/{digest}/data"
print(container_url)

except requests.RequestException as exc:
raise ValueError(f"An error occurred while requesting {wave_api_url}\n {exc}")


if __name__ == "__main__":
try:
main()
except ValueError as exc:
logger.error(f"[red]{exc}[/red]")
exit(1)
7 changes: 7 additions & 0 deletions modules/nf-core/metamdbg/asm/environment.yml
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::metamdbg=1.0"
62 changes: 62 additions & 0 deletions modules/nf-core/metamdbg/asm/main.nf
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
process METAMDBG_ASM {
tag "${meta.id}"
label 'process_medium'

conda "${moduleDir}/environment.yml"
container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ?
'https://depot.galaxyproject.org/singularity/metamdbg:1.0--hdcf5f25_1':
'biocontainers/metamdbg:1.0--hdcf5f25_1' }"

input:
tuple val(meta), path(reads)
val(input_type)

output:
tuple val(meta), path("*.contigs.fasta.gz"), emit: contigs
tuple val(meta), path("*.metaMDBG.log") , emit: log
path "versions.yml" , emit: versions

when:
task.ext.when == null || task.ext.when

script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"
switch(input_type) {
case "hifi": input = "--in-hifi ${reads}"; break
case "ont" : input = "--in-ont ${reads}" ; break
default:
error("ERROR: input_type must be one of either 'hifi' or 'ont'.")
break
}
"""
metaMDBG asm \\
--threads ${task.cpus} \\
--out-dir . \\
${args} \\
${input}
rm -r tmp/
mv contigs.fasta.gz ${prefix}.contigs.fasta.gz
mv metaMDBG.log ${prefix}.metaMDBG.log
cat <<-END_VERSIONS > versions.yml
"${task.process}":
metamdbg: \$(metaMDBG | grep "Version" | sed 's/ Version: //')
END_VERSIONS
"""

stub:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"
"""
touch ${prefix}.metaMDBG.log
touch ${prefix}.contigs.fasta.gz
cat <<-END_VERSIONS > versions.yml
"${task.process}":
metamdbg: \$(metaMDBG | grep "Version" | sed 's/ Version: //')
END_VERSIONS
"""
}
67 changes: 67 additions & 0 deletions modules/nf-core/metamdbg/asm/meta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json
name: "METAMDBG_ASM"
description: Metagenome assembler for long-read sequences (HiFi and ONT).
keywords:
- assembly
- long reads
- metagenome
- metagenome assembler
tools:
- "metamdbg":
description: "MetaMDBG: a lightweight assembler for long and accurate metagenomics
reads."
homepage: "https://github.com/GaetanBenoitDev/metaMDBG"
documentation: "https://github.com/GaetanBenoitDev/metaMDBG"
tool_dev_url: "https://github.com/GaetanBenoitDev/metaMDBG"
doi: "10.1038/s41587-023-01983-6"
licence: ["MIT"]
identifier: ""

input:
- - meta:
type: map
description: |
Groovy Map containing sample information
e.g. `[ id:'sample1', single_end:false ]`
- reads:
type: file
description: Long read sequence data from ONT or HiFi in fasta format (can be
gzipped)
pattern: "*.{fa,fasta,fa.gz,fasta.gz}"

- - input_type:
type: string
description: Sequencing technology for reads - either "hifi" for PacBio HiFi
reads or "ont" for Oxford Nanopore reads.

output:
- contigs:
- meta:
type: map
description: |
Groovy Map containing sample information
e.g. `[ id:'sample1', single_end:false ]`
- "*.contigs.fasta.gz":
type: file
description: |
Gzipped fasta file containing the assembled contigs from the input
reads.
- log:
- meta:
type: map
description: |
Groovy Map containing sample information
e.g. `[ id:'sample1', single_end:false ]`
- "*.metaMDBG.log":
type: file
description: Log file describing the metaMDBG run.
- versions:
- versions.yml:
type: file
description: File containing software versions
pattern: "versions.yml"
authors:
- "@prototaxites"
maintainers:
- "@prototaxites"
116 changes: 116 additions & 0 deletions modules/nf-core/metamdbg/asm/tests/main.nf.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
nextflow_process {

name "Test Process METAMDBG_ASM"
script "../main.nf"
process "METAMDBG_ASM"

tag "modules"
tag "modules_nfcore"
tag "metamdbg"
tag "metamdbg/asm"

test("metamdbg_asm - ont") {

when {
process {
"""
input[0] = [
[ id:'test', single_end:false ], // meta map
file(params.modules_testdata_base_path + 'genomics/prokaryotes/bacteroides_fragilis/nanopore/fastq/test.fastq.gz', checkIfExists: true),
]
input[1] = "ont"
"""
}
}

then {
assertAll(
{ assert process.success },
// output is stochastic - contig names differ per run
// log file contains nextflow work dir paths
{ assert snapshot(
file(process.out.contigs[0][1]).name,
file(process.out.log[0][1]).name,
process.out.versions
).match() },
{ assert path(process.out.log[0][1]).readLines().last().contains("Done!") }
)
}
}
test("metamdbg_asm - hifi") {

when {
process {
"""
input[0] = [
[ id:'test', single_end:false ], // meta map
file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pacbio/fastq/test_hifi.fastq.gz', checkIfExists: true),
]
input[1] = "hifi"
"""
}
}

then {
assertAll(
{ assert process.success },
// output is stochastic - contig names differ per run
// log file contains nextflow work dir paths
{ assert snapshot(
file(process.out.contigs[0][1]).name,
file(process.out.log[0][1]).name,
process.out.versions
).match() },
{ assert path(process.out.log[0][1]).readLines().last().contains("Done!") }
)
}
}

test("metamdbg_asm - wrong format") {

when {
process {
"""
input[0] = [
[ id:'test', single_end:false ], // meta map
file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pacbio/fastq/test_hifi.fastq.gz', checkIfExists: true),
]
input[1] = "wrong"
"""
}
}

then {
assertAll(
{ assert process.failed },
{ assert process.errorReport.contains("ERROR: input_type must be one of either 'hifi' or 'ont'.") }
)
}

}

test("metamdbg_asm - stub") {

options "-stub"

when {
process {
"""
input[0] = [
[ id:'test', single_end:false ], // meta map
file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pacbio/fastq/test_hifi.fastq.gz', checkIfExists: true),
]
input[1] = "hifi"
"""
}
}

then {
assertAll(
{ assert process.success },
{ assert snapshot(process.out.versions).match("stub_versions") }
)
}

}
}
Loading

0 comments on commit 432351b

Please sign in to comment.