Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def create_app():
annotations_lookup_db.init_app(bar_app)
eplant2_db.init_app(bar_app)
eplant_poplar_db.init_app(bar_app)
eplant_rice_db.init_app(bar_app)
eplant_tomato_db.init_app(bar_app)
poplar_nssnp_db.init_app(bar_app)
tomato_nssnp_db.init_app(bar_app)
Expand Down Expand Up @@ -147,6 +148,7 @@ def create_app():
annotations_lookup_db = SQLAlchemy(metadata=MetaData())
eplant2_db = SQLAlchemy(metadata=MetaData())
eplant_poplar_db = SQLAlchemy(metadata=MetaData())
eplant_rice_db = SQLAlchemy(metadata=MetaData())
eplant_tomato_db = SQLAlchemy(metadata=MetaData())
poplar_nssnp_db = SQLAlchemy(metadata=MetaData())
tomato_nssnp_db = SQLAlchemy(metadata=MetaData())
Expand Down
9 changes: 9 additions & 0 deletions api/models/eplant_rice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from api import eplant_rice_db as db


class GeneAnnotation(db.Model):
__bind_key__ = "eplant_rice"
__tablename__ = "gene_annotation"

gene = db.Column(db.String(20), nullable=False, primary_key=True)
annotation = db.Column(db.String(64000), nullable=False, primary_key=False)
76 changes: 75 additions & 1 deletion api/resources/gene_annotation.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from flask_restx import Namespace, Resource
from flask_restx import Namespace, Resource, fields
from flask import request
from markupsafe import escape
from sqlalchemy.exc import OperationalError
from api.models.eplant_rice import GeneAnnotation as EplantRiceAnnotation
from api.models.eplant_poplar import GeneAnnotation as EplantPoplarAnnotation
from api.models.eplant_tomato import GeneAnnotation as EplantTomatoAnnotation
from api.models.eplant2 import AgiAnnotation, TAIR10, GeneRIFs
from api.utils.bar_utils import BARUtils
from marshmallow import Schema, ValidationError, fields as marshmallow_fields


gene_annotation = Namespace(
Expand All @@ -22,6 +25,7 @@ def get(self, query=""):
annotation_db_list = {
"tomato": EplantTomatoAnnotation,
"poplar": EplantPoplarAnnotation,
"rice": EplantRiceAnnotation,
"arabidopsis": [AgiAnnotation, TAIR10, GeneRIFs],
}

Expand Down Expand Up @@ -105,3 +109,73 @@ def get(self, query=""):
else:
# return first 10 matches
return {"status": "success", "query": query, "result": res[:10]}


anntn_post_ex = gene_annotation.model(
"AntnRiceGenes",
{
"species": fields.String(required=True, example="rice"),
"genes": fields.List(
required=True,
example=["LOC_Os01g01010", "LOC_Os01g01050"],
cls_or_instance=fields.String,
),
},
)


class GeneIntrnsSchema(Schema):
species = marshmallow_fields.String(required=True)
genes = marshmallow_fields.List(cls_or_instance=marshmallow_fields.String)


@gene_annotation.route("/")
class GeneAnnotationPost(Resource):
@gene_annotation.expect(anntn_post_ex)
def post(self, query=""):
"""
Returns gene annotation(s) give a set of gene(s) for a species
Supported species: 'rice'
"""

json_data = request.get_json()

try:
json_data = GeneIntrnsSchema().load(json_data)
except ValidationError as err:
return BARUtils.error_exit(err.messages), 400

species = json_data["species"].lower()
genes = json_data["genes"]

if species == "rice":
for gene in genes:
if not BARUtils.is_rice_gene_valid(gene):
return BARUtils.error_exit("Invalid gene id"), 400

try:
rows = EplantRiceAnnotation.query.filter(
EplantRiceAnnotation.gene.in_(genes)
).all()
if len(rows) == 0:
return (
BARUtils.error_exit(
"No data for the given species/genes"
),
400,
)
else:
print(rows)
res = [
{
"gene": i.gene,
"annotation": i.annotation,
}
for i in rows
]
return BARUtils.success_exit(res)
except OperationalError:
return BARUtils.error_exit("An internal error has occurred."), 500

else:
return BARUtils.error_exit("Invalid species"), 400
1 change: 1 addition & 0 deletions config/BAR_API.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ SQLALCHEMY_BINDS = {
'poplar_nssnp' : 'mysql://root:root@localhost/poplar_nssnp',
'tomato_nssnp' : 'mysql://root:root@localhost/tomato_nssnp',
'eplant_poplar' : 'mysql://root:root@localhost/eplant_poplar',
'eplant_rice' : 'mysql://root:root@localhost/eplant_rice',
'eplant_tomato' : 'mysql://root:root@localhost/eplant_tomato',
'tomato_sequence' : 'mysql://root:root@localhost/tomato_sequence',
'rice_interactions': 'mysql://root:root@localhost/rice_interactions'
Expand Down
60 changes: 60 additions & 0 deletions config/databases/eplant_rice.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
-- MySQL dump 10.13 Distrib 8.0.23, for Linux (x86_64)
--
-- Host: localhost Database: eplant_rice
-- ------------------------------------------------------
-- Server version 8.0.23-3

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Current Database: `eplant_rice`
--

CREATE DATABASE /*!32312 IF NOT EXISTS*/ `eplant_rice` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `eplant_rice`;

--
-- Table structure for table `gene_annotation`
--

DROP TABLE IF EXISTS `gene_annotation`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `gene_annotation` (
`gene` varchar(20) NOT NULL,
`annotation` mediumtext NOT NULL,
PRIMARY KEY (`gene`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `gene_annotation`
--
-- WHERE: 1 limit 5

LOCK TABLES `gene_annotation` WRITE;
/*!40000 ALTER TABLE `gene_annotation` DISABLE KEYS */;
INSERT INTO `gene_annotation` VALUES ('LOC_Os01g01010','protein TBC domain containing protein, expressed'),('LOC_Os01g01030','protein monocopper oxidase, putative, expressed'),('LOC_Os01g01050', 'protein R3H domain containing protein, expressed');
/*!40000 ALTER TABLE `gene_annotation` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2021-06-26 19:08:20
1 change: 1 addition & 0 deletions config/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mysql -u $DB_USER -p$DB_PASS < ./config/databases/poplar_nssnp.sql
mysql -u $DB_USER -p$DB_PASS < ./config/databases/tomato_nssnp.sql
mysql -u $DB_USER -p$DB_PASS < ./config/databases/eplant_poplar.sql
mysql -u $DB_USER -p$DB_PASS < ./config/databases/eplant_tomato.sql
mysql -u $DB_USER -p$DB_PASS < ./config/databases/eplant_rice.sql
mysql -u $DB_USER -p$DB_PASS < ./config/databases/tomato_sequence.sql
mysql -u $DB_USER -p$DB_PASS < ./config/databases/rice_interactions.sql

Expand Down
56 changes: 56 additions & 0 deletions tests/resources/test_gene_annotation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from api import app
from unittest import TestCase
import json


class TestIntegrations(TestCase):
Expand Down Expand Up @@ -36,3 +37,58 @@ def test_keyword_search(self):
"error": "There are no data found for the given query",
}
self.assertEqual(response.json, expected)

def test_post_anntns(self):
"""
This function test retrieving gene annotations for various species' genes via POST.
"""

# Valid request
response = self.app_client.post(
"/gene_annotation/",
json={"species": "rice", "genes": ["LOC_Os01g01010", "LOC_Os01g01050"]},
)
data = json.loads(response.get_data(as_text=True))
expected = {
"wasSuccessful": True,
"data": [
{
"gene": "LOC_Os01g01010",
"annotation": "protein TBC domain containing protein, expressed"
},
{
"gene": "LOC_Os01g01050",
"annotation": "protein R3H domain containing protein, expressed"
}
]
}
self.assertEqual(data, expected)

# Invalid species
response = self.app_client.post(
"/interactions/",
json={"species": "poplar", "genes": ["LOC_Os01g01080", "LOC_Os01g73310"]},
)
data = json.loads(response.get_data(as_text=True))
expected = {"wasSuccessful": False, "error": "Invalid species"}
self.assertEqual(data, expected)

# Invalid gene ID
response = self.app_client.post(
"/interactions/", json={"species": "rice", "genes": ["abc", "xyz"]}
)
data = json.loads(response.get_data(as_text=True))
expected = {"wasSuccessful": False, "error": "Invalid gene id"}
self.assertEqual(data, expected)

# No data for valid gene IDs
response = self.app_client.post(
"/interactions/",
json={"species": "rice", "genes": ["LOC_Os01g01085", "LOC_Os01g52565"]},
)
data = json.loads(response.get_data(as_text=True))
expected = {
"wasSuccessful": False,
"error": "No data for the given species/genes",
}
self.assertEqual(data, expected)