#!/www/html/D-I-TASSER/conda-envs/DIT-py3/bin/python3.9
#coding: utf-8
###** html/query.cgi - Query result page ******************************
###
### Copyright © 2014 Regents of the University of Michigan
###
### All rights reserved.
"""Generate a query result CGI page"""
import inspect
import os.path
import sys
__CURRENT_FILE = inspect.getfile(inspect.currentframe())
__CURRENT_DIR = os.path.dirname(os.path.realpath(__CURRENT_FILE))
__BASE_PATH = __CURRENT_DIR
sys.path.append(os.path.join(__BASE_PATH, "src"))
from dbquery import DatabaseQuery
from glass import GlassWebMod
from sanitize import Sanitizer
##** Constants ********************************************************
## Entries per page
_ENTRIES_PER_PAGE = 5000
#_ENTRIES_PER_PAGE = 20
## Query target dataset
_QD_GPCR = 0
_QD_LIGAND = 1
_QD_GLASS = 2
_QD = ["gpcr", "ligand", "assoc"]
_QD_LEN = [3, 7, 1]
_QD_STR = ["GPCRs", "ligands", "associations"]
## Data sources
_SOURCE = ("ChEMBL", "IUPHAR", "DrugBank", "PDSP", "BindingDB")
##** Exception class **************************************************
class QueryNotMatchError(RuntimeError):
"""Raise an exception when a query matches nothing."""
pass
class MalformedQueryError(RuntimeError):
"""Raise an exception when a query is found malformed."""
pass
##** Query report class ***********************************************
class GlassQuery(GlassWebMod):
"""Generate a query result page."""
## Initialisation
def __init__(self):
"""Initialise a Class object."""
GlassWebMod.__init__(self)
self._query = DatabaseQuery()
self._sanitize = Sanitizer()
self._keyword = None
self._dataset = None
self._redirect_url = None
self._title = None
self._table = dict()
self._results = None
## Database query
def _determine_dataset(self):
"""Determine the query target dataset."""
try:
dataset = self.value("dataset")[-1].strip()
except:
raise MalformedQueryError()
if dataset == "Search by GPCR":
self._dataset = _QD_GPCR
elif dataset == "Search by ligand":
self._dataset = _QD_LIGAND
elif dataset == "Search by GLASS ID":
self._dataset = _QD_GLASS
else:
raise MalformedQueryError()
def _check_ligand_ro5(self, ligand):
"""Check Lipinski's rule of five for a ligand."""
if (ligand["h_don"] > 5 or ligand["h_acc"] > 10 or
ligand["mw"] > 500):
return self.format("ligand_ro5_no")
elif ligand["log_p"] is None:
return self.format("na")
elif ligand["log_p"] > 5:
return self.format("ligand_ro5_no")
else:
return self.format("ligand_ro5_yes")
def _redirect(self):
"""Set up redirection."""
dest = self._query._query.fetchone()
if self._dataset == _QD_GPCR:
self._redirect_url = "gpcr.cgi?id=" + str(
dest["uniprot"])
elif self._dataset == _QD_LIGAND:
self._redirect_url = "ligand.cgi?id=" + str(
dest["inchi_key"])
elif self._dataset == _QD_GLASS:
self._redirect_url = "assoc.cgi?id=" + str(
dest["glass"])
def _generate_content(self):
"""Execute the SQL browsing procedure."""
result = self._query._query
count = result.rowcount
if count == 0:
raise QueryNotMatchError()
elif count == 1:
self._redirect()
return
try:
page = int(self.value("page")[-1].strip())
except:
page = 1
if page < 2:
page = 1
if count < (page - 1) * _ENTRIES_PER_PAGE:
page = count // _ENTRIES_PER_PAGE + 1
if page == 1:
self._table["first"] = " disabled=\"disabled\""
else:
self._table["first"] = str()
if count < page * _ENTRIES_PER_PAGE:
self._table["last"] = " disabled=\"disabled\""
else:
self._table["last"] = str()
if page != 1:
result.fetchmany((page - 1) * _ENTRIES_PER_PAGE)
self._results = result.fetchmany(_ENTRIES_PER_PAGE)
if self._dataset == _QD_LIGAND:
for ligand in self._results:
print(ligand, file=sys.stderr)
ligand["ro5"] = self._check_ligand_ro5(ligand)
if ligand["log_p"] is None:
ligand["log_p"] = self.format("na")
#if ligand["iupac"] is None:
# ligand["iupac"] = self.format("na")
if ligand["h_acc"] is None:
ligand["h_acc"] = self.format("na")
if ligand["h_don"] is None:
ligand["h_don"] = self.format("na")
self._table["action"] = "query.cgi"
self._table["num"] = count
self._table["npage"] = count // _ENTRIES_PER_PAGE + 1
self._table["page"] = page
self._table["form"] = self.format("query_hidden",
name="dataset", value=self.value("dataset")[-1])
try:
self._table["form"] += self.format(
"query_hidden", name="query",
value=self.value("query")[-1].strip())
except:
pass
def prepare(self):
"""Search the database and decide whether to redirect."""
try:
self._determine_dataset()
try:
query = self.value("query")[-1].strip()
except:
query = None
if query:
templ = _QD[self._dataset].join(("query_", "_title"))
query = self._sanitize.sanitizeQuery(query)
self._title = self.format(templ, query)
args = [query] * _QD_LEN[self._dataset]
self._query.call(_QD[self._dataset] + "_simple", *args)
else:
templ = _QD[self._dataset].join(("browse_", "_title"))
self._title = self.format(templ)
self._query.call(_QD[self._dataset] + "_browse")
self._generate_content()
except QueryNotMatchError:
self.log_error()
self.error_info = ("err_query", )
except TypeError:
self.log_error()
self.error_info = ("err_bad_query", )
except MalformedQueryError:
self.log_error()
self.error_info = ("err_bad_query", )
# except:
# self.log_error()
# self.error_info = ("err_internal", )
except Exception as e:
import traceback
with open("/www/html/GLASS/glass_query_debug.log", "w") as f:
f.write("=== Internal error caught ===\n")
f.write(traceback.format_exc())
self.log_error()
self.error_info = ("err_internal", )
## Response
def response(self):
"""Return the GLASS query web content."""
self.prepare()
if self.error_info is not None:
self.make_error_page(self.format(*self.error_info))
return
if self._redirect_url is not None:
self.redirect(self._redirect_url)
return
template = _QD[self._dataset].join(("query_", "_res"))
code = list()
for entry in self._results:
code.append(self.format(template, **entry))
self._table["body"] = "".join(code)
template = "query_" + _QD[self._dataset]
code = self.format(template, **self._table)
self.make_page(self._title, code)
##** Main routine *****************************************************
if __name__ == "__main__":
with GlassQuery() as page:
# print("Content-type: text/html\n")
page.response()