Mercurial > repos > eric-rasche > apollo
comparison webapollo.py @ 5:7610987e0c48 draft
planemo upload for repository https://github.com/TAMU-CPT/galaxy-webapollo commit 29795b77c0d5c7894219b018a92c5ee7818096c3
author | eric-rasche |
---|---|
date | Wed, 01 Mar 2017 22:39:58 -0500 |
parents | d4ae83dedb14 |
children | f9a6e151b3b4 |
comparison
equal
deleted
inserted
replaced
4:23ead6905145 | 5:7610987e0c48 |
---|---|
1 import requests | 1 import requests |
2 import json | 2 import json |
3 import os | 3 import os |
4 import collections | 4 import collections |
5 import StringIO | 5 try: |
6 import StringIO as io | |
7 except: | |
8 import io | |
6 import logging | 9 import logging |
10 import time | |
11 import argparse | |
12 from abc import abstractmethod | |
7 from BCBio import GFF | 13 from BCBio import GFF |
8 from Bio import SeqIO | 14 from Bio import SeqIO |
9 logging.getLogger("requests").setLevel(logging.CRITICAL) | 15 logging.getLogger("requests").setLevel(logging.CRITICAL) |
10 log = logging.getLogger() | 16 log = logging.getLogger() |
11 | 17 |
12 | 18 |
19 ############################################# | |
20 ###### BEGIN IMPORT OF CACHING LIBRARY ###### | |
21 ############################################# | |
22 # This code is licensed under the MIT # | |
23 # License and is a copy of code publicly # | |
24 # available in rev. # | |
25 # e27332bc82f4e327aedaec17c9b656ae719322ed # | |
26 # of https://github.com/tkem/cachetools/ # | |
27 ############################################# | |
28 class DefaultMapping(collections.MutableMapping): | |
29 | |
30 __slots__ = () | |
31 | |
32 @abstractmethod | |
33 def __contains__(self, key): # pragma: nocover | |
34 return False | |
35 | |
36 @abstractmethod | |
37 def __getitem__(self, key): # pragma: nocover | |
38 if hasattr(self.__class__, '__missing__'): | |
39 return self.__class__.__missing__(self, key) | |
40 else: | |
41 raise KeyError(key) | |
42 | |
43 def get(self, key, default=None): | |
44 if key in self: | |
45 return self[key] | |
46 else: | |
47 return default | |
48 | |
49 __marker = object() | |
50 | |
51 def pop(self, key, default=__marker): | |
52 if key in self: | |
53 value = self[key] | |
54 del self[key] | |
55 elif default is self.__marker: | |
56 raise KeyError(key) | |
57 else: | |
58 value = default | |
59 return value | |
60 | |
61 def setdefault(self, key, default=None): | |
62 if key in self: | |
63 value = self[key] | |
64 else: | |
65 self[key] = value = default | |
66 return value | |
67 | |
68 DefaultMapping.register(dict) | |
69 | |
70 | |
71 class _DefaultSize(object): | |
72 def __getitem__(self, _): | |
73 return 1 | |
74 | |
75 def __setitem__(self, _, value): | |
76 assert value == 1 | |
77 | |
78 def pop(self, _): | |
79 return 1 | |
80 | |
81 | |
82 class Cache(DefaultMapping): | |
83 """Mutable mapping to serve as a simple cache or cache base class.""" | |
84 | |
85 __size = _DefaultSize() | |
86 | |
87 def __init__(self, maxsize, missing=None, getsizeof=None): | |
88 if missing: | |
89 self.__missing = missing | |
90 if getsizeof: | |
91 self.__getsizeof = getsizeof | |
92 self.__size = dict() | |
93 self.__data = dict() | |
94 self.__currsize = 0 | |
95 self.__maxsize = maxsize | |
96 | |
97 def __repr__(self): | |
98 return '%s(%r, maxsize=%r, currsize=%r)' % ( | |
99 self.__class__.__name__, | |
100 list(self.__data.items()), | |
101 self.__maxsize, | |
102 self.__currsize, | |
103 ) | |
104 | |
105 def __getitem__(self, key): | |
106 try: | |
107 return self.__data[key] | |
108 except KeyError: | |
109 return self.__missing__(key) | |
110 | |
111 def __setitem__(self, key, value): | |
112 maxsize = self.__maxsize | |
113 size = self.getsizeof(value) | |
114 if size > maxsize: | |
115 raise ValueError('value too large') | |
116 if key not in self.__data or self.__size[key] < size: | |
117 while self.__currsize + size > maxsize: | |
118 self.popitem() | |
119 if key in self.__data: | |
120 diffsize = size - self.__size[key] | |
121 else: | |
122 diffsize = size | |
123 self.__data[key] = value | |
124 self.__size[key] = size | |
125 self.__currsize += diffsize | |
126 | |
127 def __delitem__(self, key): | |
128 size = self.__size.pop(key) | |
129 del self.__data[key] | |
130 self.__currsize -= size | |
131 | |
132 def __contains__(self, key): | |
133 return key in self.__data | |
134 | |
135 def __missing__(self, key): | |
136 value = self.__missing(key) | |
137 try: | |
138 self.__setitem__(key, value) | |
139 except ValueError: | |
140 pass # value too large | |
141 return value | |
142 | |
143 def __iter__(self): | |
144 return iter(self.__data) | |
145 | |
146 def __len__(self): | |
147 return len(self.__data) | |
148 | |
149 @staticmethod | |
150 def __getsizeof(value): | |
151 return 1 | |
152 | |
153 @staticmethod | |
154 def __missing(key): | |
155 raise KeyError(key) | |
156 | |
157 @property | |
158 def maxsize(self): | |
159 """The maximum size of the cache.""" | |
160 return self.__maxsize | |
161 | |
162 @property | |
163 def currsize(self): | |
164 """The current size of the cache.""" | |
165 return self.__currsize | |
166 | |
167 def getsizeof(self, value): | |
168 """Return the size of a cache element's value.""" | |
169 return self.__getsizeof(value) | |
170 | |
171 | |
172 class _Link(object): | |
173 | |
174 __slots__ = ('key', 'expire', 'next', 'prev') | |
175 | |
176 def __init__(self, key=None, expire=None): | |
177 self.key = key | |
178 self.expire = expire | |
179 | |
180 def __reduce__(self): | |
181 return _Link, (self.key, self.expire) | |
182 | |
183 def unlink(self): | |
184 next = self.next | |
185 prev = self.prev | |
186 prev.next = next | |
187 next.prev = prev | |
188 | |
189 | |
190 class _Timer(object): | |
191 | |
192 def __init__(self, timer): | |
193 self.__timer = timer | |
194 self.__nesting = 0 | |
195 | |
196 def __call__(self): | |
197 if self.__nesting == 0: | |
198 return self.__timer() | |
199 else: | |
200 return self.__time | |
201 | |
202 def __enter__(self): | |
203 if self.__nesting == 0: | |
204 self.__time = time = self.__timer() | |
205 else: | |
206 time = self.__time | |
207 self.__nesting += 1 | |
208 return time | |
209 | |
210 def __exit__(self, *exc): | |
211 self.__nesting -= 1 | |
212 | |
213 def __reduce__(self): | |
214 return _Timer, (self.__timer,) | |
215 | |
216 def __getattr__(self, name): | |
217 return getattr(self.__timer, name) | |
218 | |
219 | |
220 class TTLCache(Cache): | |
221 """LRU Cache implementation with per-item time-to-live (TTL) value.""" | |
222 | |
223 def __init__(self, maxsize, ttl, timer=time.time, missing=None, | |
224 getsizeof=None): | |
225 Cache.__init__(self, maxsize, missing, getsizeof) | |
226 self.__root = root = _Link() | |
227 root.prev = root.next = root | |
228 self.__links = collections.OrderedDict() | |
229 self.__timer = _Timer(timer) | |
230 self.__ttl = ttl | |
231 | |
232 def __contains__(self, key): | |
233 try: | |
234 link = self.__links[key] # no reordering | |
235 except KeyError: | |
236 return False | |
237 else: | |
238 return not (link.expire < self.__timer()) | |
239 | |
240 def __getitem__(self, key, cache_getitem=Cache.__getitem__): | |
241 try: | |
242 link = self.__getlink(key) | |
243 except KeyError: | |
244 expired = False | |
245 else: | |
246 expired = link.expire < self.__timer() | |
247 if expired: | |
248 return self.__missing__(key) | |
249 else: | |
250 return cache_getitem(self, key) | |
251 | |
252 def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): | |
253 with self.__timer as time: | |
254 self.expire(time) | |
255 cache_setitem(self, key, value) | |
256 try: | |
257 link = self.__getlink(key) | |
258 except KeyError: | |
259 self.__links[key] = link = _Link(key) | |
260 else: | |
261 link.unlink() | |
262 link.expire = time + self.__ttl | |
263 link.next = root = self.__root | |
264 link.prev = prev = root.prev | |
265 prev.next = root.prev = link | |
266 | |
267 def __delitem__(self, key, cache_delitem=Cache.__delitem__): | |
268 cache_delitem(self, key) | |
269 link = self.__links.pop(key) | |
270 link.unlink() | |
271 if link.expire < self.__timer(): | |
272 raise KeyError(key) | |
273 | |
274 def __iter__(self): | |
275 root = self.__root | |
276 curr = root.next | |
277 while curr is not root: | |
278 # "freeze" time for iterator access | |
279 with self.__timer as time: | |
280 if not (curr.expire < time): | |
281 yield curr.key | |
282 curr = curr.next | |
283 | |
284 def __len__(self): | |
285 root = self.__root | |
286 curr = root.next | |
287 time = self.__timer() | |
288 count = len(self.__links) | |
289 while curr is not root and curr.expire < time: | |
290 count -= 1 | |
291 curr = curr.next | |
292 return count | |
293 | |
294 def __setstate__(self, state): | |
295 self.__dict__.update(state) | |
296 root = self.__root | |
297 root.prev = root.next = root | |
298 for link in sorted(self.__links.values(), key=lambda obj: obj.expire): | |
299 link.next = root | |
300 link.prev = prev = root.prev | |
301 prev.next = root.prev = link | |
302 self.expire(self.__timer()) | |
303 | |
304 def __repr__(self, cache_repr=Cache.__repr__): | |
305 with self.__timer as time: | |
306 self.expire(time) | |
307 return cache_repr(self) | |
308 | |
309 @property | |
310 def currsize(self): | |
311 with self.__timer as time: | |
312 self.expire(time) | |
313 return super(TTLCache, self).currsize | |
314 | |
315 @property | |
316 def timer(self): | |
317 """The timer function used by the cache.""" | |
318 return self.__timer | |
319 | |
320 @property | |
321 def ttl(self): | |
322 """The time-to-live value of the cache's items.""" | |
323 return self.__ttl | |
324 | |
325 def expire(self, time=None): | |
326 """Remove expired items from the cache.""" | |
327 if time is None: | |
328 time = self.__timer() | |
329 root = self.__root | |
330 curr = root.next | |
331 links = self.__links | |
332 cache_delitem = Cache.__delitem__ | |
333 while curr is not root and curr.expire < time: | |
334 cache_delitem(self, curr.key) | |
335 del links[curr.key] | |
336 next = curr.next | |
337 curr.unlink() | |
338 curr = next | |
339 | |
340 def clear(self): | |
341 with self.__timer as time: | |
342 self.expire(time) | |
343 Cache.clear(self) | |
344 | |
345 def get(self, *args, **kwargs): | |
346 with self.__timer: | |
347 return Cache.get(self, *args, **kwargs) | |
348 | |
349 def pop(self, *args, **kwargs): | |
350 with self.__timer: | |
351 return Cache.pop(self, *args, **kwargs) | |
352 | |
353 def setdefault(self, *args, **kwargs): | |
354 with self.__timer: | |
355 return Cache.setdefault(self, *args, **kwargs) | |
356 | |
357 def popitem(self): | |
358 """Remove and return the `(key, value)` pair least recently used that | |
359 has not already expired. | |
360 | |
361 """ | |
362 with self.__timer as time: | |
363 self.expire(time) | |
364 try: | |
365 key = next(iter(self.__links)) | |
366 except StopIteration: | |
367 raise KeyError('%s is empty' % self.__class__.__name__) | |
368 else: | |
369 return (key, self.pop(key)) | |
370 | |
371 if hasattr(collections.OrderedDict, 'move_to_end'): | |
372 def __getlink(self, key): | |
373 value = self.__links[key] | |
374 self.__links.move_to_end(key) | |
375 return value | |
376 else: | |
377 def __getlink(self, key): | |
378 value = self.__links.pop(key) | |
379 self.__links[key] = value | |
380 return value | |
381 | |
382 | |
383 ############################################# | |
384 ###### END IMPORT OF CACHING LIBRARY ###### | |
385 ############################################# | |
386 | |
387 cache = TTLCache( | |
388 100, # Up to 100 items | |
389 5 * 60 # 5 minute cache life | |
390 ) | |
391 userCache = TTLCache( | |
392 2, # Up to 2 items | |
393 60 # 1 minute cache life | |
394 ) | |
395 | |
396 class UnknownUserException(Exception): | |
397 pass | |
398 | |
13 def WAAuth(parser): | 399 def WAAuth(parser): |
14 parser.add_argument('apollo', help='Complete Apollo URL') | 400 parser.add_argument('apollo', help='Complete Apollo URL') |
15 parser.add_argument('username', help='WA Username') | 401 parser.add_argument('username', help='WA Username') |
16 parser.add_argument('password', help='WA Password') | 402 parser.add_argument('password', help='WA Password') |
17 parser.add_argument('--remote_user', default='', help='If set, ignore password, set the header with the name supplied to this argument to the value of email') | |
18 | 403 |
19 | 404 |
20 def OrgOrGuess(parser): | 405 def OrgOrGuess(parser): |
21 parser.add_argument('--org_json', type=file, help='Apollo JSON output, source for common name') | 406 parser.add_argument('--org_json', type=argparse.FileType("r"), help='Apollo JSON output, source for common name') |
22 parser.add_argument('--org_raw', help='Common Name') | 407 parser.add_argument('--org_raw', help='Common Name') |
23 parser.add_argument('--org_id', help='Organism ID') | 408 parser.add_argument('--org_id', help='Organism ID') |
24 | 409 |
25 | 410 |
26 def CnOrGuess(parser): | 411 def CnOrGuess(parser): |
27 OrgOrGuess(parser) | 412 OrgOrGuess(parser) |
28 parser.add_argument('--seq_fasta', type=file, help='Fasta file, IDs used as sequence sources') | 413 parser.add_argument('--seq_fasta', type=argparse.FileType("r"), help='Fasta file, IDs used as sequence sources') |
29 parser.add_argument('--seq_raw', nargs='*', help='Sequence Names') | 414 parser.add_argument('--seq_raw', nargs='*', help='Sequence Names') |
30 | 415 |
31 | 416 |
32 def GuessOrg(args, wa): | 417 def GuessOrg(args, wa): |
33 if args.org_json: | 418 if args.org_json: |
61 return org, seqs | 446 return org, seqs |
62 | 447 |
63 | 448 |
64 def AssertUser(user_list): | 449 def AssertUser(user_list): |
65 if len(user_list) == 0: | 450 if len(user_list) == 0: |
66 raise Exception("Unknown user. Please register first") | 451 raise UnknownUserException() |
452 elif len(user_list) == 1: | |
453 return user_list[0] | |
67 else: | 454 else: |
68 return user_list[0] | 455 raise Exception("Too many users!") |
69 | 456 |
70 | 457 |
71 def AssertAdmin(user): | 458 def AssertAdmin(user): |
72 if user.role == 'ADMIN': | 459 if user.role == 'ADMIN': |
73 return True | 460 return True |
79 | 466 |
80 def __init__(self, url, username, password): | 467 def __init__(self, url, username, password): |
81 self.apollo_url = url | 468 self.apollo_url = url |
82 self.username = username | 469 self.username = username |
83 self.password = password | 470 self.password = password |
471 # TODO: Remove after apollo 2.0.6. | |
472 self.clientToken = time.time() | |
84 | 473 |
85 self.annotations = AnnotationsClient(self) | 474 self.annotations = AnnotationsClient(self) |
86 self.groups = GroupsClient(self) | 475 self.groups = GroupsClient(self) |
87 self.io = IOClient(self) | 476 self.io = IOClient(self) |
88 self.organisms = OrganismsClient(self) | 477 self.organisms = OrganismsClient(self) |
91 self.bio = RemoteRecord(self) | 480 self.bio = RemoteRecord(self) |
92 | 481 |
93 def __str__(self): | 482 def __str__(self): |
94 return '<WebApolloInstance at %s>' % self.apollo_url | 483 return '<WebApolloInstance at %s>' % self.apollo_url |
95 | 484 |
485 def requireUser(self, email): | |
486 cacheKey = 'user-list' | |
487 try: | |
488 # Get the cached value | |
489 data = userCache[cacheKey] | |
490 except KeyError: | |
491 # If we hit a key error above, indicating that | |
492 # we couldn't find the key, we'll simply re-request | |
493 # the data | |
494 data = self.users.loadUsers() | |
495 userCache[cacheKey] = data | |
496 | |
497 return AssertUser([x for x in data if x.username == email]) | |
498 | |
96 | 499 |
97 class GroupObj(object): | 500 class GroupObj(object): |
98 def __init__(self, **kwargs): | 501 def __init__(self, **kwargs): |
99 self.name = kwargs['name'] | 502 self.name = kwargs['name'] |
100 | 503 |
160 } | 563 } |
161 | 564 |
162 data.update({ | 565 data.update({ |
163 'username': self._wa.username, | 566 'username': self._wa.username, |
164 'password': self._wa.password, | 567 'password': self._wa.password, |
568 'clientToken': self._wa.clientToken, | |
165 }) | 569 }) |
166 | 570 |
167 r = requests.post(url, data=json.dumps(data), headers=headers, | 571 r = requests.post(url, data=json.dumps(data), headers=headers, |
168 verify=self.__verify, params=post_params, allow_redirects=False, **self._requestArgs) | 572 verify=self.__verify, params=post_params, allow_redirects=False, **self._requestArgs) |
169 | 573 |
264 'features': symbols, | 668 'features': symbols, |
265 } | 669 } |
266 data.update(self._extra_data) | 670 data.update(self._extra_data) |
267 return self.request('setSymbol', data) | 671 return self.request('setSymbol', data) |
268 | 672 |
269 def getComments(self, features): | 673 def getComments(self, feature_id): |
270 data = { | 674 data = { |
271 'features': features, | 675 'features': [{'uniquename': feature_id}], |
676 } | |
677 data = self._update_data(data) | |
678 return self.request('getComments', data) | |
679 | |
680 def addComments(self, feature_id, comment): | |
681 #TODO: This is probably not great and will delete comments, if I had to guess... | |
682 data = { | |
683 'features': [ | |
684 { | |
685 'uniquename': feature_id, | |
686 'comments': [comment] | |
687 } | |
688 ], | |
272 } | 689 } |
273 data = self._update_data(data) | 690 data = self._update_data(data) |
274 return self.request('getComments', data) | 691 return self.request('getComments', data) |
275 | 692 |
276 def addAttribute(self, features): | 693 def addAttribute(self, features): |
295 | 712 |
296 def addFeature(self, feature, trustme=False): | 713 def addFeature(self, feature, trustme=False): |
297 if not trustme: | 714 if not trustme: |
298 raise NotImplementedError("Waiting on better docs from project. If you know what you are doing, pass trustme=True to this function.") | 715 raise NotImplementedError("Waiting on better docs from project. If you know what you are doing, pass trustme=True to this function.") |
299 | 716 |
300 data = {} | 717 data = { |
301 data.update(feature) | 718 'features': feature, |
719 } | |
302 data = self._update_data(data) | 720 data = self._update_data(data) |
303 return self.request('addFeature', data) | 721 return self.request('addFeature', data) |
304 | 722 |
305 def addTranscript(self, transcript, trustme=False): | 723 def addTranscript(self, transcript, trustme=False): |
306 if not trustme: | 724 if not trustme: |
463 'id': group.groupId, | 881 'id': group.groupId, |
464 'name': group.name, | 882 'name': group.name, |
465 } | 883 } |
466 return self.request('getOrganismPermissionsForGroup', data) | 884 return self.request('getOrganismPermissionsForGroup', data) |
467 | 885 |
886 def loadGroup(self, group): | |
887 return self.loadGroupById(group.groupId) | |
888 | |
889 def loadGroupById(self, groupId): | |
890 res = self.request('loadGroups', {'groupId': groupId}) | |
891 if isinstance(res, list): | |
892 # We can only match one, right? | |
893 return GroupObj(**res[0]) | |
894 else: | |
895 return res | |
896 | |
897 def loadGroupByName(self, name): | |
898 res = self.request('loadGroups', {'name': name}) | |
899 if isinstance(res, list): | |
900 # We can only match one, right? | |
901 return GroupObj(**res[0]) | |
902 else: | |
903 return res | |
904 | |
468 def loadGroups(self, group=None): | 905 def loadGroups(self, group=None): |
469 data = {} | 906 res = self.request('loadGroups', {}) |
907 data = [GroupObj(**x) for x in res] | |
470 if group is not None: | 908 if group is not None: |
471 data['groupId'] = group.groupId | 909 data = [x for x in data if x.name == group] |
472 | 910 |
473 return self.request('loadGroups', data) | 911 return data |
474 | 912 |
475 def deleteGroup(self, group): | 913 def deleteGroup(self, group): |
476 data = { | 914 data = { |
477 'id': group.groupId, | 915 'id': group.groupId, |
478 'name': group.name, | 916 'name': group.name, |
491 def updateOrganismPermission(self, group, organismName, | 929 def updateOrganismPermission(self, group, organismName, |
492 administrate=False, write=False, read=False, | 930 administrate=False, write=False, read=False, |
493 export=False): | 931 export=False): |
494 data = { | 932 data = { |
495 'groupId': group.groupId, | 933 'groupId': group.groupId, |
496 'name': organismName, | 934 'organism': organismName, |
497 'administrate': administrate, | 935 'ADMINISTRATE': administrate, |
498 'write': write, | 936 'WRITE': write, |
499 'export': export, | 937 'EXPORT': export, |
500 'read': read, | 938 'READ': read, |
501 } | 939 } |
502 return self.request('updateOrganismPermission', data) | 940 return self.request('updateOrganismPermission', data) |
503 | 941 |
504 def updateMembership(self, group, users): | 942 def updateMembership(self, group, users): |
505 data = { | 943 data = { |
704 | 1142 |
705 def ParseRecord(self, cn): | 1143 def ParseRecord(self, cn): |
706 org = self._wa.organisms.findOrganismByCn(cn) | 1144 org = self._wa.organisms.findOrganismByCn(cn) |
707 self._wa.annotations.setSequence(org['commonName'], org['id']) | 1145 self._wa.annotations.setSequence(org['commonName'], org['id']) |
708 | 1146 |
709 data = StringIO.StringIO(self._wa.io.write( | 1147 data = io.StringIO(self._wa.io.write( |
710 exportType='GFF3', | 1148 exportType='GFF3', |
711 seqType='genomic', | 1149 seqType='genomic', |
712 exportAllSequences=False, | 1150 exportAllSequences=False, |
713 exportGff3Fasta=True, | 1151 exportGff3Fasta=True, |
714 output="text", | 1152 output="text", |
814 | 1252 |
815 | 1253 |
816 def featuresToFeatureSchema(features): | 1254 def featuresToFeatureSchema(features): |
817 compiled = [] | 1255 compiled = [] |
818 for feature in features: | 1256 for feature in features: |
819 if feature.type != 'gene': | 1257 # if feature.type != 'gene': |
820 log.warn("Not able to handle %s features just yet...", feature.type) | 1258 # log.warn("Not able to handle %s features just yet...", feature.type) |
821 continue | 1259 # continue |
822 | 1260 |
823 for x in _yieldFeatData([feature]): | 1261 for x in _yieldFeatData([feature]): |
824 compiled.append(x) | 1262 compiled.append(x) |
825 return compiled | 1263 return compiled |
826 | 1264 |
832 if 'WRITE' in x['permissions'] or | 1270 if 'WRITE' in x['permissions'] or |
833 'READ' in x['permissions'] or | 1271 'READ' in x['permissions'] or |
834 'ADMINISTRATE' in x['permissions'] or | 1272 'ADMINISTRATE' in x['permissions'] or |
835 user.role == 'ADMIN' | 1273 user.role == 'ADMIN' |
836 } | 1274 } |
1275 | |
1276 if 'error' in orgs: | |
1277 raise Exception("Error received from Apollo server: \"%s\"" % orgs['error']) | |
1278 | |
837 return [ | 1279 return [ |
838 (org['commonName'], org['id'], False) | 1280 (org['commonName'], org['id'], False) |
839 for org in sorted(orgs, key=lambda x: x['commonName']) | 1281 for org in sorted(orgs, key=lambda x: x['commonName']) |
840 if org['commonName'] in permissionMap | 1282 if org['commonName'] in permissionMap |
841 ] | 1283 ] |
842 | 1284 |
843 | 1285 |
1286 def galaxy_list_groups(trans, *args, **kwargs): | |
1287 email = trans.get_user().email | |
1288 wa = WebApolloInstance( | |
1289 os.environ['GALAXY_WEBAPOLLO_URL'], | |
1290 os.environ['GALAXY_WEBAPOLLO_USER'], | |
1291 os.environ['GALAXY_WEBAPOLLO_PASSWORD'] | |
1292 ) | |
1293 # Assert that the email exists in apollo | |
1294 try: | |
1295 gx_user = wa.requireUser(email) | |
1296 except UnknownUserException: | |
1297 return [] | |
1298 | |
1299 # Key for cached data | |
1300 cacheKey = 'groups-' + email | |
1301 # We don't want to trust "if key in cache" because between asking and fetch | |
1302 # it might through key error. | |
1303 if cacheKey not in cache: | |
1304 # However if it ISN'T there, we know we're safe to fetch + put in | |
1305 # there. | |
1306 data = _galaxy_list_groups(wa, gx_user, *args, **kwargs) | |
1307 cache[cacheKey] = data | |
1308 return data | |
1309 try: | |
1310 # The cache key may or may not be in the cache at this point, it | |
1311 # /likely/ is. However we take no chances that it wasn't evicted between | |
1312 # when we checked above and now, so we reference the object from the | |
1313 # cache in preparation to return. | |
1314 data = cache[cacheKey] | |
1315 return data | |
1316 except KeyError: | |
1317 # If access fails due to eviction, we will fail over and can ensure that | |
1318 # data is inserted. | |
1319 data = _galaxy_list_groups(wa, gx_user, *args, **kwargs) | |
1320 cache[cacheKey] = data | |
1321 return data | |
1322 | |
1323 | |
1324 def _galaxy_list_groups(wa, gx_user, *args, **kwargs): | |
1325 # Fetch the groups. | |
1326 group_data = [] | |
1327 for group in wa.groups.loadGroups(): | |
1328 # Reformat | |
1329 group_data.append((group.name, group.groupId, False)) | |
1330 return group_data | |
1331 | |
1332 | |
844 def galaxy_list_orgs(trans, *args, **kwargs): | 1333 def galaxy_list_orgs(trans, *args, **kwargs): |
845 email = trans.get_user().email | 1334 email = trans.get_user().email |
846 | |
847 wa = WebApolloInstance( | 1335 wa = WebApolloInstance( |
848 os.environ.get('GALAXY_WEBAPOLLO_URL', 'https://example.com'), | 1336 os.environ['GALAXY_WEBAPOLLO_URL'], |
849 os.environ.get('GALAXY_WEBAPOLLO_USER', 'admin'), | 1337 os.environ['GALAXY_WEBAPOLLO_USER'], |
850 os.environ.get('GALAXY_WEBAPOLLO_PASSWORD', 'admin') | 1338 os.environ['GALAXY_WEBAPOLLO_PASSWORD'] |
851 ) | 1339 ) |
852 | 1340 try: |
853 gx_user = AssertUser(wa.users.loadUsers(email=email)) | 1341 gx_user = wa.requireUser(email) |
1342 except UnknownUserException: | |
1343 return [] | |
1344 | |
1345 # Key for cached data | |
1346 cacheKey = 'orgs-' + email | |
1347 if cacheKey not in cache: | |
1348 data = _galaxy_list_orgs(wa, gx_user, *args, **kwargs) | |
1349 cache[cacheKey] = data | |
1350 return data | |
1351 try: | |
1352 data = cache[cacheKey] | |
1353 return data | |
1354 except KeyError: | |
1355 data = _galaxy_list_orgs(wa, gx_user, *args, **kwargs) | |
1356 cache[cacheKey] = data | |
1357 return data | |
1358 | |
1359 | |
1360 def _galaxy_list_orgs(wa, gx_user, *args, **kwargs): | |
1361 # Fetch all organisms | |
854 all_orgs = wa.organisms.findAllOrganisms() | 1362 all_orgs = wa.organisms.findAllOrganisms() |
855 | 1363 # Figure out which are accessible to the user |
856 orgs = accessible_organisms(gx_user, all_orgs) | 1364 orgs = accessible_organisms(gx_user, all_orgs) |
857 | 1365 # Return org list |
858 return orgs | 1366 return orgs |
1367 | |
1368 ## This is all for implementing the command line interface for testing. | |
1369 | |
1370 class obj(object): | |
1371 pass | |
1372 | |
1373 | |
1374 class fakeTrans(object): | |
1375 | |
1376 def __init__(self, username): | |
1377 self.un = username | |
1378 | |
1379 def get_user(self): | |
1380 o = obj() | |
1381 o.email = self.un | |
1382 return o | |
1383 | |
1384 if __name__ == '__main__': | |
1385 parser = argparse.ArgumentParser(description='Test access to apollo server') | |
1386 parser.add_argument('email', help='Email of user to test') | |
1387 parser.add_argument('--action', choices=['org', 'group'], default='org', help='Data set to test, fetch a list of groups or users known to the requesting user.') | |
1388 args = parser.parse_args() | |
1389 | |
1390 trans = fakeTrans(args.email) | |
1391 if args.action == 'org': | |
1392 for f in galaxy_list_orgs(trans): | |
1393 print(f) | |
1394 else: | |
1395 for f in galaxy_list_groups(trans): | |
1396 print(f) |