#!/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()