Package bpm :: Module faclient
[hide private]
[frames] | no frames]

Source Code for Module bpm.faclient

  1  """ 
  2  A client class for the FuncAssociate web service at 
  3   
  4  http://llama.mshri.on.ca/cgi/funcassociate/serv 
  5   
  6  The documentation of the FuncAssociate API may be found at 
  7   
  8  http://llama.mshri.on.ca/funcassociate/doc 
  9   
 10   
 11  COPYRIGHT AND LICENSE 
 12   
 13  Copyright (c) 2010, President and Fellows of Harvard College and 
 14  Gabriel Berriz gberriz@hms.harvard.edu.  All rights reserved. 
 15   
 16  This module is distributed as "The Program" under the Harvard 
 17  University End-User License Agreement. 
 18  http://llama.mshri.on.ca/license.html. 
 19  """ 
 20   
 21  # -*- mode: python -*- 
 22  ################################################################ 
 23  # funcassociate/client.py 
 24  # 
 25  # Copyright (c) 2010 President and Fellows of Harvard College 
 26  # and Gabriel F. Berriz (gberriz@hms.harvard.edu).  All rights 
 27  # reserved. 
 28  ################################################################ 
 29   
 30  import re 
 31  import signal 
 32  import socket 
 33  from inspect import getargspec 
 34   
 35  import httplib 
 36   
 37  import json 
 38   
 39  # ----------------------------------------------------------------------------- 
 40   
 41  DEFAULT_SERVICE_HOST = 'http://llama.mshri.on.ca' 
 42  DEFAULT_SERVICE_URL = '/cgi/funcassociate/serv' 
43 44 # ----------------------------------------------------------------------------- 45 46 -class ServiceError(Exception):
47 """ 48 Exception raised when the response from server includes a non-null 49 error. 50 """
51
52 -class NetworkError(ServiceError):
53 """ 54 Exception raised when server fails to respond to a ping request. 55 """
56
57 -class TimeoutError(ServiceError):
58 """ 59 Exception raised when response from the server fails to arrive 60 within the prescribed time interval. 61 """
62
63 -class InputError(Exception):
64 """ 65 Exception raised by functionate method upon detecting bad inputs 66 from user. 67 """
68
69 -class _fc(object):
70 host = DEFAULT_SERVICE_HOST 71 url = DEFAULT_SERVICE_URL 72 headers = { 73 'Content-type': 'application/json', 74 } 75 timeout = 180 76
77 - def __init__(self, host=host, url=url, timeout=None):
78 self.host = re.sub("\Ahttps?://", "", host) 79 self.url = re.sub("\Ahttps?://[^/]+/", "", url) 80 81 self.timeout = 30 82 try: 83 if self.ping() != "OK": 84 raise ValueError() 85 except (socket.gaierror, ValueError): 86 raise NetworkError("No response from %s%s" % (host, url)) 87 88 if timeout is None: 89 timeout = _fc.timeout 90 91 try: 92 self.timeout = int(timeout) 93 assert self.timeout > 0 94 except: 95 raise ValueError("timeout parameter must be a positive number") 96 97 return
98 99 @staticmethod
100 - def _timeout(signo, frame):
101 raise TimeoutError()
102
103 - def _make_request(self, method, params=[]):
104 """ 105 Make a request to the Funcassociate web service. 106 107 @return: result 108 """ 109 conn = httplib.HTTPConnection(self.host) 110 payload = json.dumps({'method': method, 'params': params, 'id': 0}) 111 112 conn.request("POST", self.url, body=payload, 113 headers=_fc.headers) 114 115 hold = signal.signal(signal.SIGALRM, _fc._timeout) 116 if self.timeout > 0: 117 signal.alarm(self.timeout) 118 try: 119 try: 120 response = conn.getresponse() 121 signal.alarm(0) 122 except TimeoutError: 123 signal.alarm(0) 124 raise TimeoutError("Request to %s timed out" % self.host) 125 finally: 126 signal.signal(signal.SIGALRM, hold) 127 128 conn.close() 129 response_data = response.read() 130 decoded_response = json.loads(response_data) 131 132 if decoded_response['error']: 133 raise ServiceError(str(decoded_response['error']['message'])) 134 return decoded_response['result']
135 136 @staticmethod
137 - def _check_args(f, given):
138 spec = getargspec(f) 139 formals = spec[0] 140 defaults = spec[3] 141 # we disregard the first argument, self; hence the decrement 142 # by 1 below 143 max_ = len(formals) - 1 144 if defaults is None: 145 min_ = max_ 146 else: 147 min_ = max_ - len(defaults) 148 qual = None 149 150 if given < min_: 151 if max_ > min_: 152 qual = "at least %d" % min_ 153 else: 154 qual = "exactly %d" % min_ 155 if min_ > 1: 156 s = "s" 157 else: 158 s = "" 159 elif given > max_: 160 if max_ > min_: 161 qual = "at most %d" % max_ 162 elif max_ > 0: 163 qual = "exactly %d" % max_ 164 else: 165 qual = "no" 166 if max_ == 1: 167 s = "" 168 else: 169 s = "s" 170 171 if qual is not None: 172 raise TypeError("%s() takes %s " 173 "argument%s (%d given)" % 174 (f.__name__, qual, s, given))
175
176 - def _decorate(f):
177 def wrapper(self, *args): 178 _fc._check_args(f, len(args)) 179 return self._make_request(f.__name__, args)
180 return wrapper
181 182 @_decorate
183 - def available_species(self):
184 """ 185 @return: List of species supported by Funcassociate. 186 service. 187 """
188 189 @_decorate
190 - def available_namespaces(self, species):
191 """ 192 @return: List of namespaces supported by Funcassociate for the 193 given species. 194 """
195 196 @_decorate
197 - def go_associations(self, species, namespace, support=None):
198 """ 199 @return: List of GO associations used by Funcassociate 200 for the specified species, namespace, and support 201 """
202 203 @_decorate
204 - def go_attrib_dict(self):
205 """ 206 @return: Dictionary whose keys are GO attribute IDs and whose 207 values are their corresponding human-readable names. 208 """
209 210 @_decorate
211 - def version(self):
212 """ 213 @return: Version of Funcassociate server. 214 """
215 216 @_decorate
217 - def ping(self):
218 """ 219 @return: The string "OK". 220 """
221 222 @_decorate
223 - def fail(self):
224 """ 225 @return: nothing. 226 """
227
228 - def functionate(self, query=None, associations=None, 229 attrib_dict=None, species=None, namespace=None, 230 genespace=None, mode=None, which=None, 231 cutoff=None, reps=None):
232 """ 233 @return: functionate results structure 234 """ 235 params = locals() 236 del params['self'] 237 keys = params.keys() 238 for k in keys: 239 if params[k] is None: 240 del params[k] 241 result = self._make_request('functionate', [params]) 242 243 if result.has_key("input_error"): 244 raise InputError(result["input_error"]) 245 246 return result
247 248 FuncassociateClient = _fc 249 250 if '__main__' == __name__: 251 c = _fc() 252 response = c.functionate(query=("YBL071W-A", "YCL055W", "YCR094W", 253 "YDL127W", "YFL029C", "YGR271C-A", 254 "YHR099W", "YJR066W", "YKL203C", 255 "YNL289W"), 256 species="Saccharomyces cerevisiae", 257 namespace="sgd_systematic") 258 259 print "OVERREPRESENTED ATTRIBUTES" 260 261 headers = ("N", "X", "LOD", "P", "P_adj", "attrib ID", "attrib name") 262 print "\t".join(headers) 263 264 info = response["request_info"] 265 reps = info["reps"] 266 below_detection_threshhold = "< %f" % (1.0/float(reps)) 267 268 for row in response["over"]: 269 row.pop(1) 270 if row[4] is 0: 271 row[4] = below_detection_threshhold 272 print "\t".join(map(str, row)) 273 274 print "\nREQUEST INFO" 275 for k in info.keys(): 276 print "%s: %s" % (k, info[k]) 277