pyxetabase 3.1.0.dev21__py3-none-any.whl → 4.0.0.dev29__py3-none-any.whl

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 (40) hide show
  1. pyxetabase/opencga_config.py +29 -0
  2. pyxetabase/rest_clients/_parent_rest_clients.py +47 -13
  3. pyxetabase/rest_clients/admin_client.py +1 -2
  4. pyxetabase/rest_clients/meta_client.py +4 -3
  5. pyxetabase/rest_clients/study_client.py +28 -0
  6. pyxetabase/rest_clients/variant_operation_client.py +26 -27
  7. {pyxetabase-3.1.0.dev21.dist-info → pyxetabase-4.0.0.dev29.dist-info}/METADATA +1 -1
  8. pyxetabase-4.0.0.dev29.dist-info/RECORD +35 -0
  9. pyopencga/__init__.py +0 -0
  10. pyopencga/commons.py +0 -347
  11. pyopencga/exceptions.py +0 -8
  12. pyopencga/opencga_client.py +0 -334
  13. pyopencga/opencga_config.py +0 -182
  14. pyopencga/rest_clients/__init__.py +0 -0
  15. pyopencga/rest_clients/_parent_rest_clients.py +0 -110
  16. pyopencga/rest_clients/admin_client.py +0 -173
  17. pyopencga/rest_clients/alignment_client.py +0 -373
  18. pyopencga/rest_clients/clinical_analysis_client.py +0 -1279
  19. pyopencga/rest_clients/cohort_client.py +0 -338
  20. pyopencga/rest_clients/disease_panel_client.py +0 -352
  21. pyopencga/rest_clients/family_client.py +0 -355
  22. pyopencga/rest_clients/file_client.py +0 -698
  23. pyopencga/rest_clients/ga4gh_client.py +0 -86
  24. pyopencga/rest_clients/individual_client.py +0 -435
  25. pyopencga/rest_clients/job_client.py +0 -415
  26. pyopencga/rest_clients/meta_client.py +0 -85
  27. pyopencga/rest_clients/organization_client.py +0 -216
  28. pyopencga/rest_clients/project_client.py +0 -128
  29. pyopencga/rest_clients/sample_client.py +0 -446
  30. pyopencga/rest_clients/study_client.py +0 -433
  31. pyopencga/rest_clients/user_client.py +0 -192
  32. pyopencga/rest_clients/variant_client.py +0 -1378
  33. pyopencga/rest_clients/variant_operation_client.py +0 -719
  34. pyopencga/rest_clients/workflow_client.py +0 -263
  35. pyopencga/rest_response.py +0 -220
  36. pyopencga/retry.py +0 -57
  37. pyxetabase-3.1.0.dev21.dist-info/RECORD +0 -63
  38. {pyxetabase-3.1.0.dev21.dist-info → pyxetabase-4.0.0.dev29.dist-info}/WHEEL +0 -0
  39. {pyxetabase-3.1.0.dev21.dist-info → pyxetabase-4.0.0.dev29.dist-info}/licenses/LICENSE +0 -0
  40. {pyxetabase-3.1.0.dev21.dist-info → pyxetabase-4.0.0.dev29.dist-info}/top_level.txt +0 -0
@@ -76,6 +76,35 @@ class ClientConfiguration(object):
76
76
  except requests.ConnectionError:
77
77
  raise Exception('Unreachable host "{}"'.format(self.host))
78
78
 
79
+ @property
80
+ def host(self):
81
+ return self._config['rest']['host']
82
+
83
+ @host.setter
84
+ def host(self, new_host):
85
+ self._config['rest']['host'] = new_host
86
+
87
+ @property
88
+ def tlsAllowInvalidCertificates(self):
89
+ if ('tlsAllowInvalidCertificates' in self._config['rest']
90
+ and self._config['rest']['tlsAllowInvalidCertificates'] is not None):
91
+ return self._config['rest']['tlsAllowInvalidCertificates']
92
+ else:
93
+ return False
94
+
95
+ @property
96
+ def version(self):
97
+ return self._config['version'] if 'version' in self._config else 'v2'
98
+
99
+ @property
100
+ def cookies(self):
101
+ if 'cookies' in self._config and self._config['cookies']:
102
+ python_session_fhand = open(os.path.expanduser("~/.opencga/python_session.json"), 'r')
103
+ session_info = json.loads(python_session_fhand.read())
104
+ return session_info['cookies']
105
+ else:
106
+ return None
107
+
79
108
  @property
80
109
  def configuration(self):
81
110
  return self._config
@@ -1,6 +1,7 @@
1
- import json
1
+ import os
2
+ import requests
2
3
 
3
- from pyxetabase.commons import execute
4
+ from pyxetabase.commons import execute, _create_rest_url, snake_to_camel_case
4
5
  from pyxetabase.rest_response import RestResponse
5
6
  from pyxetabase.retry import retry
6
7
 
@@ -87,18 +88,23 @@ class _ParentRestClient(object):
87
88
  def _post(self, category, resource, data=None, query_id=None, subcategory=None,
88
89
  second_query_id=None, **options):
89
90
  """Queries the REST service and returns the result"""
90
- if data is not None:
91
- return self._rest_retry(
92
- method='post', category=category, resource=resource, query_id=query_id,
93
- subcategory=subcategory, second_query_id=second_query_id,
94
- data=data, **options
95
- )
91
+ # Special treatment for the "/{apiVersion}/files/upload" endpoint
92
+ if category == 'files' and resource == 'upload':
93
+ response = self._upload(category=category, resource=resource, **options)
94
+ return RestResponse(response)
96
95
  else:
97
- return self._rest_retry(
98
- method='post', category=category, resource=resource, query_id=query_id,
99
- subcategory=subcategory, second_query_id=second_query_id,
100
- **options
101
- )
96
+ if data is not None:
97
+ return self._rest_retry(
98
+ method='post', category=category, resource=resource, query_id=query_id,
99
+ subcategory=subcategory, second_query_id=second_query_id,
100
+ data=data, **options
101
+ )
102
+ else:
103
+ return self._rest_retry(
104
+ method='post', category=category, resource=resource, query_id=query_id,
105
+ subcategory=subcategory, second_query_id=second_query_id,
106
+ **options
107
+ )
102
108
 
103
109
  def _delete(self, category, resource, query_id=None, subcategory=None,
104
110
  second_query_id=None, **options):
@@ -108,3 +114,31 @@ class _ParentRestClient(object):
108
114
  subcategory=subcategory, second_query_id=second_query_id,
109
115
  **options
110
116
  )
117
+
118
+ def _upload(self, category, resource, **options):
119
+ """Upload files"""
120
+
121
+ # Checking that the parameter file contains the file path to upload
122
+ if 'file' not in options or not isinstance(options['file'], str):
123
+ raise ValueError('To upload a file, please specify the file path as the "file" parameter.')
124
+
125
+ # Creating URL and headers
126
+ url, header = _create_rest_url(host=self._cfg.host, version=self._cfg.version, sid=self.token,
127
+ category=category, resource=resource, options=options)
128
+
129
+ # Creating data
130
+ data = {}
131
+ for k, v in options.items():
132
+ if k == 'file': # Param "file" is not included in data
133
+ continue
134
+ data[snake_to_camel_case(k)] = v
135
+
136
+ # Uploading
137
+ fpath = os.path.realpath(os.path.expanduser(options['file']))
138
+ with open(fpath, "rb") as f:
139
+ fhand = {"file": (fpath, f, "application/octet-stream")}
140
+ response = requests.post(url, headers=header, files=fhand, data=data or None)
141
+ if response.status_code != 200:
142
+ raise Exception(response.content)
143
+
144
+ return response.json()
@@ -147,8 +147,7 @@ class Admin(_ParentRestClient):
147
147
 
148
148
  def sync_users(self, data=None, **options):
149
149
  """
150
- Synchronise a group of users from an authentication origin with a
151
- group in a study from catalog.
150
+ [DEPRECATED] Moved to /users/sync.
152
151
  PATH: /{apiVersion}/admin/users/sync
153
152
 
154
153
  :param dict data: JSON containing the parameters. (REQUIRED)
@@ -55,15 +55,16 @@ class Meta(_ParentRestClient):
55
55
 
56
56
  return self._get(category='meta', resource='model', **options)
57
57
 
58
- def openapi(self, **options):
58
+ def openapi(self, url, **options):
59
59
  """
60
60
  Opencga openapi json.
61
61
  PATH: /{apiVersion}/meta/openapi
62
62
 
63
- :param str environment: Environment of the app.
64
- :param str host: Opencga host without environment.
63
+ :param str url: Opencga host with environment. (REQUIRED)
64
+ :param str study: Opencga study to be default in queries.
65
65
  """
66
66
 
67
+ options['url'] = url
67
68
  return self._get(category='meta', resource='openapi', **options)
68
69
 
69
70
  def ping(self, **options):
@@ -166,6 +166,19 @@ class Study(_ParentRestClient):
166
166
 
167
167
  return self._get(category='studies', resource='groups', query_id=study, **options)
168
168
 
169
+ def sync_groups(self, study, data=None, **options):
170
+ """
171
+ Associate a remote group from an authentication origin with a local
172
+ group in a study.
173
+ PATH: /{apiVersion}/studies/{study}/groups/sync
174
+
175
+ :param dict data: JSON containing the parameters. (REQUIRED)
176
+ :param str study: Study [[organization@]project:]study where study and
177
+ project can be either the ID or UUID. (REQUIRED)
178
+ """
179
+
180
+ return self._post(category='studies', resource='sync', query_id=study, subcategory='groups', data=data, **options)
181
+
169
182
  def update_groups(self, study, data=None, **options):
170
183
  """
171
184
  Add or remove a group.
@@ -386,6 +399,21 @@ class Study(_ParentRestClient):
386
399
 
387
400
  return self._post(category='studies', resource='update', query_id=study, data=data, **options)
388
401
 
402
+ def sync_users(self, study, authentication_origin_id, **options):
403
+ """
404
+ Synchronize all users from the remote groups of a given authentication
405
+ origin.
406
+ PATH: /{apiVersion}/studies/{study}/users/sync
407
+
408
+ :param str authentication_origin_id: Authentication origin ID.
409
+ (REQUIRED)
410
+ :param str study: Study [[organization@]project:]study where study and
411
+ project can be either the ID or UUID. (REQUIRED)
412
+ """
413
+
414
+ options['authenticationOriginId'] = authentication_origin_id
415
+ return self._post(category='studies', resource='sync', query_id=study, subcategory='users', **options)
416
+
389
417
  def variable_sets(self, study, **options):
390
418
  """
391
419
  Fetch variableSets from a study.
@@ -86,6 +86,32 @@ class VariantOperation(_ParentRestClient):
86
86
 
87
87
  return self._delete(category='operation', resource='delete', subcategory='variant/annotation', **options)
88
88
 
89
+ def variant_annotation_extension_configure(self, data=None, **options):
90
+ """
91
+ Install a variant annotation extension and configure the project to
92
+ use it.
93
+ PATH: /{apiVersion}/operation/variant/annotation/extension/configure
94
+
95
+ :param str job_id: Job ID. It must be a unique string within the
96
+ study. An ID will be autogenerated automatically if not provided.
97
+ :param str job_description: Job description.
98
+ :param str job_depends_on: Comma separated list of existing job IDs
99
+ the job will depend on.
100
+ :param str job_tags: Job tags.
101
+ :param str job_scheduled_start_time: Time when the job is scheduled to
102
+ start.
103
+ :param str job_priority: Priority of the job.
104
+ :param bool job_dry_run: Flag indicating that the job will be executed
105
+ in dry-run mode. In this mode, OpenCGA will validate that all
106
+ parameters and prerequisites are correctly set for successful
107
+ execution, but the job will not actually run.
108
+ :param str project: project.
109
+ :param dict data: Parameters to configure a variant annotation
110
+ extension.
111
+ """
112
+
113
+ return self._post(category='operation', resource='configure', subcategory='variant/annotation/extension', data=data, **options)
114
+
89
115
  def index_variant_annotation(self, data=None, **options):
90
116
  """
91
117
  Create and load variant annotations into the database.
@@ -601,33 +627,6 @@ class VariantOperation(_ParentRestClient):
601
627
 
602
628
  return self._post(category='operation', resource='secondaryIndex', subcategory='variant', data=data, **options)
603
629
 
604
- def delete_variant_secondary_index(self, **options):
605
- """
606
- Remove a secondary index from the search engine for a specific set of
607
- samples.
608
- PATH: /{apiVersion}/operation/variant/secondaryIndex/delete
609
-
610
- :param str job_id: Job ID. It must be a unique string within the
611
- study. An ID will be autogenerated automatically if not provided.
612
- :param str job_description: Job description.
613
- :param str job_depends_on: Comma separated list of existing job IDs
614
- the job will depend on.
615
- :param str job_tags: Job tags.
616
- :param str job_scheduled_start_time: Time when the job is scheduled to
617
- start.
618
- :param str job_priority: Priority of the job.
619
- :param bool job_dry_run: Flag indicating that the job will be executed
620
- in dry-run mode. In this mode, OpenCGA will validate that all
621
- parameters and prerequisites are correctly set for successful
622
- execution, but the job will not actually run.
623
- :param str study: Study [[organization@]project:]study where study and
624
- project can be either the ID or UUID.
625
- :param str samples: Samples to remove. Needs to provide all the
626
- samples in the secondary index.
627
- """
628
-
629
- return self._delete(category='operation', resource='delete', subcategory='variant/secondaryIndex', **options)
630
-
631
630
  def setup_variant(self, data=None, **options):
632
631
  """
633
632
  Execute Variant Setup to allow using the variant engine. This setup is
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyxetabase
3
- Version: 3.1.0.dev21
3
+ Version: 4.0.0.dev29
4
4
  Summary: A REST client for OpenCGA enterprise REST web services
5
5
  Author: Daniel Perez-Gil
6
6
  Author-email: daniel.perez@zettagenomics.com
@@ -0,0 +1,35 @@
1
+ pyxetabase/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ pyxetabase/commons.py,sha256=Okt5DgvSpZW9PUsxoLNpROb0BDrdr_zhgry4X3dQpfk,14308
3
+ pyxetabase/exceptions.py,sha256=GmtDcurD3d_fzaa8AEntF4-sZR4Elgg4Iz3z-UUqjYU,274
4
+ pyxetabase/opencga_client.py,sha256=V-M9i28z3A-Vgw5BnG_Ddm0MUdjQ0_XG38gohGtzavI,15386
5
+ pyxetabase/opencga_config.py,sha256=RK23fextK79S5wq4FaQygwuPnE4p4J9GbjY6hJ0Krxc,7009
6
+ pyxetabase/rest_response.py,sha256=TgwTI2LZFF_jV9-HSawGkF_qZ88n-dxEtIKiFcfPyDk,8635
7
+ pyxetabase/retry.py,sha256=LjViQOaa_GkpDFkcRq9jIS183mE9t4Rq0uls9PV_mfI,2297
8
+ pyxetabase/rest_clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ pyxetabase/rest_clients/_parent_rest_clients.py,sha256=OuCnmaziUCENpmpA3CzKJGEhMY_Z-7Q_rlkH75QDi7I,5854
10
+ pyxetabase/rest_clients/admin_client.py,sha256=WebfbQVa7CjiaNcp5MqwAkgDTqCfW-v5AgTaxmL5EF0,6927
11
+ pyxetabase/rest_clients/alignment_client.py,sha256=srY1fmjMZCPWlbqhrD2gYVhS2zu7fgPx61tZOqQi4Wc,18509
12
+ pyxetabase/rest_clients/clinical_analysis_client.py,sha256=j2LmLT8wg3C9srRMB2mksEVFnqN22Anb7HxZCbdF50c,69126
13
+ pyxetabase/rest_clients/cohort_client.py,sha256=D-su-AFOziztVMI-oAcr5G2Uq_psbLV8Wt0bqZ7zZgI,16324
14
+ pyxetabase/rest_clients/cvdb_client.py,sha256=V7ny5nQEeJqsbALAe7JLyoV6b0XyYF7c9lsn-qK-i8o,143102
15
+ pyxetabase/rest_clients/disease_panel_client.py,sha256=GAYRyAfoB_VunskXOhAzMNbsrFupb6M2QbRK3x1Y5vo,18513
16
+ pyxetabase/rest_clients/family_client.py,sha256=n-kyjnrV09R50JxyiHjFs8rCQkOKFU0Z1O7oVYuaKxg,18586
17
+ pyxetabase/rest_clients/federation_client.py,sha256=p5B8dRq9gj-fdgIfIPhmkT7mNU65cRFtH06kaGtmbWE,5066
18
+ pyxetabase/rest_clients/file_client.py,sha256=fwTWnZtprYNDUBvRetLLe6PTBxW_M8LxN6OlAMGWXC4,33730
19
+ pyxetabase/rest_clients/ga4gh_client.py,sha256=fPnmiblnfpz_zcZPJblGqOFksrdiF3MUer3fv2nwQwk,3506
20
+ pyxetabase/rest_clients/individual_client.py,sha256=C59zr_t7tTxNR7ZBeAPY6fyYl59fE7KY05MaLyXWmXw,23225
21
+ pyxetabase/rest_clients/job_client.py,sha256=amoBW3SL56l6sAPCUB55rZhLR8DcdIIfb5ymOZ9NkLQ,19811
22
+ pyxetabase/rest_clients/meta_client.py,sha256=uExVRfdSKiXteLYe7R3q9x3zCp9mMWWMyPDU56TtoDo,2308
23
+ pyxetabase/rest_clients/organization_client.py,sha256=tnwUTCqJoGiKXMQLMv4ymHA16JxnR5iL2SMLaJDBRs8,9465
24
+ pyxetabase/rest_clients/project_client.py,sha256=M8naPsj47z2ylTrJNU_JyHReKzXrB038PoEtKKrtxmc,5212
25
+ pyxetabase/rest_clients/sample_client.py,sha256=VOsPAhw9HwaEHzzw_5gcVQ1v2xSesvzN3TO4z2opaNo,23621
26
+ pyxetabase/rest_clients/study_client.py,sha256=STtboEiGP-lQ1UptjHxk-ANd3uG6cA6U3srvOO4UQIE,21491
27
+ pyxetabase/rest_clients/user_client.py,sha256=frA7-rMii-yoRyca_Orkj1T80OeEe-zCdWZCHKn1sio,7683
28
+ pyxetabase/rest_clients/variant_client.py,sha256=mmBuVE0JBThJr5zsLGci5nykNcCKyfZXRKl-h3HT9PA,75436
29
+ pyxetabase/rest_clients/variant_operation_client.py,sha256=ceZ2-ii0D1oCDMRz_EURwUf_VjtsV5lzJuY-ZwG1b6Q,36840
30
+ pyxetabase/rest_clients/workflow_client.py,sha256=QYnyI17aNCjq-uXlguaSj78F0xupeWwmf8uYK1Y5tf4,12482
31
+ pyxetabase-4.0.0.dev29.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
32
+ pyxetabase-4.0.0.dev29.dist-info/METADATA,sha256=TL6HOzwe313tz-0JeNMPB2aGt2WsY0qniQ1Xl2oxiUc,5540
33
+ pyxetabase-4.0.0.dev29.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
+ pyxetabase-4.0.0.dev29.dist-info/top_level.txt,sha256=0m5pDpBX-lM8QpPl7bTpTQAm4kgu2-nr-pcaEu4Tn_8,11
35
+ pyxetabase-4.0.0.dev29.dist-info/RECORD,,
pyopencga/__init__.py DELETED
File without changes
pyopencga/commons.py DELETED
@@ -1,347 +0,0 @@
1
- import sys
2
- import threading
3
- from time import sleep
4
- import warnings
5
-
6
- import requests
7
-
8
- from pyopencga.exceptions import OpencgaInvalidToken, OpencgaAuthorisationError
9
-
10
- try:
11
- from Queue import Queue
12
- except ImportError:
13
- from queue import Queue
14
-
15
- _CALL_BATCH_SIZE = 2000
16
- _NUM_THREADS_DEFAULT = 4
17
-
18
-
19
- def deprecated(func):
20
- """Prints a warning for functions marked as deprecated"""
21
- def new_func(*args, **kwargs):
22
- warnings.simplefilter('always', DeprecationWarning) # turn off filter
23
- warnings.warn('Call to deprecated function "{}".'.format(func.__name__),
24
- category=DeprecationWarning, stacklevel=2)
25
- warnings.simplefilter('default', DeprecationWarning) # reset filter
26
- return func(*args, **kwargs)
27
- return new_func
28
-
29
-
30
- def snake_to_camel_case(text):
31
- """Converts snake_case to camelCase"""
32
- components = text.split('_')
33
- return components[0] + ''.join(x.title() for x in components[1:])
34
-
35
-
36
- def _create_rest_url(host, version, sid, category, resource, subcategory=None, query_id=None,
37
- second_query_id=None, options=None):
38
- """Creates the URL for querying the REST service"""
39
-
40
- # Creating the basic URL
41
- url = ('/'.join([host,
42
- 'webservices/rest',
43
- version,
44
- category
45
- ]))
46
-
47
- # If subcategory is queried, query_id can be absent
48
- if query_id is not None:
49
- url += '/' + query_id
50
-
51
- if subcategory is not None:
52
- url += '/' + subcategory
53
-
54
- if second_query_id is not None:
55
- url += '/' + second_query_id
56
-
57
- url += '/' + resource
58
-
59
- header = {"Accept-Encoding": "gzip"}
60
- if sid is not None:
61
- header['Authorization'] = 'Bearer {}'.format(sid)
62
-
63
- # Checking optional params
64
- if options is not None:
65
- opts = []
66
- for k, v in options.items():
67
- k = snake_to_camel_case(k)
68
- if k == 'debug':
69
- continue
70
- if isinstance(v, list):
71
- opts.append(k + '=' + ','.join(map(str, v)))
72
- else:
73
- opts.append(k + '=' + str(v))
74
- if opts:
75
- url += '?' + '&'.join(opts)
76
- return url, header
77
-
78
-
79
- def _fetch(config, sid, category, resource, method, subcategory=None, query_id=None,
80
- second_query_id=None, data=None, options=None):
81
- """Queries the REST service retrieving results until exhaustion or limit"""
82
- # HERE BE DRAGONS
83
- final_response = None
84
-
85
- # Setting up skip and limit default parameters
86
- call_skip = 0
87
- call_limit = 1000
88
- max_limit = None
89
- if options is None:
90
- opts = {'skip': call_skip, 'limit': call_limit}
91
- else:
92
- opts = options.copy() # Do not modify original data!
93
- if 'skip' not in opts:
94
- opts['skip'] = call_skip
95
- # If 'limit' is specified, a maximum of 'limit' results will be returned
96
- if 'limit' in opts:
97
- max_limit = int(opts['limit'])
98
- # Server must be always queried for results in groups of 1000
99
- opts['limit'] = call_limit
100
-
101
- # If there is a query_id, the next variables will be used
102
- total_id_list = [] # All initial ids
103
- next_id_list = [] # Ids which should be queried again for more results
104
- next_id_indexes = [] # Ids position in the final response
105
- if query_id is not None:
106
- total_id_list = query_id.split(',')
107
-
108
- # If some query has more than 'call_limit' results, the server will be
109
- # queried again to retrieve the next 'call_limit results'
110
- call = True
111
- current_query_id = None # Current REST query
112
- current_id_list = None # Current list of ids
113
- time_out_counter = 0 # Number of times a query is repeated due to time-out
114
- while call:
115
- # Check 'limit' parameter if there is a maximum limit of results
116
- if max_limit is not None and max_limit <= call_limit:
117
- opts['limit'] = max_limit
118
-
119
- # Updating query_id and list of ids to query
120
- if query_id is not None:
121
- if current_query_id is None:
122
- current_query_id = query_id
123
- current_id_list = total_id_list
124
- current_id_indexes = range(len(total_id_list))
125
- else:
126
- current_query_id = ','.join(next_id_list)
127
- current_id_list = next_id_list
128
- current_id_indexes = next_id_indexes
129
-
130
- # Retrieving url
131
- url, header = _create_rest_url(host=config.host,
132
- version=config.version,
133
- category=category,
134
- sid=sid,
135
- subcategory=subcategory,
136
- query_id=current_query_id,
137
- second_query_id=second_query_id,
138
- resource=resource,
139
- options=opts)
140
-
141
- # DEBUG param
142
- if opts is not None and 'debug' in opts and opts['debug']:
143
- sys.stderr.write(url + '\n')
144
-
145
- # Getting REST response
146
- if method == 'get':
147
- try:
148
- r = requests.get(url, headers=header, cookies=config.cookies, verify=not config.tlsAllowInvalidCertificates)
149
- except requests.exceptions.ConnectionError:
150
- sleep(1)
151
- r = requests.get(url, headers=header, cookies=config.cookies, verify=not config.tlsAllowInvalidCertificates)
152
- elif method == 'post':
153
- try:
154
- r = requests.post(url, json=data, headers=header, cookies=config.cookies, verify=not config.tlsAllowInvalidCertificates)
155
- except requests.exceptions.ConnectionError:
156
- sleep(1)
157
- r = requests.post(url, json=data, headers=header, cookies=config.cookies, verify=not config.tlsAllowInvalidCertificates)
158
- elif method == 'delete':
159
- try:
160
- r = requests.delete(url, headers=header, cookies=config.cookies, verify=not config.tlsAllowInvalidCertificates)
161
- except requests.exceptions.ConnectionError:
162
- sleep(1)
163
- r = requests.delete(url, headers=header, cookies=config.cookies, verify=not config.tlsAllowInvalidCertificates)
164
- else:
165
- raise NotImplementedError('method: ' + method + ' not implemented.')
166
-
167
- if r.status_code == 504: # Gateway Time-out
168
- if time_out_counter == 99:
169
- msg = 'Server not responding in time'
170
- raise requests.ConnectionError(msg)
171
- time_out_counter += 1
172
- continue
173
- time_out_counter = 0
174
-
175
- if r.status_code == 401:
176
- raise OpencgaInvalidToken(r.content)
177
- elif r.status_code == 403:
178
- raise OpencgaAuthorisationError(r.content)
179
- elif r.status_code != 200:
180
- raise Exception(r.content)
181
-
182
- if r.headers['Content-Type'] == 'application/json':
183
- try:
184
- response = r.json()
185
-
186
- # TODO Remove deprecated response and result in future release. Added for backwards compatibility
187
- if 'response' in response:
188
- response['responses'] = response['response']
189
- for query_result in response['responses']:
190
- if 'result' in query_result:
191
- query_result['results'] = query_result['result']
192
-
193
- except ValueError:
194
- raise ValueError('Bad JSON format retrieved from server')
195
- elif r.headers['Content-Type'] == 'application/octet-stream':
196
- return r.content
197
- else:
198
- raise ValueError('Unexpected content type retrieved from server ("{}"): "{}"'.format(
199
- r.headers['Content-Type'], r.content)
200
- )
201
-
202
- # Setting up final_response
203
- if final_response is None:
204
- final_response = response
205
- # Concatenating results
206
- else:
207
- if query_id is not None:
208
- for index, res in enumerate(response['responses']):
209
- id_index = current_id_indexes[index]
210
- final_response[id_index]['results'] += res['results']
211
- else:
212
- final_response['responses'][0]['results'] += response['responses'][0]['results']
213
-
214
- if query_id is not None:
215
- # Checking which ids are completely retrieved
216
- next_id_list = []
217
- next_id_indexes = []
218
- for index, res in enumerate(response['responses']):
219
- if res['numResults'] == call_limit:
220
- next_id_list.append(current_id_list[index])
221
- next_id_indexes.append(current_id_indexes[index])
222
- # Ending REST calling when there are no more ids to retrieve
223
- if not next_id_list:
224
- call = False
225
- else:
226
- # Ending REST calling when there are no more results to retrieve
227
- if response['responses'][0]['numResults'] != call_limit:
228
- call = False
229
-
230
- # Skipping the first 'limit' results to retrieve the next ones
231
- opts['skip'] += call_limit
232
-
233
- # Subtracting the number of returned results from the maximum goal
234
- if max_limit is not None:
235
- max_limit -= call_limit
236
- # When 'limit' is 0 returns all the results. So, break the loop if 0
237
- if max_limit == 0:
238
- break
239
-
240
- return final_response
241
-
242
-
243
- def _worker(queue, results, config, sid, category, resource, method, subcategory=None,
244
- second_query_id=None, data=None, options=None):
245
-
246
- """Manages the queue system for the threads"""
247
- while True:
248
- # Fetching new element from the queue
249
- index, query_id = queue.get()
250
- response = _fetch(config=config, sid=sid, category=category, subcategory=subcategory,
251
- resource=resource, method=method, data=data, query_id=query_id,
252
- second_query_id=second_query_id, options=options)
253
- # Store data in results at correct index
254
- results[index] = response
255
- # Signaling to the queue that task has been processed
256
- queue.task_done()
257
-
258
-
259
- def merge_query_responses(query_response_list):
260
- final_response = query_response_list[0]
261
- for i, query_response in enumerate(query_response_list):
262
- if i != 0:
263
- final_response['events'] += query_response['events']
264
- final_response['time'] += query_response['time']
265
- # final_response['responses'] += response['responses']
266
-
267
- for key in query_response['params']:
268
- if final_response['params'][key] != query_response['params'][key]:
269
- final_response['params'][key] += ',' + query_response['params'][key]
270
-
271
- for j, query_result in enumerate(query_response['responses']):
272
- if len(final_response['responses'])-1 < j:
273
- final_response['responses'] += []
274
- for key in query_result:
275
- if key not in final_response['responses'][j]:
276
- final_response['responses'][j][key] = query_result[key]
277
- else:
278
- if isinstance(query_result[key], (int, list)):
279
- final_response['responses'][j][key] += query_result[key]
280
- return final_response
281
-
282
-
283
- def execute(config, sid, category, resource, method, subcategory=None, query_id=None,
284
- second_query_id=None, data=None, options=None):
285
- """Queries the REST service using multiple threads if needed"""
286
-
287
- # If query_id is an array, convert to comma-separated string
288
- if query_id is not None:
289
- if isinstance(query_id, list):
290
- query_id = ','.join([str(item) for item in query_id])
291
- else:
292
- query_id = str(query_id) # convert to string so we can call this method with int ids
293
-
294
- # Multithread if the number of queries is greater than _CALL_BATCH_SIZE
295
- if query_id is None or len(query_id.split(',')) <= _CALL_BATCH_SIZE:
296
- response = _fetch(config=config, sid=sid, category=category, subcategory=subcategory,
297
- resource=resource, method=method, data=data, query_id=query_id,
298
- second_query_id=second_query_id, options=options)
299
- return response
300
- else:
301
- if options is not None and 'num_threads' in options:
302
- num_threads = options['num_threads']
303
- else:
304
- num_threads = _NUM_THREADS_DEFAULT
305
-
306
- # Splitting query_id into batches depending on the call batch size
307
- id_list = query_id.split(',')
308
- id_batches = [','.join(id_list[x:x + _CALL_BATCH_SIZE])
309
- for x in range(0, len(id_list), _CALL_BATCH_SIZE)]
310
-
311
- # Setting up the queue to hold all the id batches
312
- q = Queue(maxsize=0)
313
- # Creating a size defined list to store thread results
314
- res = [''] * len(id_batches)
315
-
316
- # Setting up the threads
317
- for thread in range(num_threads):
318
- t = threading.Thread(target=_worker,
319
- kwargs={'queue': q,
320
- 'results': res,
321
- 'config': config,
322
- 'sid': sid,
323
- 'category': category,
324
- 'subcategory': subcategory,
325
- 'second_query_id': second_query_id,
326
- 'resource': resource,
327
- 'method': method,
328
- 'data': data,
329
- 'options': options})
330
- # Setting threads as "daemon" allows main program to exit eventually
331
- # even if these do not finish correctly
332
- t.daemon = True
333
- t.start()
334
-
335
- # Loading up the queue with index and id batches for each job
336
- for index, batch in enumerate(id_batches):
337
- q.put((index, batch)) # Notice this is a tuple
338
-
339
- # Waiting until the queue has been processed
340
- q.join()
341
-
342
- # Joining all the responses into a one final response
343
- final_query_response = merge_query_responses(res)
344
-
345
- return final_query_response
346
-
347
-
pyopencga/exceptions.py DELETED
@@ -1,8 +0,0 @@
1
- class OpencgaAuthorisationError(Exception):
2
- def __init__(self, message):
3
- super(OpencgaAuthorisationError, self).__init__(message)
4
-
5
-
6
- class OpencgaInvalidToken(Exception):
7
- def __init__(self, message):
8
- super(OpencgaInvalidToken, self).__init__(message)