basepair 1.5__0-py3.8.egg

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. EGG-INFO/PKG-INFO +27 -0
  2. EGG-INFO/SOURCES.txt +38 -0
  3. EGG-INFO/dependency_links.txt +1 -0
  4. EGG-INFO/requires.txt +5 -0
  5. EGG-INFO/scripts/basepair +637 -0
  6. EGG-INFO/top_level.txt +1 -0
  7. EGG-INFO/zip-safe +1 -0
  8. basepair/__init__.py +32 -0
  9. basepair/__pycache__/__init__.cpython-38.pyc +0 -0
  10. basepair/__pycache__/api.cpython-38.pyc +0 -0
  11. basepair/api.py +1353 -0
  12. basepair/helpers/__init__.py +3 -0
  13. basepair/helpers/__pycache__/__init__.cpython-38.pyc +0 -0
  14. basepair/helpers/__pycache__/eprint.cpython-38.pyc +0 -0
  15. basepair/helpers/__pycache__/nice_print.cpython-38.pyc +0 -0
  16. basepair/helpers/__pycache__/set_filter.cpython-38.pyc +0 -0
  17. basepair/helpers/eprint.py +8 -0
  18. basepair/helpers/nice_print.py +170 -0
  19. basepair/helpers/set_filter.py +18 -0
  20. basepair/infra/__init__.py +0 -0
  21. basepair/infra/__pycache__/__init__.cpython-38.pyc +0 -0
  22. basepair/infra/configuration/__init__.py +1 -0
  23. basepair/infra/configuration/__pycache__/__init__.cpython-38.pyc +0 -0
  24. basepair/infra/configuration/__pycache__/parser.cpython-38.pyc +0 -0
  25. basepair/infra/configuration/parser.py +67 -0
  26. basepair/infra/webapp/__init__.py +12 -0
  27. basepair/infra/webapp/__pycache__/__init__.cpython-38.pyc +0 -0
  28. basepair/infra/webapp/__pycache__/abstract.cpython-38.pyc +0 -0
  29. basepair/infra/webapp/__pycache__/analysis.cpython-38.pyc +0 -0
  30. basepair/infra/webapp/__pycache__/file.cpython-38.pyc +0 -0
  31. basepair/infra/webapp/__pycache__/gene.cpython-38.pyc +0 -0
  32. basepair/infra/webapp/__pycache__/genome.cpython-38.pyc +0 -0
  33. basepair/infra/webapp/__pycache__/genome_file.cpython-38.pyc +0 -0
  34. basepair/infra/webapp/__pycache__/host.cpython-38.pyc +0 -0
  35. basepair/infra/webapp/__pycache__/module.cpython-38.pyc +0 -0
  36. basepair/infra/webapp/__pycache__/pipeline.cpython-38.pyc +0 -0
  37. basepair/infra/webapp/__pycache__/project.cpython-38.pyc +0 -0
  38. basepair/infra/webapp/__pycache__/sample.cpython-38.pyc +0 -0
  39. basepair/infra/webapp/__pycache__/upload.cpython-38.pyc +0 -0
  40. basepair/infra/webapp/__pycache__/user.cpython-38.pyc +0 -0
  41. basepair/infra/webapp/abstract.py +128 -0
  42. basepair/infra/webapp/analysis.py +10 -0
  43. basepair/infra/webapp/file.py +10 -0
  44. basepair/infra/webapp/gene.py +10 -0
  45. basepair/infra/webapp/genome.py +10 -0
  46. basepair/infra/webapp/genome_file.py +10 -0
  47. basepair/infra/webapp/host.py +10 -0
  48. basepair/infra/webapp/module.py +10 -0
  49. basepair/infra/webapp/pipeline.py +10 -0
  50. basepair/infra/webapp/project.py +10 -0
  51. basepair/infra/webapp/sample.py +10 -0
  52. basepair/infra/webapp/upload.py +10 -0
  53. basepair/infra/webapp/user.py +48 -0
  54. basepair/utils/__init__.py +0 -0
  55. basepair/utils/__pycache__/__init__.cpython-38.pyc +0 -0
  56. basepair/utils/__pycache__/colors.cpython-38.pyc +0 -0
  57. basepair/utils/__pycache__/monitor.cpython-38.pyc +0 -0
  58. basepair/utils/__pycache__/s3.cpython-38.pyc +0 -0
  59. basepair/utils/__pycache__/sqs.cpython-38.pyc +0 -0
  60. basepair/utils/__pycache__/swf.cpython-38.pyc +0 -0
  61. basepair/utils/colors.py +43 -0
  62. basepair/utils/monitor.py +38 -0
  63. basepair/utils/s3.py +77 -0
  64. basepair/utils/sqs.py +147 -0
  65. basepair/utils/swf.py +129 -0
@@ -0,0 +1,3 @@
1
+ from .eprint import eprint
2
+ from .nice_print import NicePrint
3
+ from .set_filter import SetFilter
@@ -0,0 +1,8 @@
1
+ '''Helper for print in stderr'''
2
+
3
+ # General imports
4
+ import sys
5
+
6
+ def eprint(*args, **kwargs):
7
+ '''print in sys.stderr'''
8
+ print(*args, file=sys.stderr, **kwargs)
@@ -0,0 +1,170 @@
1
+ '''Helper to print object nicely'''
2
+
3
+ # General imports
4
+ import os
5
+
6
+ # Lib imports
7
+ from tabulate import tabulate
8
+
9
+ class NicePrint:
10
+ '''Helper class to print nice objects'''
11
+
12
+ @staticmethod
13
+ def analyses(data):
14
+ '''Print analyses'''
15
+ to_print = [
16
+ [
17
+ analysis['id'],
18
+ analysis['name'],
19
+ analysis['started_on'],
20
+ analysis['completed_on'],
21
+ analysis['status'],
22
+ analysis['meta']['num_files'],
23
+ analysis['tags']
24
+ ] for analysis in data
25
+ ]
26
+ print(tabulate(to_print, headers=[
27
+ 'id',
28
+ 'name',
29
+ 'started on',
30
+ 'completed on',
31
+ 'status',
32
+ 'num files',
33
+ 'tags',
34
+ ]))
35
+
36
+ @staticmethod
37
+ def analysis(data):
38
+ '''Print analysis'''
39
+ for analysis in data:
40
+ to_print = [
41
+ ['id', analysis['id']],
42
+ ['name', analysis['name']],
43
+ ['date_created', analysis['date_created']],
44
+ ['completed_on', analysis['completed_on']],
45
+ ]
46
+
47
+ for sample in analysis['samples']:
48
+ to_print.append(['sample', sample.split('/')[-1]])
49
+
50
+ if analysis['controls']:
51
+ for control in analysis['controls']:
52
+ to_print.append(['control', control['id']])
53
+
54
+ print('\nAnalysis info:')
55
+ print(tabulate(to_print, headers=['Variable', 'Value']))
56
+
57
+ print('\nAnalysis files:')
58
+
59
+ # convert only filesizes that are not None
60
+ for filedata in analysis['files']:
61
+ filedata['filesize'] = filedata['filesize']/(1024.**3) if filedata['filesize'] else 'NA'
62
+
63
+ to_print = [
64
+ [
65
+ file['id'],
66
+ file['filesize'],
67
+ file['source'],
68
+ os.path.split(file['path'])[1],
69
+ file['tags'],
70
+ ] for file in analysis['files']
71
+ ]
72
+ print(tabulate(
73
+ to_print,
74
+ floatfmt='.4f',
75
+ headers=[
76
+ 'id',
77
+ 'filesize (Gigabytes)',
78
+ 'source',
79
+ 'name',
80
+ 'tags',
81
+ ],
82
+ numalign='right',
83
+ ))
84
+ print('\n\n')
85
+
86
+ @staticmethod
87
+ def genome(data):
88
+ '''Print genome'''
89
+ to_print = [[genome['id'], genome['name'], genome['created_on']] for genome in data]
90
+ print(tabulate(to_print, headers=['id', 'name', 'created_on']))
91
+
92
+ @staticmethod
93
+ def genomes(data):
94
+ '''Print genomes'''
95
+ NicePrint.genome(data)
96
+
97
+ @staticmethod
98
+ def sample(data):
99
+ '''Print sample'''
100
+ for sample in data:
101
+ print('Sample id: {}'.format(sample['id']))
102
+ print('Sample name: {}'.format(sample['name']))
103
+ print('Sample datatype: {}'.format(sample['datatype']))
104
+ print('Sample genome: {}'.format(sample['genome_name'] or sample['genome']))
105
+ print('Sample data created: {}'.format(sample['date_created']))
106
+ print('Sample num reads: {}'.format(sample['meta']['num_reads']))
107
+ print('Analyses:')
108
+ to_print = [
109
+ [
110
+ analysis['id'],
111
+ analysis['name'],
112
+ analysis['started_on'],
113
+ analysis['completed_on'],
114
+ analysis['status'],
115
+ analysis['meta']['num_files'],
116
+ analysis['tags']
117
+ ] for analysis in sample['analyses_full']
118
+ ]
119
+ print(tabulate(to_print, headers=[
120
+ 'id',
121
+ 'name',
122
+ 'started on',
123
+ 'completed on',
124
+ 'status',
125
+ 'num files',
126
+ 'tags',
127
+ ]))
128
+ print('\n\n')
129
+
130
+ @staticmethod
131
+ def samples(data):
132
+ '''Print samples'''
133
+ to_print = [
134
+ [
135
+ sample['id'],
136
+ sample['name'],
137
+ sample['datatype'],
138
+ sample['genome_name'] or sample['genome'],
139
+ sample['date_created'],
140
+ sample['meta']['num_reads']
141
+ ] for sample in data
142
+ ]
143
+ print(tabulate(to_print, headers=[
144
+ 'id',
145
+ 'name',
146
+ 'datatype',
147
+ 'genome',
148
+ 'date created',
149
+ 'num reads',
150
+ ]))
151
+
152
+ @staticmethod
153
+ def workflows(data):
154
+ '''Print pipelines'''
155
+ to_print = [
156
+ [
157
+ pipeline['id'],
158
+ pipeline['name'],
159
+ pipeline['datatype'],
160
+ pipeline['description'],
161
+ pipeline['tags']
162
+ ] for pipeline in data
163
+ ]
164
+ print(tabulate(to_print, headers=[
165
+ 'id',
166
+ 'name',
167
+ 'datatype',
168
+ 'description',
169
+ 'tags',
170
+ ]))
@@ -0,0 +1,18 @@
1
+ '''Helper to filter sets of data'''
2
+
3
+ class SetFilter:
4
+ '''Helper class to filter list'''
5
+ @staticmethod
6
+ def diff(a_set, b_set):
7
+ '''Filter by not intersection'''
8
+ return not set(b_set).intersection(set(a_set))
9
+
10
+ @staticmethod
11
+ def exact(a_set, b_set):
12
+ '''Filter by eq'''
13
+ return set(a_set) == set(b_set)
14
+
15
+ @staticmethod
16
+ def subset(a_set, b_set):
17
+ '''Filter by intersection'''
18
+ return set(a_set).intersection(set(b_set))
File without changes
@@ -0,0 +1 @@
1
+ from .parser import Parser
@@ -0,0 +1,67 @@
1
+ '''Configuration parser'''
2
+
3
+ # General imports
4
+ import json
5
+ import os
6
+
7
+ # App imports
8
+ from basepair.helpers import eprint
9
+
10
+ class Parser(): # pylint: disable=too-few-public-methods
11
+ '''Configuration parser class'''
12
+ def __init__(self, source):
13
+ # check if local json file
14
+ self.cfg = {}
15
+ if isinstance(source, dict):
16
+ self.cfg = source
17
+ elif os.path.isfile(source):
18
+ try:
19
+ self.cfg = json.load(open(source))
20
+ except OSError as error:
21
+ eprint(f'ERROR: Not able to open config file: {error}')
22
+ except ValueError as error:
23
+ eprint(f'ERROR: Not able to read config file: {error}')
24
+ # TODO: if uri implement configuration manager
25
+
26
+ @staticmethod
27
+ def get_cli_credentials_from(cfg):
28
+ '''Get cli credential from service cfg'''
29
+ credentials = ''
30
+ credentials_cfg = cfg.get('credentials', {})
31
+ if credentials_cfg and not credentials_cfg.get('role'):
32
+ credentials = 'AWS_ACCESS_KEY_ID={} AWS_SECRET_ACCESS_KEY={} '.format(
33
+ credentials_cfg.get('id'),
34
+ credentials_cfg.get('secret'),
35
+ )
36
+ return credentials
37
+
38
+ def get_reflib_storage(self, bucket=None):
39
+ '''Get storage setting for reflibs'''
40
+ storages_cfg = self.cfg.get('storage', {}).get('reflib', {})
41
+ all_reflib_buckets = []
42
+ for storage_cfg in storages_cfg:
43
+ storage_settings = storage_cfg.get('settings', {})
44
+ all_reflib_buckets.append({
45
+ 'bucket': bucket or storage_settings.get('bucket'),
46
+ 'credentials': storage_cfg.get('credentials'),
47
+ 'region': storage_settings.get('region'),
48
+ })
49
+ return all_reflib_buckets
50
+
51
+ def get_user_storage(self, bucket=None):
52
+ '''Get storage setting'''
53
+ storage_cfg = self.cfg.get('storage', {}).get('user', {})
54
+ storage_settings = storage_cfg.get('settings', {})
55
+ return {
56
+ 'bucket': bucket or storage_settings.get('bucket'),
57
+ 'credentials': storage_cfg.get('credentials'),
58
+ 'region': storage_settings.get('region'),
59
+ }
60
+
61
+ def get_webapp_api(self):
62
+ '''Get webapp api settings'''
63
+ return self.cfg.get('api', {})
64
+
65
+ def is_empty(self):
66
+ '''Check if cfg is empty'''
67
+ return not self.cfg
@@ -0,0 +1,12 @@
1
+ from .analysis import Analysis
2
+ from .file import File
3
+ from .gene import Gene
4
+ from .genome import Genome
5
+ from .genome_file import GenomeFile
6
+ from .host import Host
7
+ from .module import Module
8
+ from .pipeline import Pipeline
9
+ from .project import Project
10
+ from .sample import Sample
11
+ from .upload import Upload
12
+ from .user import User
@@ -0,0 +1,128 @@
1
+ '''Webapp API'''
2
+
3
+ # General imports
4
+ import json
5
+ import os
6
+
7
+ # Lib imports
8
+ import requests
9
+
10
+ # App imports
11
+ from basepair.helpers import eprint
12
+
13
+ class Abstract:
14
+ '''Webapp abastract class'''
15
+ def __init__(self, cfg):
16
+ protocol = 'https' if cfg.get('ssl', True) else 'http'
17
+ self.endpoint = protocol + '://' + cfg.get('host') + cfg.get('prefix')
18
+ self.payload = {
19
+ 'username': cfg.get('username'),
20
+ 'api_key': cfg.get('key')
21
+ }
22
+ self.headers = {'content-type': 'application/json'}
23
+
24
+ def delete(self, obj_id, verify=True):
25
+ '''Delete resource'''
26
+ try:
27
+ response = requests.delete(
28
+ '{}{}'.format(self.endpoint, obj_id),
29
+ params=self.payload,
30
+ verify=verify
31
+ )
32
+ return self._parse_response(response)
33
+ except requests.exceptions.RequestException as error:
34
+ eprint('ERROR: {}'.format(error))
35
+ return { 'error': True, 'msg': error}
36
+
37
+ def get(self, obj_id, cache=False, params={}, verify=True): # pylint: disable=dangerous-default-value
38
+ '''Get detail of an resource'''
39
+ if cache:
40
+ filename = os.path.expanduser(cache)
41
+ if os.path.exists(filename) and os.path.getsize(filename):
42
+ return json.loads(open(filename, 'r').read().strip())
43
+
44
+ params.update(self.payload)
45
+ try:
46
+ response = requests.get(
47
+ '{}{}'.format(self.endpoint, obj_id),
48
+ params=params,
49
+ verify=verify,
50
+ )
51
+ parsed = self._parse_response(response)
52
+
53
+ # save in cache if required
54
+ if cache and parsed and not parsed.get('error'):
55
+ directory = os.path.dirname(filename)
56
+ if not os.path.exists(directory):
57
+ os.makedirs(directory)
58
+ with open(filename, 'w') as handle:
59
+ handle.write(json.dumps(parsed, indent=2))
60
+ return parsed
61
+ except requests.exceptions.RequestException as error:
62
+ eprint('ERROR: {}'.format(error))
63
+ return {'error': True, 'msg': error}
64
+
65
+ def list(self, params={'limit': 100}, verify=True): # pylint: disable=dangerous-default-value
66
+ '''Get a list of items'''
67
+ params.update(self.payload)
68
+ try:
69
+ response = requests.get(
70
+ self.endpoint.rstrip('/'),
71
+ params=params,
72
+ verify=verify,
73
+ )
74
+ return self._parse_response(response)
75
+ except requests.exceptions.RequestException as error:
76
+ eprint('ERROR: {}'.format(error))
77
+ return {'error': True, 'msg': error}
78
+
79
+ def list_all(self): # pylint: disable=dangerous-default-value
80
+ '''Get a list of all items'''
81
+ item_list = []
82
+ limit = 500
83
+ offset = 0
84
+ total_count = 1
85
+ while len(item_list) < total_count:
86
+ response = self.list({'limit': limit, 'offset': offset})
87
+ if response.get('error'):
88
+ return {'error': True, 'msg': response.get('msg')}
89
+ total_count = response.get('meta', {}).get('total_count')
90
+ item_list += response.get('objects')
91
+ offset += limit
92
+ return item_list
93
+
94
+ def save(self, obj_id=None, params={}, payload={}, verify=True): # pylint: disable=dangerous-default-value
95
+ '''Save or update resource'''
96
+ params.update(self.payload)
97
+ try:
98
+ response = getattr(requests, 'put' if obj_id else 'post')(
99
+ '{}{}'.format(self.endpoint, obj_id or ''),
100
+ data=json.dumps(payload),
101
+ headers=self.headers,
102
+ params=params,
103
+ verify=verify,
104
+ )
105
+ return self._parse_response(response)
106
+ except requests.exceptions.RequestException as error:
107
+ eprint('ERROR: {}'.format(error))
108
+ return {'error': True, 'msg': error}
109
+
110
+ @classmethod
111
+ def _parse_response(cls, response):
112
+ '''General response parser'''
113
+ error_msgs = {
114
+ 401: 'You don\'t have access to this resource.',
115
+ 404: 'Resource not found.',
116
+ 500: 'Error retrieving data from API!'
117
+ }
118
+
119
+ if response.status_code in error_msgs:
120
+ eprint('ERROR: {}'.format(error_msgs[response.status_code]))
121
+ return {'error': True, 'msg': error_msgs[response.status_code]}
122
+
123
+ try:
124
+ return response.json()
125
+ except json.decoder.JSONDecodeError as error:
126
+ msg = 'ERROR: Not able to parse response: {}.'.format(error)
127
+ eprint(msg)
128
+ return {'error': True, 'msg': msg}
@@ -0,0 +1,10 @@
1
+ '''Analysis webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class Analysis(Abstract):
7
+ '''Webapp Analysis class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'analyses/'
@@ -0,0 +1,10 @@
1
+ '''File webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class File(Abstract):
7
+ '''Webapp File class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'files/'
@@ -0,0 +1,10 @@
1
+ '''Gene webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class Gene(Abstract):
7
+ '''Webapp Gene class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'genes/'
@@ -0,0 +1,10 @@
1
+ '''Genome webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class Genome(Abstract):
7
+ '''Webapp Genome class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'genomes/'
@@ -0,0 +1,10 @@
1
+ '''Genome file webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class GenomeFile(Abstract):
7
+ '''Webapp GenomeFile class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'genomefiles/'
@@ -0,0 +1,10 @@
1
+ '''Host webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class Host(Abstract):
7
+ '''Webapp Host class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'hosts/'
@@ -0,0 +1,10 @@
1
+ '''Module webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class Module(Abstract):
7
+ '''Webapp Module class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'modules/'
@@ -0,0 +1,10 @@
1
+ '''Pipeline webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class Pipeline(Abstract):
7
+ '''Webapp Pipeline class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'pipelines/'
@@ -0,0 +1,10 @@
1
+ '''Project webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class Project(Abstract):
7
+ '''Webapp Project class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'projects/'
@@ -0,0 +1,10 @@
1
+ '''Sample webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class Sample(Abstract):
7
+ '''Webapp Sample class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'samples/'
@@ -0,0 +1,10 @@
1
+ '''Upload webapp api wrapper'''
2
+
3
+ # App imports
4
+ from .abstract import Abstract
5
+
6
+ class Upload(Abstract):
7
+ '''Webapp Upload class'''
8
+ def __init__(self, cfg):
9
+ super().__init__(cfg)
10
+ self.endpoint += 'uploads/'
@@ -0,0 +1,48 @@
1
+ '''User webapp api wrapper'''
2
+
3
+ # General imports
4
+ import json
5
+ import os
6
+
7
+ # Lib imports
8
+ import requests
9
+
10
+ # App imports
11
+ from basepair.helpers import eprint
12
+ from .abstract import Abstract
13
+
14
+ class User(Abstract):
15
+ '''Webapp User class'''
16
+ def __init__(self, cfg):
17
+ super().__init__(cfg)
18
+ self.endpoint += 'users/'
19
+
20
+ def get_configuration(self, cache=False, verify=True):
21
+ '''Get host configuration for user'''
22
+ if cache:
23
+ filename = os.path.expanduser(cache)
24
+ if os.path.exists(filename) and os.path.getsize(filename):
25
+ return json.loads(open(filename, 'r').read().strip())
26
+
27
+ params = {'origin': 'cli'}
28
+ params.update(self.payload)
29
+ try:
30
+ response = requests.get(
31
+ '{}get_configuration'.format(self.endpoint),
32
+ params=params,
33
+ verify=verify,
34
+ )
35
+ parsed = self._parse_response(response)
36
+
37
+ # save in cache if required
38
+ if cache and parsed and not parsed.get('error'):
39
+ directory = os.path.dirname(filename)
40
+ if not os.path.exists(directory):
41
+ os.makedirs(directory)
42
+ eprint('Saving configuration into:', filename)
43
+ with open(filename, 'w') as handle:
44
+ handle.write(json.dumps(parsed, indent=2))
45
+ return parsed
46
+ except requests.exceptions.RequestException as error:
47
+ eprint('ERROR: {}'.format(error))
48
+ return { 'error': True, 'msg': error}
File without changes