Mercurial > repos > eric-rasche > apollo
diff webapollo.py @ 7:f9a6e151b3b4 draft
planemo upload for repository https://github.com/TAMU-CPT/galaxy-webapollo commit 52b9e5bf6a6efb09a5cb845ee48703651c644174
author | eric-rasche |
---|---|
date | Tue, 27 Jun 2017 04:05:17 -0400 |
parents | 7610987e0c48 |
children |
line wrap: on
line diff
--- a/webapollo.py Sat Mar 04 18:00:52 2017 -0500 +++ b/webapollo.py Tue Jun 27 04:05:17 2017 -0400 @@ -1,23 +1,29 @@ -import requests -import json -import os +from __future__ import print_function +import argparse import collections -try: - import StringIO as io -except: - import io +import json import logging +import os +import requests import time -import argparse +from future import standard_library +from builtins import next +from builtins import str +from builtins import object from abc import abstractmethod from BCBio import GFF from Bio import SeqIO +standard_library.install_aliases() +try: + import StringIO as io +except BaseException: + import io logging.getLogger("requests").setLevel(logging.CRITICAL) log = logging.getLogger() ############################################# -###### BEGIN IMPORT OF CACHING LIBRARY ###### +# BEGIN IMPORT OF CACHING LIBRARY # ############################################# # This code is licensed under the MIT # # License and is a copy of code publicly # @@ -25,6 +31,7 @@ # e27332bc82f4e327aedaec17c9b656ae719322ed # # of https://github.com/tkem/cachetools/ # ############################################# + class DefaultMapping(collections.MutableMapping): __slots__ = () @@ -65,6 +72,7 @@ self[key] = value = default return value + DefaultMapping.register(dict) @@ -381,21 +389,24 @@ ############################################# -###### END IMPORT OF CACHING LIBRARY ###### +# END IMPORT OF CACHING LIBRARY # ############################################# + cache = TTLCache( - 100, # Up to 100 items - 5 * 60 # 5 minute cache life + 100, # Up to 100 items + 5 * 60 # 5 minute cache life ) userCache = TTLCache( - 2, # Up to 2 items - 60 # 1 minute cache life + 2, # Up to 2 items + 60 # 1 minute cache life ) + class UnknownUserException(Exception): pass + def WAAuth(parser): parser.add_argument('apollo', help='Complete Apollo URL') parser.add_argument('username', help='WA Username') @@ -468,8 +479,6 @@ self.apollo_url = url self.username = username self.password = password - # TODO: Remove after apollo 2.0.6. - self.clientToken = time.time() self.annotations = AnnotationsClient(self) self.groups = GroupsClient(self) @@ -478,6 +487,10 @@ self.users = UsersClient(self) self.metrics = MetricsClient(self) self.bio = RemoteRecord(self) + self.status = StatusClient(self) + self.canned_comments = CannedCommentsClient(self) + self.canned_keys = CannedKeysClient(self) + self.canned_values = CannedValuesClient(self) def __str__(self): return '<WebApolloInstance at %s>' % self.apollo_url @@ -539,6 +552,12 @@ data[prop] = getattr(self, prop) return data + def orgPerms(self): + for orgPer in self.organismPermissions: + if len(orgPer['permissions']) > 2: + orgPer['permissions'] = json.loads(orgPer['permissions']) + yield orgPer + def __str__(self): return '<User %s: %s %s <%s>>' % (self.userId, self.firstName, self.lastName, self.username) @@ -565,7 +584,6 @@ data.update({ 'username': self._wa.username, 'password': self._wa.password, - 'clientToken': self._wa.clientToken, }) r = requests.post(url, data=json.dumps(data), headers=headers, @@ -677,22 +695,49 @@ data = self._update_data(data) return self.request('getComments', data) - def addComments(self, feature_id, comment): - #TODO: This is probably not great and will delete comments, if I had to guess... + def addComments(self, feature_id, comments): + # TODO: This is probably not great and will delete comments, if I had to guess... data = { 'features': [ { 'uniquename': feature_id, - 'comments': [comment] + 'comments': comments } ], } data = self._update_data(data) - return self.request('getComments', data) + return self.request('addComments', data) + + def addAttributes(self, feature_id, attributes): + nrps = [] + for (key, values) in attributes.items(): + for value in values: + nrps.append({ + 'tag': key, + 'value': value + }) - def addAttribute(self, features): data = { - 'features': features, + 'features': [ + { + 'uniquename': feature_id, + 'non_reserved_properties': nrps + } + ] + } + data = self._update_data(data) + return self.request('addAttribute', data) + + def deleteAttribute(self, feature_id, key, value): + data = { + 'features': [ + { + 'uniquename': feature_id, + 'non_reserved_properties': [ + {'tag': key, 'value': value} + ] + } + ] } data = self._update_data(data) return self.request('addAttribute', data) @@ -991,6 +1036,198 @@ return self.request('write', data) +class StatusClient(Client): + CLIENT_BASE = '/availableStatus/' + + def addStatus(self, value): + data = { + 'value': value + } + + return self.request('createStatus', data) + + def findAllStatuses(self): + return self.request('showStatus', {}) + + def findStatusByValue(self, value): + statuses = self.findAllStatuses() + statuses = [x for x in statuses if x['value'] == value] + if len(statuses) == 0: + raise Exception("Unknown status value") + else: + return statuses[0] + + def findStatusById(self, id_number): + statuses = self.findAllStatuses() + statuses = [x for x in statuses if str(x['id']) == str(id_number)] + if len(statuses) == 0: + raise Exception("Unknown ID") + else: + return statuses[0] + + def updateStatus(self, id_number, new_value): + data = { + 'id': id_number, + 'new_value': new_value + } + + return self.request('updateStatus', data) + + def deleteStatus(self, id_number): + data = { + 'id': id_number + } + + return self.request('deleteStatus', data) + + +class CannedCommentsClient(Client): + CLIENT_BASE = '/cannedComment/' + + def addComment(self, comment, metadata=""): + data = { + 'comment': comment, + 'metadata': metadata + } + + return self.request('createComment', data) + + def findAllComments(self): + return self.request('showComment', {}) + + def findCommentByValue(self, value): + comments = self.findAllComments() + comments = [x for x in comments if x['comment'] == value] + if len(comments) == 0: + raise Exception("Unknown comment") + else: + return comments[0] + + def findCommentById(self, id_number): + comments = self.findAllComments() + comments = [x for x in comments if str(x['id']) == str(id_number)] + if len(comments) == 0: + raise Exception("Unknown ID") + else: + return comments[0] + + def updateComment(self, id_number, new_value, metadata=None): + data = { + 'id': id_number, + 'new_comment': new_value + } + + if metadata is not None: + data['metadata'] = metadata + + return self.request('updateComment', data) + + def deleteComment(self, id_number): + data = { + 'id': id_number + } + + return self.request('deleteComment', data) + + +class CannedKeysClient(Client): + CLIENT_BASE = '/cannedKey/' + + def addKey(self, key, metadata=""): + data = { + 'key': key, + 'metadata': metadata + } + + return self.request('createKey', data) + + def findAllKeys(self): + return self.request('showKey', {}) + + def findKeyByValue(self, value): + keys = self.findAllKeys() + keys = [x for x in keys if x['label'] == value] + if len(keys) == 0: + raise Exception("Unknown key") + else: + return keys[0] + + def findKeyById(self, id_number): + keys = self.findAllKeys() + keys = [x for x in keys if str(x['id']) == str(id_number)] + if len(keys) == 0: + raise Exception("Unknown ID") + else: + return keys[0] + + def updateKey(self, id_number, new_key, metadata=None): + data = { + 'id': id_number, + 'new_key': new_key + } + + if metadata is not None: + data['metadata'] = metadata + + return self.request('updateKey', data) + + def deleteKey(self, id_number): + data = { + 'id': id_number + } + + return self.request('deleteKey', data) + + +class CannedValuesClient(Client): + CLIENT_BASE = '/cannedValue/' + + def addValue(self, value, metadata=""): + data = { + 'value': value, + 'metadata': metadata + } + + return self.request('createValue', data) + + def findAllValues(self): + return self.request('showValue', {}) + + def findValueByValue(self, value): + values = self.findAllValues() + values = [x for x in values if x['label'] == value] + if len(values) == 0: + raise Exception("Unknown value") + else: + return values[0] + + def findValueById(self, id_number): + values = self.findAllValues() + values = [x for x in values if str(x['id']) == str(id_number)] + if len(values) == 0: + raise Exception("Unknown ID") + else: + return values[0] + + def updateValue(self, id_number, new_value, metadata=None): + data = { + 'id': id_number, + 'new_value': new_value + } + + if metadata is not None: + data['metadata'] = metadata + + return self.request('updateValue', data) + + def deleteValue(self, id_number): + data = { + 'id': id_number + } + + return self.request('deleteValue', data) + + class OrganismsClient(Client): CLIENT_BASE = '/organism/' @@ -1222,7 +1459,7 @@ def _tnType(feature): - if feature.type in ('gene', 'mRNA', 'exon', 'CDS'): + if feature.type in ('gene', 'mRNA', 'exon', 'CDS', 'terminator', 'tRNA'): return feature.type else: return 'exon' @@ -1365,8 +1602,55 @@ # Return org list return orgs -## This is all for implementing the command line interface for testing. + +def galaxy_list_users(trans, *args, **kwargs): + email = trans.get_user().email + wa = WebApolloInstance( + os.environ['GALAXY_WEBAPOLLO_URL'], + os.environ['GALAXY_WEBAPOLLO_USER'], + os.environ['GALAXY_WEBAPOLLO_PASSWORD'] + ) + # Assert that the email exists in apollo + try: + gx_user = wa.requireUser(email) + except UnknownUserException: + return [] + # Key for cached data + cacheKey = 'users-' + email + # We don't want to trust "if key in cache" because between asking and fetch + # it might through key error. + if cacheKey not in cache: + # However if it ISN'T there, we know we're safe to fetch + put in + # there. + data = _galaxy_list_users(wa, gx_user, *args, **kwargs) + cache[cacheKey] = data + return data + try: + # The cache key may or may not be in the cache at this point, it + # /likely/ is. However we take no chances that it wasn't evicted between + # when we checked above and now, so we reference the object from the + # cache in preparation to return. + data = cache[cacheKey] + return data + except KeyError: + # If access fails due to eviction, we will fail over and can ensure that + # data is inserted. + data = _galaxy_list_users(wa, gx_user, *args, **kwargs) + cache[cacheKey] = data + return data + + +def _galaxy_list_users(wa, gx_user, *args, **kwargs): + # Fetch the users. + user_data = [] + for user in wa.users.loadUsers(): + # Reformat + user_data.append((user.username, user.username, False)) + return user_data + + +# This is all for implementing the command line interface for testing. class obj(object): pass @@ -1381,16 +1665,46 @@ o.email = self.un return o + +def retry(closure, sleep=1, limit=5): + """ + Apollo has the bad habit of returning 500 errors if you call APIs + too quickly, largely because of the unholy things that happen in + grails. + + To deal with the fact that we cannot send an addComments call too + quickly after a createFeature call, we have this function that will + keep calling a closure until it works. + """ + count = 0 + while True: + count += 1 + + if count >= limit: + return False + try: + # Try calling it + closure() + # If successful, exit + return True + except Exception as e: + log.info(str(e)[0:100]) + time.sleep(sleep) + + if __name__ == '__main__': parser = argparse.ArgumentParser(description='Test access to apollo server') parser.add_argument('email', help='Email of user to test') - 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.') + parser.add_argument('--action', choices=['org', 'group', 'users'], default='org', help='Data set to test, fetch a list of groups or users known to the requesting user.') args = parser.parse_args() trans = fakeTrans(args.email) if args.action == 'org': for f in galaxy_list_orgs(trans): print(f) - else: + elif args.action == 'group': for f in galaxy_list_groups(trans): print(f) + else: + for f in galaxy_list_users(trans): + print(f)