Mercurial > repos > gga > apollo_fetch_jbrowse
comparison webapollo.py @ 10:dca2fb399ee6 draft
"planemo upload for repository https://github.com/galaxy-genome-annotation/galaxy-tools/tree/master/tools/apollo commit 08015be1ee8a784e0619f961aaa724857debfd6f"
| author | gga |
|---|---|
| date | Mon, 02 Dec 2019 05:45:36 -0500 |
| parents | 54277b911534 |
| children | d91f4bc313d3 |
comparison
equal
deleted
inserted
replaced
| 9:d8bb1f9b85b2 | 10:dca2fb399ee6 |
|---|---|
| 3 import argparse | 3 import argparse |
| 4 import collections | 4 import collections |
| 5 import json | 5 import json |
| 6 import logging | 6 import logging |
| 7 import os | 7 import os |
| 8 import random | |
| 9 import time | 8 import time |
| 10 from abc import abstractmethod | 9 from abc import abstractmethod |
| 11 | 10 |
| 12 from BCBio import GFF | |
| 13 | |
| 14 from Bio import SeqIO | |
| 15 | |
| 16 import requests | 11 import requests |
| 17 | 12 |
| 18 from six.moves.builtins import next | 13 from six.moves.builtins import next |
| 19 from six.moves.builtins import object | 14 from six.moves.builtins import object |
| 20 from six.moves.builtins import str | 15 |
| 21 | 16 import yaml |
| 22 | 17 |
| 23 try: | |
| 24 import StringIO as io | |
| 25 except BaseException: | |
| 26 import io | |
| 27 logging.getLogger("requests").setLevel(logging.CRITICAL) | 18 logging.getLogger("requests").setLevel(logging.CRITICAL) |
| 28 log = logging.getLogger() | 19 log = logging.getLogger() |
| 29 | 20 |
| 30 | 21 |
| 31 ############################################# | 22 ############################################# |
| 429 OrgOrGuess(parser) | 420 OrgOrGuess(parser) |
| 430 parser.add_argument('--seq_fasta', type=argparse.FileType("r"), help='Fasta file, IDs used as sequence sources') | 421 parser.add_argument('--seq_fasta', type=argparse.FileType("r"), help='Fasta file, IDs used as sequence sources') |
| 431 parser.add_argument('--seq_raw', nargs='*', help='Sequence Names') | 422 parser.add_argument('--seq_raw', nargs='*', help='Sequence Names') |
| 432 | 423 |
| 433 | 424 |
| 434 def GuessOrg(args, wa): | |
| 435 if args.org_json: | |
| 436 orgs = [x.get('commonName', None) | |
| 437 for x in json.load(args.org_json)] | |
| 438 orgs = [x for x in orgs if x is not None] | |
| 439 return orgs | |
| 440 elif args.org_raw: | |
| 441 org = args.org_raw.strip() | |
| 442 if len(org) > 0: | |
| 443 return [org] | |
| 444 else: | |
| 445 raise Exception("Organism Common Name not provided") | |
| 446 elif args.org_id: | |
| 447 return [wa.organisms.findOrganismById(args.org_id).get('commonName', None)] | |
| 448 else: | |
| 449 raise Exception("Organism Common Name not provided") | |
| 450 | |
| 451 | |
| 452 def GuessCn(args, wa): | |
| 453 org = GuessOrg(args, wa) | |
| 454 seqs = [] | |
| 455 if args.seq_fasta: | |
| 456 # If we have a fasta, pull all rec ids from that. | |
| 457 for rec in SeqIO.parse(args.seq_fasta, 'fasta'): | |
| 458 seqs.append(rec.id) | |
| 459 elif args.seq_raw: | |
| 460 # Otherwise raw list. | |
| 461 seqs = [x.strip() for x in args.seq_raw if len(x.strip()) > 0] | |
| 462 | |
| 463 return org, seqs | |
| 464 | |
| 465 | |
| 466 def AssertUser(user_list): | 425 def AssertUser(user_list): |
| 467 if len(user_list) == 0: | 426 if len(user_list) == 0: |
| 468 raise UnknownUserException() | 427 raise UnknownUserException() |
| 469 elif len(user_list) == 1: | 428 elif len(user_list) == 1: |
| 470 return user_list[0] | 429 return user_list[0] |
| 471 else: | 430 else: |
| 472 raise Exception("Too many users!") | 431 raise Exception("Too many users!") |
| 473 | 432 |
| 474 | 433 |
| 475 def AssertAdmin(user): | |
| 476 if user.role == 'ADMIN': | |
| 477 return True | |
| 478 else: | |
| 479 raise Exception("User is not an administrator. Permission denied") | |
| 480 | |
| 481 | |
| 482 def PermissionCheck(user, org_cn, permission_type): | |
| 483 return any(org["organism"] == org_cn and permission_type in org["permissions"] for org in user.organismPermissions) | |
| 484 | |
| 485 | |
| 486 def PasswordGenerator(length): | |
| 487 chars = list('qwrtpsdfghjklzxcvbnm') | |
| 488 return ''.join(random.choice(chars) for _ in range(length)) | |
| 489 | |
| 490 | |
| 491 def IsRemoteUser(): | |
| 492 if 'GALAXY_WEBAPOLLO_REMOTE_USER' not in os.environ: | |
| 493 return False | |
| 494 value = os.environ['GALAXY_WEBAPOLLO_REMOTE_USER'] | |
| 495 if value.lower() in ('true', 't', '1'): | |
| 496 return True | |
| 497 else: | |
| 498 return False | |
| 499 | |
| 500 | |
| 501 class WebApolloInstance(object): | 434 class WebApolloInstance(object): |
| 502 | 435 |
| 503 def __init__(self, url, username, password): | 436 def __init__(self): |
| 504 self.apollo_url = url | 437 |
| 505 self.username = username | 438 if 'ARROW_GLOBAL_CONFIG_PATH' in os.environ: |
| 506 self.password = password | 439 |
| 507 | 440 with open(os.environ['ARROW_GLOBAL_CONFIG_PATH'], 'r') as config: |
| 508 self.annotations = AnnotationsClient(self) | 441 conf = yaml.safe_load(config) |
| 442 try: | |
| 443 instance_name = conf['__default'] | |
| 444 except KeyError: | |
| 445 raise Exception("Unknown Apollo instance and no __default provided") | |
| 446 self.apollo_url = conf[instance_name]['url'] | |
| 447 self.username = conf[instance_name]['username'] | |
| 448 self.password = conf[instance_name]['password'] | |
| 449 else: | |
| 450 self.apollo_url = os.environ['GALAXY_WEBAPOLLO_URL'] | |
| 451 self.username = os.environ['GALAXY_WEBAPOLLO_USER'] | |
| 452 self.password = os.environ['GALAXY_WEBAPOLLO_PASSWORD'] | |
| 453 | |
| 509 self.groups = GroupsClient(self) | 454 self.groups = GroupsClient(self) |
| 510 self.io = IOClient(self) | |
| 511 self.organisms = OrganismsClient(self) | 455 self.organisms = OrganismsClient(self) |
| 512 self.users = UsersClient(self) | 456 self.users = UsersClient(self) |
| 513 self.metrics = MetricsClient(self) | |
| 514 self.bio = RemoteRecord(self) | |
| 515 self.status = StatusClient(self) | |
| 516 self.canned_comments = CannedCommentsClient(self) | |
| 517 self.canned_keys = CannedKeysClient(self) | |
| 518 self.canned_values = CannedValuesClient(self) | |
| 519 | 457 |
| 520 def __str__(self): | 458 def __str__(self): |
| 521 return '<WebApolloInstance at %s>' % self.apollo_url | 459 return '<WebApolloInstance at %s>' % self.apollo_url |
| 522 | 460 |
| 523 def requireUser(self, email): | 461 def requireUser(self, email): |
| 557 for groupData in kwargs['groups']: | 495 for groupData in kwargs['groups']: |
| 558 groups.append(GroupObj(**groupData)) | 496 groups.append(GroupObj(**groupData)) |
| 559 self.groups = groups | 497 self.groups = groups |
| 560 | 498 |
| 561 self.__props = kwargs.keys() | 499 self.__props = kwargs.keys() |
| 562 | |
| 563 def isAdmin(self): | |
| 564 if hasattr(self, 'role'): | |
| 565 return self.role == self.ROLE_ADMIN | |
| 566 return False | |
| 567 | |
| 568 def refresh(self, wa): | |
| 569 # This method requires some sleeping usually. | |
| 570 newU = wa.users.loadUser(self).toDict() | |
| 571 for prop in newU: | |
| 572 setattr(self, prop, newU[prop]) | |
| 573 | |
| 574 def toDict(self): | |
| 575 data = {} | |
| 576 for prop in self.__props: | |
| 577 data[prop] = getattr(self, prop) | |
| 578 return data | |
| 579 | |
| 580 def orgPerms(self): | |
| 581 for orgPer in self.organismPermissions: | |
| 582 if len(orgPer['permissions']) > 2: | |
| 583 orgPer['permissions'] = json.loads(orgPer['permissions']) | |
| 584 yield orgPer | |
| 585 | 500 |
| 586 def __str__(self): | 501 def __str__(self): |
| 587 return '<User %s: %s %s <%s>>' % (self.userId, self.firstName, | 502 return '<User %s: %s %s <%s>>' % (self.userId, self.firstName, |
| 588 self.lastName, self.username) | 503 self.lastName, self.username) |
| 589 | 504 |
| 645 # @see self.body for HTTP response body | 560 # @see self.body for HTTP response body |
| 646 raise Exception("Unexpected response from apollo %s: %s" % | 561 raise Exception("Unexpected response from apollo %s: %s" % |
| 647 (r.status_code, r.text)) | 562 (r.status_code, r.text)) |
| 648 | 563 |
| 649 | 564 |
| 650 class MetricsClient(Client): | |
| 651 CLIENT_BASE = '/metrics/' | |
| 652 | |
| 653 def getServerMetrics(self): | |
| 654 return self.get('metrics', {}) | |
| 655 | |
| 656 | |
| 657 class AnnotationsClient(Client): | |
| 658 CLIENT_BASE = '/annotationEditor/' | |
| 659 | |
| 660 def _update_data(self, data): | |
| 661 if not hasattr(self, '_extra_data'): | |
| 662 raise Exception("Please call setSequence first") | |
| 663 | |
| 664 data.update(self._extra_data) | |
| 665 return data | |
| 666 | |
| 667 def setSequence(self, sequence, organism): | |
| 668 self._extra_data = { | |
| 669 'sequence': sequence, | |
| 670 'organism': organism, | |
| 671 } | |
| 672 | |
| 673 def setDescription(self, featureDescriptions): | |
| 674 data = { | |
| 675 'features': featureDescriptions, | |
| 676 } | |
| 677 data = self._update_data(data) | |
| 678 return self.request('setDescription', data) | |
| 679 | |
| 680 def setName(self, uniquename, name): | |
| 681 # TODO | |
| 682 data = { | |
| 683 'features': [ | |
| 684 { | |
| 685 'uniquename': uniquename, | |
| 686 'name': name, | |
| 687 } | |
| 688 ], | |
| 689 } | |
| 690 data = self._update_data(data) | |
| 691 return self.request('setName', data) | |
| 692 | |
| 693 def setNames(self, features): | |
| 694 # TODO | |
| 695 data = { | |
| 696 'features': features, | |
| 697 } | |
| 698 data = self._update_data(data) | |
| 699 return self.request('setName', data) | |
| 700 | |
| 701 def setStatus(self, statuses): | |
| 702 # TODO | |
| 703 data = { | |
| 704 'features': statuses, | |
| 705 } | |
| 706 data = self._update_data(data) | |
| 707 return self.request('setStatus', data) | |
| 708 | |
| 709 def setSymbol(self, symbols): | |
| 710 data = { | |
| 711 'features': symbols, | |
| 712 } | |
| 713 data.update(self._extra_data) | |
| 714 return self.request('setSymbol', data) | |
| 715 | |
| 716 def getComments(self, feature_id): | |
| 717 data = { | |
| 718 'features': [{'uniquename': feature_id}], | |
| 719 } | |
| 720 data = self._update_data(data) | |
| 721 return self.request('getComments', data) | |
| 722 | |
| 723 def addComments(self, feature_id, comments): | |
| 724 # TODO: This is probably not great and will delete comments, if I had to guess... | |
| 725 data = { | |
| 726 'features': [ | |
| 727 { | |
| 728 'uniquename': feature_id, | |
| 729 'comments': comments | |
| 730 } | |
| 731 ], | |
| 732 } | |
| 733 data = self._update_data(data) | |
| 734 return self.request('addComments', data) | |
| 735 | |
| 736 def addAttributes(self, feature_id, attributes): | |
| 737 nrps = [] | |
| 738 for (key, values) in attributes.items(): | |
| 739 for value in values: | |
| 740 nrps.append({ | |
| 741 'tag': key, | |
| 742 'value': value | |
| 743 }) | |
| 744 | |
| 745 data = { | |
| 746 'features': [ | |
| 747 { | |
| 748 'uniquename': feature_id, | |
| 749 'non_reserved_properties': nrps | |
| 750 } | |
| 751 ] | |
| 752 } | |
| 753 data = self._update_data(data) | |
| 754 return self.request('addAttribute', data) | |
| 755 | |
| 756 def deleteAttribute(self, feature_id, key, value): | |
| 757 data = { | |
| 758 'features': [ | |
| 759 { | |
| 760 'uniquename': feature_id, | |
| 761 'non_reserved_properties': [ | |
| 762 {'tag': key, 'value': value} | |
| 763 ] | |
| 764 } | |
| 765 ] | |
| 766 } | |
| 767 data = self._update_data(data) | |
| 768 return self.request('addAttribute', data) | |
| 769 | |
| 770 def getFeatures(self): | |
| 771 data = self._update_data({}) | |
| 772 return self.request('getFeatures', data) | |
| 773 | |
| 774 def getSequence(self, uniquename): | |
| 775 data = { | |
| 776 'features': [ | |
| 777 {'uniquename': uniquename} | |
| 778 ] | |
| 779 } | |
| 780 data = self._update_data(data) | |
| 781 return self.request('getSequence', data) | |
| 782 | |
| 783 def addFeature(self, feature, trustme=False): | |
| 784 if not trustme: | |
| 785 raise NotImplementedError("Waiting on better docs from project. If you know what you are doing, pass trustme=True to this function.") | |
| 786 | |
| 787 data = { | |
| 788 'features': feature, | |
| 789 } | |
| 790 data = self._update_data(data) | |
| 791 return self.request('addFeature', data) | |
| 792 | |
| 793 def addTranscript(self, transcript, trustme=False): | |
| 794 if not trustme: | |
| 795 raise NotImplementedError("Waiting on better docs from project. If you know what you are doing, pass trustme=True to this function.") | |
| 796 | |
| 797 data = {} | |
| 798 data.update(transcript) | |
| 799 data = self._update_data(data) | |
| 800 return self.request('addTranscript', data) | |
| 801 | |
| 802 # addExon, add/delete/updateComments, addTranscript skipped due to docs | |
| 803 | |
| 804 def duplicateTranscript(self, transcriptId): | |
| 805 data = { | |
| 806 'features': [{'uniquename': transcriptId}] | |
| 807 } | |
| 808 | |
| 809 data = self._update_data(data) | |
| 810 return self.request('duplicateTranscript', data) | |
| 811 | |
| 812 def setTranslationStart(self, uniquename, start): | |
| 813 data = { | |
| 814 'features': [{ | |
| 815 'uniquename': uniquename, | |
| 816 'location': { | |
| 817 'fmin': start | |
| 818 } | |
| 819 }] | |
| 820 } | |
| 821 data = self._update_data(data) | |
| 822 return self.request('setTranslationStart', data) | |
| 823 | |
| 824 def setTranslationEnd(self, uniquename, end): | |
| 825 data = { | |
| 826 'features': [{ | |
| 827 'uniquename': uniquename, | |
| 828 'location': { | |
| 829 'fmax': end | |
| 830 } | |
| 831 }] | |
| 832 } | |
| 833 data = self._update_data(data) | |
| 834 return self.request('setTranslationEnd', data) | |
| 835 | |
| 836 def setLongestOrf(self, uniquename): | |
| 837 data = { | |
| 838 'features': [{ | |
| 839 'uniquename': uniquename, | |
| 840 }] | |
| 841 } | |
| 842 data = self._update_data(data) | |
| 843 return self.request('setLongestOrf', data) | |
| 844 | |
| 845 def setBoundaries(self, uniquename, start, end): | |
| 846 data = { | |
| 847 'features': [{ | |
| 848 'uniquename': uniquename, | |
| 849 'location': { | |
| 850 'fmin': start, | |
| 851 'fmax': end, | |
| 852 } | |
| 853 }] | |
| 854 } | |
| 855 data = self._update_data(data) | |
| 856 return self.request('setBoundaries', data) | |
| 857 | |
| 858 def getSequenceAlterations(self): | |
| 859 data = { | |
| 860 } | |
| 861 data = self._update_data(data) | |
| 862 return self.request('getSequenceAlterations', data) | |
| 863 | |
| 864 def setReadthroughStopCodon(self, uniquename): | |
| 865 data = { | |
| 866 'features': [{ | |
| 867 'uniquename': uniquename, | |
| 868 }] | |
| 869 } | |
| 870 data = self._update_data(data) | |
| 871 return self.request('setReadthroughStopCodon', data) | |
| 872 | |
| 873 def deleteSequenceAlteration(self, uniquename): | |
| 874 data = { | |
| 875 'features': [{ | |
| 876 'uniquename': uniquename, | |
| 877 }] | |
| 878 } | |
| 879 data = self._update_data(data) | |
| 880 return self.request('deleteSequenceAlteration', data) | |
| 881 | |
| 882 def flipStrand(self, uniquenames): | |
| 883 data = { | |
| 884 'features': [ | |
| 885 {'uniquename': x} for x in uniquenames | |
| 886 ] | |
| 887 } | |
| 888 data = self._update_data(data) | |
| 889 return self.request('flipStrand', data) | |
| 890 | |
| 891 def mergeExons(self, exonA, exonB): | |
| 892 data = { | |
| 893 'features': [ | |
| 894 {'uniquename': exonA}, | |
| 895 {'uniquename': exonB}, | |
| 896 ] | |
| 897 } | |
| 898 data = self._update_data(data) | |
| 899 return self.request('mergeExons', data) | |
| 900 | |
| 901 # def splitExon(): pass | |
| 902 | |
| 903 def deleteFeatures(self, uniquenames): | |
| 904 assert isinstance(uniquenames, collections.Iterable) | |
| 905 data = { | |
| 906 'features': [ | |
| 907 {'uniquename': x} for x in uniquenames | |
| 908 ] | |
| 909 } | |
| 910 data = self._update_data(data) | |
| 911 return self.request('deleteFeature', data) | |
| 912 | |
| 913 # def deleteExon(): pass | |
| 914 | |
| 915 # def makeIntron(self, uniquename, ): pass | |
| 916 | |
| 917 def getSequenceSearchTools(self): | |
| 918 return self.get('getSequenceSearchTools', {}) | |
| 919 | |
| 920 def getCannedComments(self): | |
| 921 return self.get('getCannedComments', {}) | |
| 922 | |
| 923 def searchSequence(self, searchTool, sequence, database): | |
| 924 data = { | |
| 925 'key': searchTool, | |
| 926 'residues': sequence, | |
| 927 'database_id': database, | |
| 928 } | |
| 929 return self.request('searchSequences', data) | |
| 930 | |
| 931 def getGff3(self, uniquenames): | |
| 932 assert isinstance(uniquenames, collections.Iterable) | |
| 933 data = { | |
| 934 'features': [ | |
| 935 {'uniquename': x} for x in uniquenames | |
| 936 ] | |
| 937 } | |
| 938 data = self._update_data(data) | |
| 939 return self.request('getGff3', data, isJson=False) | |
| 940 | |
| 941 | |
| 942 class GroupsClient(Client): | 565 class GroupsClient(Client): |
| 943 CLIENT_BASE = '/group/' | 566 CLIENT_BASE = '/group/' |
| 944 | |
| 945 def createGroup(self, name): | |
| 946 data = {'name': name} | |
| 947 return self.request('createGroup', data) | |
| 948 | |
| 949 def getOrganismPermissionsForGroup(self, group): | |
| 950 data = { | |
| 951 'id': group.groupId, | |
| 952 'name': group.name, | |
| 953 } | |
| 954 return self.request('getOrganismPermissionsForGroup', data) | |
| 955 | |
| 956 def loadGroup(self, group): | |
| 957 return self.loadGroupById(group.groupId) | |
| 958 | |
| 959 def loadGroupById(self, groupId): | |
| 960 res = self.request('loadGroups', {'groupId': groupId}) | |
| 961 if isinstance(res, list): | |
| 962 # We can only match one, right? | |
| 963 return GroupObj(**res[0]) | |
| 964 else: | |
| 965 return res | |
| 966 | |
| 967 def loadGroupByName(self, name): | |
| 968 res = self.request('loadGroups', {'name': name}) | |
| 969 if isinstance(res, list): | |
| 970 # We can only match one, right? | |
| 971 return GroupObj(**res[0]) | |
| 972 else: | |
| 973 return res | |
| 974 | 567 |
| 975 def loadGroups(self, group=None): | 568 def loadGroups(self, group=None): |
| 976 res = self.request('loadGroups', {}) | 569 res = self.request('loadGroups', {}) |
| 977 data = [GroupObj(**x) for x in res] | 570 data = [GroupObj(**x) for x in res] |
| 978 if group is not None: | 571 if group is not None: |
| 979 data = [x for x in data if x.name == group] | 572 data = [x for x in data if x.name == group] |
| 980 | 573 |
| 981 return data | 574 return data |
| 982 | 575 |
| 983 def deleteGroup(self, group): | |
| 984 data = { | |
| 985 'id': group.groupId, | |
| 986 'name': group.name, | |
| 987 } | |
| 988 return self.request('deleteGroup', data) | |
| 989 | |
| 990 def updateGroup(self, group, newName): | |
| 991 # TODO: Sure would be nice if modifying ``group.name`` would invoke | |
| 992 # this? | |
| 993 data = { | |
| 994 'id': group.groupId, | |
| 995 'name': newName, | |
| 996 } | |
| 997 return self.request('updateGroup', data) | |
| 998 | |
| 999 def updateOrganismPermission(self, group, organismName, | |
| 1000 administrate=False, write=False, read=False, | |
| 1001 export=False): | |
| 1002 data = { | |
| 1003 'groupId': group.groupId, | |
| 1004 'organism': organismName, | |
| 1005 'ADMINISTRATE': administrate, | |
| 1006 'WRITE': write, | |
| 1007 'EXPORT': export, | |
| 1008 'READ': read, | |
| 1009 } | |
| 1010 return self.request('updateOrganismPermission', data) | |
| 1011 | |
| 1012 def updateMembership(self, group, users): | |
| 1013 data = { | |
| 1014 'groupId': group.groupId, | |
| 1015 'user': [user.email for user in users] | |
| 1016 } | |
| 1017 return self.request('updateMembership', data) | |
| 1018 | |
| 1019 | |
| 1020 class IOClient(Client): | |
| 1021 CLIENT_BASE = '/IOService/' | |
| 1022 | |
| 1023 def write(self, exportType='FASTA', seqType='peptide', | |
| 1024 exportFormat='text', sequences=None, organism=None, | |
| 1025 output='text', exportAllSequences=False, | |
| 1026 exportGff3Fasta=False): | |
| 1027 if exportType not in ('FASTA', 'GFF3'): | |
| 1028 raise Exception("exportType must be one of FASTA, GFF3") | |
| 1029 | |
| 1030 if seqType not in ('peptide', 'cds', 'cdna', 'genomic'): | |
| 1031 raise Exception("seqType must be one of peptide, cds, dna, genomic") | |
| 1032 | |
| 1033 if exportFormat not in ('gzip', 'text'): | |
| 1034 raise Exception("exportFormat must be one of gzip, text") | |
| 1035 | |
| 1036 if output not in ('file', 'text'): | |
| 1037 raise Exception("output must be one of file, text") | |
| 1038 | |
| 1039 data = { | |
| 1040 'type': exportType, | |
| 1041 'seqType': seqType, | |
| 1042 'format': exportFormat, | |
| 1043 'sequences': sequences, | |
| 1044 'organism': organism, | |
| 1045 'output': output, | |
| 1046 'exportAllSequences': exportAllSequences, | |
| 1047 'exportGff3Fasta': exportGff3Fasta, | |
| 1048 } | |
| 1049 | |
| 1050 return self.request('write', data, isJson=output == 'file') | |
| 1051 | |
| 1052 def download(self, uuid, outputFormat='gzip'): | |
| 1053 | |
| 1054 if outputFormat.lower() not in ('gzip', 'text'): | |
| 1055 raise Exception("outputFormat must be one of file, text") | |
| 1056 | |
| 1057 data = { | |
| 1058 'format': outputFormat, | |
| 1059 'uuid': uuid, | |
| 1060 } | |
| 1061 return self.request('write', data) | |
| 1062 | |
| 1063 | |
| 1064 class StatusClient(Client): | |
| 1065 CLIENT_BASE = '/availableStatus/' | |
| 1066 | |
| 1067 def addStatus(self, value): | |
| 1068 data = { | |
| 1069 'value': value | |
| 1070 } | |
| 1071 | |
| 1072 return self.request('createStatus', data) | |
| 1073 | |
| 1074 def findAllStatuses(self): | |
| 1075 return self.request('showStatus', {}) | |
| 1076 | |
| 1077 def findStatusByValue(self, value): | |
| 1078 statuses = self.findAllStatuses() | |
| 1079 statuses = [x for x in statuses if x['value'] == value] | |
| 1080 if len(statuses) == 0: | |
| 1081 raise Exception("Unknown status value") | |
| 1082 else: | |
| 1083 return statuses[0] | |
| 1084 | |
| 1085 def findStatusById(self, id_number): | |
| 1086 statuses = self.findAllStatuses() | |
| 1087 statuses = [x for x in statuses if str(x['id']) == str(id_number)] | |
| 1088 if len(statuses) == 0: | |
| 1089 raise Exception("Unknown ID") | |
| 1090 else: | |
| 1091 return statuses[0] | |
| 1092 | |
| 1093 def updateStatus(self, id_number, new_value): | |
| 1094 data = { | |
| 1095 'id': id_number, | |
| 1096 'new_value': new_value | |
| 1097 } | |
| 1098 | |
| 1099 return self.request('updateStatus', data) | |
| 1100 | |
| 1101 def deleteStatus(self, id_number): | |
| 1102 data = { | |
| 1103 'id': id_number | |
| 1104 } | |
| 1105 | |
| 1106 return self.request('deleteStatus', data) | |
| 1107 | |
| 1108 | |
| 1109 class CannedCommentsClient(Client): | |
| 1110 CLIENT_BASE = '/cannedComment/' | |
| 1111 | |
| 1112 def addComment(self, comment, metadata=""): | |
| 1113 data = { | |
| 1114 'comment': comment, | |
| 1115 'metadata': metadata | |
| 1116 } | |
| 1117 | |
| 1118 return self.request('createComment', data) | |
| 1119 | |
| 1120 def findAllComments(self): | |
| 1121 return self.request('showComment', {}) | |
| 1122 | |
| 1123 def findCommentByValue(self, value): | |
| 1124 comments = self.findAllComments() | |
| 1125 comments = [x for x in comments if x['comment'] == value] | |
| 1126 if len(comments) == 0: | |
| 1127 raise Exception("Unknown comment") | |
| 1128 else: | |
| 1129 return comments[0] | |
| 1130 | |
| 1131 def findCommentById(self, id_number): | |
| 1132 comments = self.findAllComments() | |
| 1133 comments = [x for x in comments if str(x['id']) == str(id_number)] | |
| 1134 if len(comments) == 0: | |
| 1135 raise Exception("Unknown ID") | |
| 1136 else: | |
| 1137 return comments[0] | |
| 1138 | |
| 1139 def updateComment(self, id_number, new_value, metadata=None): | |
| 1140 data = { | |
| 1141 'id': id_number, | |
| 1142 'new_comment': new_value | |
| 1143 } | |
| 1144 | |
| 1145 if metadata is not None: | |
| 1146 data['metadata'] = metadata | |
| 1147 | |
| 1148 return self.request('updateComment', data) | |
| 1149 | |
| 1150 def deleteComment(self, id_number): | |
| 1151 data = { | |
| 1152 'id': id_number | |
| 1153 } | |
| 1154 | |
| 1155 return self.request('deleteComment', data) | |
| 1156 | |
| 1157 | |
| 1158 class CannedKeysClient(Client): | |
| 1159 CLIENT_BASE = '/cannedKey/' | |
| 1160 | |
| 1161 def addKey(self, key, metadata=""): | |
| 1162 data = { | |
| 1163 'key': key, | |
| 1164 'metadata': metadata | |
| 1165 } | |
| 1166 | |
| 1167 return self.request('createKey', data) | |
| 1168 | |
| 1169 def findAllKeys(self): | |
| 1170 return self.request('showKey', {}) | |
| 1171 | |
| 1172 def findKeyByValue(self, value): | |
| 1173 keys = self.findAllKeys() | |
| 1174 keys = [x for x in keys if x['label'] == value] | |
| 1175 if len(keys) == 0: | |
| 1176 raise Exception("Unknown key") | |
| 1177 else: | |
| 1178 return keys[0] | |
| 1179 | |
| 1180 def findKeyById(self, id_number): | |
| 1181 keys = self.findAllKeys() | |
| 1182 keys = [x for x in keys if str(x['id']) == str(id_number)] | |
| 1183 if len(keys) == 0: | |
| 1184 raise Exception("Unknown ID") | |
| 1185 else: | |
| 1186 return keys[0] | |
| 1187 | |
| 1188 def updateKey(self, id_number, new_key, metadata=None): | |
| 1189 data = { | |
| 1190 'id': id_number, | |
| 1191 'new_key': new_key | |
| 1192 } | |
| 1193 | |
| 1194 if metadata is not None: | |
| 1195 data['metadata'] = metadata | |
| 1196 | |
| 1197 return self.request('updateKey', data) | |
| 1198 | |
| 1199 def deleteKey(self, id_number): | |
| 1200 data = { | |
| 1201 'id': id_number | |
| 1202 } | |
| 1203 | |
| 1204 return self.request('deleteKey', data) | |
| 1205 | |
| 1206 | |
| 1207 class CannedValuesClient(Client): | |
| 1208 CLIENT_BASE = '/cannedValue/' | |
| 1209 | |
| 1210 def addValue(self, value, metadata=""): | |
| 1211 data = { | |
| 1212 'value': value, | |
| 1213 'metadata': metadata | |
| 1214 } | |
| 1215 | |
| 1216 return self.request('createValue', data) | |
| 1217 | |
| 1218 def findAllValues(self): | |
| 1219 return self.request('showValue', {}) | |
| 1220 | |
| 1221 def findValueByValue(self, value): | |
| 1222 values = self.findAllValues() | |
| 1223 values = [x for x in values if x['label'] == value] | |
| 1224 if len(values) == 0: | |
| 1225 raise Exception("Unknown value") | |
| 1226 else: | |
| 1227 return values[0] | |
| 1228 | |
| 1229 def findValueById(self, id_number): | |
| 1230 values = self.findAllValues() | |
| 1231 values = [x for x in values if str(x['id']) == str(id_number)] | |
| 1232 if len(values) == 0: | |
| 1233 raise Exception("Unknown ID") | |
| 1234 else: | |
| 1235 return values[0] | |
| 1236 | |
| 1237 def updateValue(self, id_number, new_value, metadata=None): | |
| 1238 data = { | |
| 1239 'id': id_number, | |
| 1240 'new_value': new_value | |
| 1241 } | |
| 1242 | |
| 1243 if metadata is not None: | |
| 1244 data['metadata'] = metadata | |
| 1245 | |
| 1246 return self.request('updateValue', data) | |
| 1247 | |
| 1248 def deleteValue(self, id_number): | |
| 1249 data = { | |
| 1250 'id': id_number | |
| 1251 } | |
| 1252 | |
| 1253 return self.request('deleteValue', data) | |
| 1254 | |
| 1255 | 576 |
| 1256 class OrganismsClient(Client): | 577 class OrganismsClient(Client): |
| 1257 CLIENT_BASE = '/organism/' | 578 CLIENT_BASE = '/organism/' |
| 1258 | |
| 1259 def addOrganism(self, commonName, directory, blatdb=None, species=None, | |
| 1260 genus=None, public=False): | |
| 1261 data = { | |
| 1262 'commonName': commonName, | |
| 1263 'directory': directory, | |
| 1264 'publicMode': public, | |
| 1265 } | |
| 1266 | |
| 1267 if blatdb is not None: | |
| 1268 data['blatdb'] = blatdb | |
| 1269 if genus is not None: | |
| 1270 data['genus'] = genus | |
| 1271 if species is not None: | |
| 1272 data['species'] = species | |
| 1273 | |
| 1274 return self.request('addOrganism', data) | |
| 1275 | 579 |
| 1276 def findAllOrganisms(self): | 580 def findAllOrganisms(self): |
| 1277 orgs = self.request('findAllOrganisms', {}) | 581 orgs = self.request('findAllOrganisms', {}) |
| 1278 if not isinstance(orgs, (list,)): | 582 if not isinstance(orgs, (list,)): |
| 1279 orgs = [] | 583 orgs = [] |
| 1280 return orgs | 584 return orgs |
| 1281 | 585 |
| 1282 def findOrganismByCn(self, cn): | |
| 1283 orgs = self.findAllOrganisms() | |
| 1284 orgs = [x for x in orgs if x['commonName'] == cn] | |
| 1285 if len(orgs) == 0: | |
| 1286 raise Exception("Unknown common name") | |
| 1287 else: | |
| 1288 return orgs[0] | |
| 1289 | |
| 1290 def findOrganismById(self, id_number): | |
| 1291 orgs = self.findAllOrganisms() | |
| 1292 orgs = [x for x in orgs if str(x['id']) == str(id_number)] | |
| 1293 if len(orgs) == 0: | |
| 1294 raise Exception("Unknown ID") | |
| 1295 else: | |
| 1296 return orgs[0] | |
| 1297 | |
| 1298 def deleteOrganism(self, organismId): | |
| 1299 return self.request('deleteOrganism', {'id': organismId}) | |
| 1300 | |
| 1301 def deleteOrganismFeatures(self, organismId): | |
| 1302 return self.request('deleteOrganismFeatures', {'id': organismId}) | |
| 1303 | |
| 1304 def getSequencesForOrganism(self, commonName): | |
| 1305 return self.request('getSequencesForOrganism', {'organism': commonName}) | |
| 1306 | |
| 1307 def updateOrganismInfo(self, organismId, commonName, directory, blatdb=None, species=None, genus=None, public=False): | |
| 1308 data = { | |
| 1309 'id': organismId, | |
| 1310 'name': commonName, | |
| 1311 'directory': directory, | |
| 1312 'publicMode': public, | |
| 1313 } | |
| 1314 | |
| 1315 if blatdb is not None: | |
| 1316 data['blatdb'] = blatdb | |
| 1317 if genus is not None: | |
| 1318 data['genus'] = genus | |
| 1319 if species is not None: | |
| 1320 data['species'] = species | |
| 1321 | |
| 1322 return self.request('updateOrganismInfo', data) | |
| 1323 | |
| 1324 | 586 |
| 1325 class UsersClient(Client): | 587 class UsersClient(Client): |
| 1326 CLIENT_BASE = '/user/' | 588 CLIENT_BASE = '/user/' |
| 1327 | 589 |
| 1328 # Real one | 590 def loadUsers(self): |
| 1329 # def getOrganismPermissionsForUser(self, user): | |
| 1330 # data = { | |
| 1331 # 'userId': user.userId, | |
| 1332 # } | |
| 1333 # return self.request('getOrganismPermissionsForUser', data) | |
| 1334 | |
| 1335 # Utter frigging hack | |
| 1336 def getOrganismPermissionsForUser(self, user): | |
| 1337 return self.loadUser(user).organismPermissions | |
| 1338 | |
| 1339 def updateOrganismPermission(self, user, organism, administrate=False, | |
| 1340 write=False, export=False, read=False): | |
| 1341 data = { | |
| 1342 'userId': user.userId, | |
| 1343 'organism': organism, | |
| 1344 'ADMINISTRATE': administrate, | |
| 1345 'WRITE': write, | |
| 1346 'EXPORT': export, | |
| 1347 'READ': read, | |
| 1348 } | |
| 1349 return self.request('updateOrganismPermission', data) | |
| 1350 | |
| 1351 def loadUser(self, user): | |
| 1352 return self.loadUserById(user.userId) | |
| 1353 | |
| 1354 def loadUserById(self, userId): | |
| 1355 res = self.request('loadUsers', {'userId': userId}) | |
| 1356 if isinstance(res, list): | |
| 1357 # We can only match one, right? | |
| 1358 return UserObj(**res[0]) | |
| 1359 else: | |
| 1360 return res | |
| 1361 | |
| 1362 def loadUsers(self, email=None): | |
| 1363 res = self.request('loadUsers', {}) | 591 res = self.request('loadUsers', {}) |
| 592 | |
| 1364 data = [UserObj(**x) for x in res] | 593 data = [UserObj(**x) for x in res] |
| 1365 if email is not None: | |
| 1366 data = [x for x in data if x.username == email] | |
| 1367 | 594 |
| 1368 return data | 595 return data |
| 1369 | 596 |
| 1370 def addUserToGroup(self, group, user): | 597 |
| 1371 data = {'group': group.name, 'userId': user.userId} | 598 def handle_credentials(user): |
| 1372 return self.request('addUserToGroup', data) | 599 if hasattr(user, 'new_password'): |
| 1373 | 600 f = open("Apollo_credentials.txt", "w") |
| 1374 def removeUserFromGroup(self, group, user): | 601 f.write('Username:\t%s\nPassword:\t%s' % (user.username, user.new_password)) |
| 1375 data = {'group': group.name, 'userId': user.userId} | |
| 1376 return self.request('removeUserFromGroup', data) | |
| 1377 | |
| 1378 def createUser(self, email, firstName, lastName, newPassword, role="user", groups=None, addToHistory=False): | |
| 1379 data = { | |
| 1380 'firstName': firstName, | |
| 1381 'lastName': lastName, | |
| 1382 'email': email, | |
| 1383 'role': role, | |
| 1384 'groups': [] if groups is None else groups, | |
| 1385 # 'availableGroups': [], | |
| 1386 'newPassword': newPassword, | |
| 1387 # 'organismPermissions': [], | |
| 1388 } | |
| 1389 returnData = self.request('createUser', data) | |
| 1390 if addToHistory and not IsRemoteUser(): | |
| 1391 f = open("Apollo_credentials.txt", "w") | |
| 1392 f.write('Username: %s\tPassword: %s' % (email, newPassword)) | |
| 1393 return returnData | |
| 1394 | |
| 1395 def assertOrCreateUser(self, email): | |
| 1396 try: | |
| 1397 gx_user = AssertUser(self.loadUsers(email)) | |
| 1398 except Exception: | |
| 1399 self.createUser(email, email, email, PasswordGenerator(12), role='user', addToHistory=True) | |
| 1400 gx_user = AssertUser(self.loadUsers(email)) | |
| 1401 return gx_user | |
| 1402 | |
| 1403 def deleteUser(self, user): | |
| 1404 return self.request('deleteUser', {'userId': user.userId}) | |
| 1405 | |
| 1406 def updateUser(self, user, email, firstName, lastName, newPassword): | |
| 1407 data = { | |
| 1408 'userId': user.userId, | |
| 1409 'email': email, | |
| 1410 'firstName': firstName, | |
| 1411 'lastName': lastName, | |
| 1412 'newPassword': newPassword, | |
| 1413 } | |
| 1414 return self.request('updateUser', data) | |
| 1415 | |
| 1416 | |
| 1417 class RemoteRecord(Client): | |
| 1418 CLIENT_BASE = None | |
| 1419 | |
| 1420 def ParseRecord(self, cn): | |
| 1421 org = self._wa.organisms.findOrganismByCn(cn) | |
| 1422 self._wa.annotations.setSequence(org['commonName'], org['id']) | |
| 1423 | |
| 1424 data = io.StringIO(self._wa.io.write( | |
| 1425 exportType='GFF3', | |
| 1426 seqType='genomic', | |
| 1427 exportAllSequences=False, | |
| 1428 exportGff3Fasta=True, | |
| 1429 output="text", | |
| 1430 exportFormat="text", | |
| 1431 sequences=cn, | |
| 1432 )) | |
| 1433 data.seek(0) | |
| 1434 | |
| 1435 for record in GFF.parse(data): | |
| 1436 yield WebApolloSeqRecord(record, self._wa) | |
| 1437 | |
| 1438 | |
| 1439 class WebApolloSeqRecord(object): | |
| 1440 def __init__(self, sr, wa): | |
| 1441 self._sr = sr | |
| 1442 self._wa = wa | |
| 1443 | |
| 1444 def __dir__(self): | |
| 1445 return dir(self._sr) | |
| 1446 | |
| 1447 def __getattr__(self, key): | |
| 1448 if key in ('_sr', '_wa'): | |
| 1449 return self.__dict__[key] | |
| 1450 else: | |
| 1451 if key == 'features': | |
| 1452 return (WebApolloSeqFeature(x, self._wa) | |
| 1453 for x in self._sr.__dict__[key]) | |
| 1454 else: | |
| 1455 return self._sr.__dict__[key] | |
| 1456 | |
| 1457 def __setattr__(self, key, value): | |
| 1458 if key in ('_sd', '_wa'): | |
| 1459 self.__dict__[key] = value | |
| 1460 else: | |
| 1461 self._sr.__dict__[key] = value | |
| 1462 # Methods acting on the SeqRecord object | |
| 1463 | |
| 1464 | |
| 1465 class WebApolloSeqFeature(object): | |
| 1466 def __init__(self, sf, wa): | |
| 1467 self._sf = sf | |
| 1468 self._wa = wa | |
| 1469 | |
| 1470 def __dir__(self): | |
| 1471 return dir(self._sf) | |
| 1472 | |
| 1473 def __getattr__(self, key): | |
| 1474 if key in ('_sf', '_wa'): | |
| 1475 return self.__dict__[key] | |
| 1476 else: | |
| 1477 return self._sf.__dict__[key] | |
| 1478 | |
| 1479 def __setattr__(self, key, value): | |
| 1480 if key in ('_sf', '_wa'): | |
| 1481 self.__dict__[key] = value | |
| 1482 else: | |
| 1483 # Methods acting on the SeqFeature object | |
| 1484 if key == 'location': | |
| 1485 if value.strand != self._sf.location.strand: | |
| 1486 self.wa.annotations.flipStrand( | |
| 1487 self._sf.qualifiers['ID'][0] | |
| 1488 ) | |
| 1489 | |
| 1490 self.wa.annotations.setBoundaries( | |
| 1491 self._sf.qualifiers['ID'][0], | |
| 1492 value.start, | |
| 1493 value.end, | |
| 1494 ) | |
| 1495 | |
| 1496 self._sf.__dict__[key] = value | |
| 1497 else: | |
| 1498 self._sf.__dict__[key] = value | |
| 1499 | |
| 1500 | |
| 1501 def _tnType(feature): | |
| 1502 if feature.type in ('gene', 'mRNA', 'exon', 'CDS', 'terminator', 'tRNA'): | |
| 1503 return feature.type | |
| 1504 else: | |
| 1505 return 'exon' | |
| 1506 | |
| 1507 | |
| 1508 def _yieldFeatData(features): | |
| 1509 for f in features: | |
| 1510 current = { | |
| 1511 'location': { | |
| 1512 'strand': f.strand, | |
| 1513 'fmin': int(f.location.start), | |
| 1514 'fmax': int(f.location.end), | |
| 1515 }, | |
| 1516 'type': { | |
| 1517 'name': _tnType(f), | |
| 1518 'cv': { | |
| 1519 'name': 'sequence', | |
| 1520 } | |
| 1521 }, | |
| 1522 } | |
| 1523 if f.type in ('gene', 'mRNA'): | |
| 1524 current['name'] = f.qualifiers.get('Name', [f.id])[0] | |
| 1525 if hasattr(f, 'sub_features') and len(f.sub_features) > 0: | |
| 1526 current['children'] = [x for x in _yieldFeatData(f.sub_features)] | |
| 1527 | |
| 1528 yield current | |
| 1529 | |
| 1530 | |
| 1531 def featuresToFeatureSchema(features): | |
| 1532 compiled = [] | |
| 1533 for feature in features: | |
| 1534 # if feature.type != 'gene': | |
| 1535 # log.warn("Not able to handle %s features just yet...", feature.type) | |
| 1536 # continue | |
| 1537 | |
| 1538 for x in _yieldFeatData([feature]): | |
| 1539 compiled.append(x) | |
| 1540 return compiled | |
| 1541 | 602 |
| 1542 | 603 |
| 1543 def accessible_organisms(user, orgs): | 604 def accessible_organisms(user, orgs): |
| 1544 permissionMap = { | 605 permissionMap = { |
| 1545 x['organism']: x['permissions'] | 606 x['organism']: x['permissions'] |
| 1557 ] | 618 ] |
| 1558 | 619 |
| 1559 | 620 |
| 1560 def galaxy_list_groups(trans, *args, **kwargs): | 621 def galaxy_list_groups(trans, *args, **kwargs): |
| 1561 email = trans.get_user().email | 622 email = trans.get_user().email |
| 1562 wa = WebApolloInstance( | 623 wa = WebApolloInstance() |
| 1563 os.environ['GALAXY_WEBAPOLLO_URL'], | |
| 1564 os.environ['GALAXY_WEBAPOLLO_USER'], | |
| 1565 os.environ['GALAXY_WEBAPOLLO_PASSWORD'] | |
| 1566 ) | |
| 1567 | 624 |
| 1568 # Key for cached data | 625 # Key for cached data |
| 1569 cacheKey = 'groups-' + email | 626 cacheKey = 'groups-' + email |
| 1570 # We don't want to trust "if key in cache" because between asking and fetch | 627 # We don't want to trust "if key in cache" because between asking and fetch |
| 1571 # it might through key error. | 628 # it might through key error. |
| 1599 return group_data | 656 return group_data |
| 1600 | 657 |
| 1601 | 658 |
| 1602 def galaxy_list_orgs(trans, *args, **kwargs): | 659 def galaxy_list_orgs(trans, *args, **kwargs): |
| 1603 email = trans.get_user().email | 660 email = trans.get_user().email |
| 1604 wa = WebApolloInstance( | 661 wa = WebApolloInstance() |
| 1605 os.environ['GALAXY_WEBAPOLLO_URL'], | |
| 1606 os.environ['GALAXY_WEBAPOLLO_USER'], | |
| 1607 os.environ['GALAXY_WEBAPOLLO_PASSWORD'] | |
| 1608 ) | |
| 1609 try: | 662 try: |
| 1610 gx_user = wa.requireUser(email) | 663 gx_user = wa.requireUser(email) |
| 1611 except UnknownUserException: | 664 except UnknownUserException: |
| 1612 return [] | 665 return [] |
| 1613 | 666 |
| 1633 orgs = accessible_organisms(gx_user, all_orgs) | 686 orgs = accessible_organisms(gx_user, all_orgs) |
| 1634 # Return org list | 687 # Return org list |
| 1635 return orgs | 688 return orgs |
| 1636 | 689 |
| 1637 | 690 |
| 1638 def galaxy_list_users(trans, *args, **kwargs): | |
| 1639 email = trans.get_user().email | |
| 1640 wa = WebApolloInstance( | |
| 1641 os.environ['GALAXY_WEBAPOLLO_URL'], | |
| 1642 os.environ['GALAXY_WEBAPOLLO_USER'], | |
| 1643 os.environ['GALAXY_WEBAPOLLO_PASSWORD'] | |
| 1644 ) | |
| 1645 # Assert that the email exists in apollo | |
| 1646 try: | |
| 1647 gx_user = wa.requireUser(email) | |
| 1648 except UnknownUserException: | |
| 1649 return [] | |
| 1650 | |
| 1651 # Key for cached data | |
| 1652 cacheKey = 'users-' + email | |
| 1653 # We don't want to trust "if key in cache" because between asking and fetch | |
| 1654 # it might through key error. | |
| 1655 if cacheKey not in cache: | |
| 1656 # However if it ISN'T there, we know we're safe to fetch + put in | |
| 1657 # there. | |
| 1658 data = _galaxy_list_users(wa, gx_user, *args, **kwargs) | |
| 1659 cache[cacheKey] = data | |
| 1660 return data | |
| 1661 try: | |
| 1662 # The cache key may or may not be in the cache at this point, it | |
| 1663 # /likely/ is. However we take no chances that it wasn't evicted between | |
| 1664 # when we checked above and now, so we reference the object from the | |
| 1665 # cache in preparation to return. | |
| 1666 data = cache[cacheKey] | |
| 1667 return data | |
| 1668 except KeyError: | |
| 1669 # If access fails due to eviction, we will fail over and can ensure that | |
| 1670 # data is inserted. | |
| 1671 data = _galaxy_list_users(wa, gx_user, *args, **kwargs) | |
| 1672 cache[cacheKey] = data | |
| 1673 return data | |
| 1674 | |
| 1675 | |
| 1676 def _galaxy_list_users(wa, gx_user, *args, **kwargs): | |
| 1677 # Fetch the users. | |
| 1678 user_data = [] | |
| 1679 for user in wa.users.loadUsers(): | |
| 1680 # Reformat | |
| 1681 user_data.append((user.username, user.username, False)) | |
| 1682 return user_data | |
| 1683 | |
| 1684 | |
| 1685 # This is all for implementing the command line interface for testing. | 691 # This is all for implementing the command line interface for testing. |
| 1686 class obj(object): | 692 class obj(object): |
| 1687 pass | 693 pass |
| 1688 | 694 |
| 1689 | 695 |
| 1696 o = obj() | 702 o = obj() |
| 1697 o.email = self.un | 703 o.email = self.un |
| 1698 return o | 704 return o |
| 1699 | 705 |
| 1700 | 706 |
| 1701 def retry(closure, sleep=1, limit=5): | |
| 1702 """ | |
| 1703 Apollo has the bad habit of returning 500 errors if you call APIs | |
| 1704 too quickly, largely because of the unholy things that happen in | |
| 1705 grails. | |
| 1706 | |
| 1707 To deal with the fact that we cannot send an addComments call too | |
| 1708 quickly after a createFeature call, we have this function that will | |
| 1709 keep calling a closure until it works. | |
| 1710 """ | |
| 1711 count = 0 | |
| 1712 while True: | |
| 1713 count += 1 | |
| 1714 | |
| 1715 if count >= limit: | |
| 1716 return False | |
| 1717 try: | |
| 1718 # Try calling it | |
| 1719 closure() | |
| 1720 # If successful, exit | |
| 1721 return True | |
| 1722 except Exception as e: | |
| 1723 log.info(str(e)[0:100]) | |
| 1724 time.sleep(sleep) | |
| 1725 | |
| 1726 | |
| 1727 if __name__ == '__main__': | 707 if __name__ == '__main__': |
| 1728 parser = argparse.ArgumentParser(description='Test access to apollo server') | 708 parser = argparse.ArgumentParser(description='Test access to apollo server') |
| 1729 parser.add_argument('email', help='Email of user to test') | 709 parser.add_argument('email', help='Email of user to test') |
| 1730 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.') | 710 parser.add_argument('--action', choices=['org', 'group'], default='org', help='Data set to test, fetch a list of groups or orgs known to the requesting user.') |
| 1731 args = parser.parse_args() | 711 args = parser.parse_args() |
| 1732 | 712 |
| 1733 trans = fakeTrans(args.email) | 713 trans = fakeTrans(args.email) |
| 1734 if args.action == 'org': | 714 if args.action == 'org': |
| 1735 for f in galaxy_list_orgs(trans): | 715 print(galaxy_list_orgs(trans)) |
| 1736 print(f) | |
| 1737 elif args.action == 'group': | 716 elif args.action == 'group': |
| 1738 for f in galaxy_list_groups(trans): | 717 print(galaxy_list_groups(trans)) |
| 1739 print(f) | |
| 1740 else: | |
| 1741 for f in galaxy_list_users(trans): | |
| 1742 print(f) |
