Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
VinzentRisch committed Jul 16, 2024
2 parents c9a12a9 + 38e48b5 commit b215266
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 14 deletions.
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ To install _q2-amr_, follow the steps described below.
mamba create -yn q2-amr \
-c https://packages.qiime2.org/qiime2/2024.2/shotgun/released/ \
-c qiime2 -c conda-forge -c bioconda -c defaults \
qiime2 q2cli q2templates q2-types q2-feature-table q2-demux rgi tqdm
qiime2 q2cli q2templates q2-types q2-feature-table q2-demux rgi tqdm ncbi-amrfinderplus

conda activate q2-amr

Expand All @@ -38,7 +38,7 @@ qiime info
CONDA_SUBDIR=osx-64 mamba create -yn q2-amr \
-c https://packages.qiime2.org/qiime2/2024.2/shotgun/released/ \
-c qiime2 -c conda-forge -c bioconda -c defaults \
qiime2 q2cli q2templates q2-types q2-feature-table q2-demux rgi tqdm
qiime2 q2cli q2templates q2-types q2-feature-table q2-demux rgi tqdm ncbi-amrfinderplus

conda activate q2-amr
conda config --env --set subdir osx-64
Expand All @@ -57,19 +57,20 @@ qiime info

## Functionality
This QIIME 2 plugin contains actions used to annotate short single/paired-end
sequencing reads and MAGs with antimicrobial resistance genes. Currently, the [CARD](https://card.mcmaster.ca) database is supported (for details on
the implementation and usage, please refer to the [rgi](https://github.com/arpcard/rgi) documentation). Below you will
sequencing reads and MAGs with antimicrobial resistance genes. Currently, the tools [RGI](https://github.com/arpcard/rgi) and [AMRFinderPlus](https://github.com/ncbi/amr) are supported (for details on
the implementation and usage, please refer to the documentation of the tools). Below you will
find an overview of actions available in the plugin.

| Action | Description | Underlying tool | Used function |
|-----------------------|--------------------------------------------------------------------------------------|---------------------------------------|--------------------------------------|
| fetch-card-db | Download and preprocess CARD and WildCARD data. | [rgi](https://github.com/arpcard/rgi) | card_annotation, wildcard_annotation |
| annotate-mags-card | Annotate MAGs with antimicrobial resistance gene information from CARD. | [rgi](https://github.com/arpcard/rgi) | main, load |
| annotate-reads-card | Annotate metagenomic reads with antimicrobial resistance gene information from CARD. | [rgi](https://github.com/arpcard/rgi) | bwt, load |
| heatmap | Create a heatmap from annotate-mags-card output files. | [rgi](https://github.com/arpcard/rgi) | heatmap |
| kmer-query-mags-card | Pathogen-of-origin prediction for ARGs in MAGs. | [rgi](https://github.com/arpcard/rgi) | kmer-query, load |
| kmer-query-reads-card | Pathogen-of-origin prediction for ARGs in reads. | [rgi](https://github.com/arpcard/rgi) | kmer-query, load |
| kmer-build-card | Build a kmer database with a custom kmer length. | [rgi](https://github.com/arpcard/rgi) | kmer-build |
| Action | Description | Underlying tool | Used function |
|-------------------------|--------------------------------------------------------------------------------------|----------------------------------------------|--------------------------------------|
| fetch-card-db | Download and preprocess CARD and WildCARD data. | [rgi](https://github.com/arpcard/rgi) | card_annotation, wildcard_annotation |
| annotate-mags-card | Annotate MAGs with antimicrobial resistance gene information from CARD. | [rgi](https://github.com/arpcard/rgi) | main, load |
| annotate-reads-card | Annotate metagenomic reads with antimicrobial resistance gene information from CARD. | [rgi](https://github.com/arpcard/rgi) | bwt, load |
| heatmap | Create a heatmap from annotate-mags-card output files. | [rgi](https://github.com/arpcard/rgi) | heatmap |
| kmer-query-mags-card | Pathogen-of-origin prediction for ARGs in MAGs. | [rgi](https://github.com/arpcard/rgi) | kmer-query, load |
| kmer-query-reads-card | Pathogen-of-origin prediction for ARGs in reads. | [rgi](https://github.com/arpcard/rgi) | kmer-query, load |
| kmer-build-card | Build a kmer database with a custom kmer length. | [rgi](https://github.com/arpcard/rgi) | kmer-build |
| fetch-amrfinderplus-db | Download AMRFinderPlus database. | [AMRFinderPlus](https://github.com/ncbi/amr) | -u |

## Dev environment
This repository follows the _black_ code style. To make the development slightly easier
Expand Down
1 change: 1 addition & 0 deletions ci/recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ requirements:
- setuptools

run:
- ncbi-amrfinderplus
- python=3.8.*
- qiime2 {{ qiime2_epoch }}.*
- q2-demux {{ qiime2_epoch }}.*
Expand Down
50 changes: 50 additions & 0 deletions q2_amr/amrfinderplus/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import os
import re
import subprocess

from qiime2.util import duplicate

from q2_amr.amrfinderplus.types import AMRFinderPlusDatabaseDirFmt
from q2_amr.card.utils import run_command


def fetch_amrfinderplus_db() -> AMRFinderPlusDatabaseDirFmt:
amrfinderplus_db = AMRFinderPlusDatabaseDirFmt()

# Run "amrfinder -u" command that downloads the database
run_amrfinder_u()

# Define path where the database will be downloaded to
conda_prefix = os.getenv("CONDA_PREFIX")
amrfinder_db_path = os.path.join(
conda_prefix, "share", "amrfinderplus", "data", "latest"
)

# Copy all files from amrfinder_db_path to database directory format
_copy_all(amrfinder_db_path, amrfinderplus_db.path)

return amrfinderplus_db


def _copy_all(src_dir, des_dir):
regex = re.compile(r".*(?:AMR_CDS|changes).*")
# Loop over all files in the source directory
for file in os.listdir(src_dir):
# Check if the filename does not match the regex pattern and copy the file
# from src to des. Files matching the pattern are not needed for the database.
if not regex.match(file):
duplicate(os.path.join(src_dir, file), os.path.join(des_dir, file))


def run_amrfinder_u():
# The command "amrfinder -u" downloads the latest amrfinderplus database or
# updates it
cmd = ["amrfinder", "-u"]
try:
run_command(cmd, verbose=True)
except subprocess.CalledProcessError as e:
raise Exception(
"An error was encountered while running AMRFinderPlus, "
f"(return code {e.returncode}), please inspect "
"stdout and stderr to learn more."
)
52 changes: 52 additions & 0 deletions q2_amr/amrfinderplus/tests/test_database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import os
import subprocess
from unittest.mock import patch

from qiime2.plugin.testing import TestPluginBase

from q2_amr.amrfinderplus.database import (
_copy_all,
fetch_amrfinderplus_db,
run_amrfinder_u,
)


class TestFetchAMRFinderPlusDB(TestPluginBase):
package = "q2_amr.amrfinderplus.tests"

@patch("q2_amr.amrfinderplus.database.run_amrfinder_u")
@patch("q2_amr.amrfinderplus.database._copy_all")
def test_fetch_amrfinderplus_db(self, mock_run_amrfinder_u, mock__copy_all):
fetch_amrfinderplus_db()

@patch("q2_amr.amrfinderplus.database.run_command")
def test_run_amrfinder_u(self, mock_run_command):
run_amrfinder_u()
mock_run_command.assert_called_once_with(
["amrfinder", "-u"],
verbose=True,
)

@patch("q2_amr.amrfinderplus.database.run_command")
def test_run_amrfinder_u_error(self, mock_run_command):
expected_message = (
"An error was encountered while running AMRFinderPlus, "
"(return code 1), please inspect stdout and stderr to learn more."
)
mock_run_command.side_effect = subprocess.CalledProcessError(1, "cmd")
with self.assertRaises(Exception) as cm:
run_amrfinder_u()
self.assertEqual(str(cm.exception), expected_message)

def test__copy_all(self):
tmp = self.temp_dir.name
os.mkdir(os.path.join(tmp, "src"))
os.mkdir(os.path.join(tmp, "des"))

with open(os.path.join(tmp, "src", "a"), "w"), open(
os.path.join(tmp, "src", "AMR_CDS.nto"), "w"
):
pass

_copy_all(os.path.join(tmp, "src"), os.path.join(tmp, "des"))
self.assertTrue(os.path.exists(os.path.join(tmp, "des", "a")))
2 changes: 1 addition & 1 deletion q2_amr/card/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
)


def run_command(cmd, cwd, verbose=True):
def run_command(cmd, cwd=None, verbose=True):
if verbose:
print(EXTERNAL_CMD_WARNING)
print("\nCommand:", end=" ")
Expand Down
11 changes: 11 additions & 0 deletions q2_amr/citations.bib
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,14 @@ @article{alcock_card_2023
keywords = {*Data Curation, *Databases, Factual, *Drug Resistance, Microbial, *Machine Learning, Anti-Bacterial Agents/pharmacology, Genes, Bacterial, Likelihood Functions, Molecular Sequence Annotation, Software},
pages = {D690--D699},
}

@article{feldgarden2021amrfinderplus,
title={AMRFinderPlus and the Reference Gene Catalog facilitate examination of the genomic links among antimicrobial resistance, stress response, and virulence},
author={Feldgarden, Michael and Brover, Vyacheslav and Gonzalez-Escalona, Narjol and Frye, Jonathan G and Haendiges, Julie and Haft, Daniel H and Hoffmann, Maria and Pettengill, James B and Prasad, Arjun B and Tillman, Glenn E and others},
journal={Scientific reports},
volume={11},
number={1},
pages={12728},
year={2021},
publisher={Nature Publishing Group UK London}
}
15 changes: 15 additions & 0 deletions q2_amr/plugin_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from qiime2.plugin import Citations, Plugin

from q2_amr import __version__
from q2_amr.amrfinderplus.database import fetch_amrfinderplus_db
from q2_amr.amrfinderplus.sample_data import annotate_sample_data_amrfinderplus
from q2_amr.amrfinderplus.types._format import (
AMRFinderPlusAnnotationDirFmt,
Expand Down Expand Up @@ -1084,6 +1085,20 @@
" size",
citations=[citations["alcock_card_2023"]],
)
plugin.methods.register_function(
function=fetch_amrfinderplus_db,
inputs={},
parameters={},
outputs=[("amrfinderplus_db", AMRFinderPlusDatabase)],
input_descriptions={},
parameter_descriptions={},
output_descriptions={
"amrfinderplus_db": "AMRFinderPlus database.",
},
name="Download AMRFinderPlus database.",
description="Download the latest version of the AMRFinderPlus database.",
citations=[citations["feldgarden2021amrfinderplus"]],
)

organisms = [
"Acinetobacter_baumannii",
Expand Down

0 comments on commit b215266

Please sign in to comment.