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
22
23
24
25
26
27
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'
47 """
48 Exception raised when the response from server includes a non-null
49 error.
50 """
51
53 """
54 Exception raised when server fails to respond to a ping request.
55 """
56
58 """
59 Exception raised when response from the server fails to arrive
60 within the prescribed time interval.
61 """
62
68
70 host = DEFAULT_SERVICE_HOST
71 url = DEFAULT_SERVICE_URL
72 headers = {
73 'Content-type': 'application/json',
74 }
75 timeout = 180
76
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
102
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
138 spec = getargspec(f)
139 formals = spec[0]
140 defaults = spec[3]
141
142
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
180 return wrapper
181
182 @_decorate
184 """
185 @return: List of species supported by Funcassociate.
186 service.
187 """
188
189 @_decorate
191 """
192 @return: List of namespaces supported by Funcassociate for the
193 given species.
194 """
195
196 @_decorate
198 """
199 @return: List of GO associations used by Funcassociate
200 for the specified species, namespace, and support
201 """
202
203 @_decorate
205 """
206 @return: Dictionary whose keys are GO attribute IDs and whose
207 values are their corresponding human-readable names.
208 """
209
210 @_decorate
212 """
213 @return: Version of Funcassociate server.
214 """
215
216 @_decorate
218 """
219 @return: The string "OK".
220 """
221
222 @_decorate
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