Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/bioblend/galaxy/client.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
author | shellac |
---|---|
date | Thu, 14 May 2020 14:56:58 -0400 |
parents | 26e78fe6e8c4 |
children |
comparison
equal
deleted
inserted
replaced
1:75ca89e9b81c | 2:6af9afd405e9 |
---|---|
1 """ | |
2 An interface the clients should implement. | |
3 | |
4 This class is primarily a helper for the library and user code | |
5 should not use it directly. | |
6 """ | |
7 | |
8 import time | |
9 | |
10 import requests | |
11 from requests.packages.urllib3.exceptions import ProtocolError | |
12 | |
13 import bioblend | |
14 # The following import must be preserved for compatibility because | |
15 # ConnectionError class was originally defined here | |
16 from bioblend import ConnectionError # noqa: I202 | |
17 | |
18 | |
19 class Client(object): | |
20 | |
21 # Class variables that configure GET request retries. Note that since these | |
22 # are class variables their values are shared by all Client instances -- | |
23 # i.e., HistoryClient, WorkflowClient, etc. | |
24 # | |
25 # Number of attempts before giving up on a GET request. | |
26 _max_get_retries = 1 | |
27 # Delay in seconds between subsequent retries. | |
28 _get_retry_delay = 10 | |
29 | |
30 @classmethod | |
31 def max_get_retries(cls): | |
32 """ | |
33 The maximum number of attempts for a GET request. | |
34 """ | |
35 return cls._max_get_retries | |
36 | |
37 @classmethod | |
38 def set_max_get_retries(cls, value): | |
39 """ | |
40 Set the maximum number of attempts for GET requests. A value greater | |
41 than one causes failed GET requests to be retried `value` - 1 times. | |
42 | |
43 Default: 1 | |
44 """ | |
45 if value < 1: | |
46 raise ValueError("Number of retries must be >= 1 (got: %s)" % value) | |
47 cls._max_get_retries = value | |
48 return cls | |
49 | |
50 @classmethod | |
51 def get_retry_delay(cls): | |
52 """ | |
53 The delay (in seconds) to wait before retrying a failed GET | |
54 request. | |
55 """ | |
56 return cls._get_retry_delay | |
57 | |
58 @classmethod | |
59 def set_get_retry_delay(cls, value): | |
60 """ | |
61 Set the delay (in seconds) to wait before retrying a failed GET | |
62 request. Default: 10 | |
63 """ | |
64 if value < 0: | |
65 raise ValueError("Retry delay must be >= 0 (got: %s)" % value) | |
66 cls._get_retry_delay = value | |
67 return cls | |
68 | |
69 def __init__(self, galaxy_instance): | |
70 """ | |
71 A generic Client interface defining the common fields. | |
72 | |
73 All clients *must* define the following field (which will be | |
74 used as part of the URL composition (e.g., | |
75 ``http://<galaxy_instance>/api/libraries``): ``self.module = | |
76 'workflows' | 'libraries' | 'histories' | ...`` | |
77 """ | |
78 self.gi = galaxy_instance | |
79 self.url = '/'.join([self.gi.url, self.module]) | |
80 | |
81 def _get(self, id=None, deleted=False, contents=None, url=None, | |
82 params=None, json=True): | |
83 """ | |
84 Do a GET request, composing the URL from ``id``, ``deleted`` and | |
85 ``contents``. Alternatively, an explicit ``url`` can be provided. | |
86 If ``json`` is set to ``True``, return a decoded JSON object | |
87 (and treat an empty or undecodable response as an error). | |
88 | |
89 The request will optionally be retried as configured by | |
90 ``max_get_retries`` and ``get_retry_delay``: this offers some | |
91 resilience in the presence of temporary failures. | |
92 | |
93 :return: The decoded response if ``json`` is set to ``True``, otherwise | |
94 the response object | |
95 """ | |
96 if not url: | |
97 url = self.gi._make_url(self, module_id=id, deleted=deleted, | |
98 contents=contents) | |
99 attempts_left = self.max_get_retries() | |
100 retry_delay = self.get_retry_delay() | |
101 bioblend.log.debug("GET - attempts left: %s; retry delay: %s", | |
102 attempts_left, retry_delay) | |
103 msg = '' | |
104 while attempts_left > 0: | |
105 attempts_left -= 1 | |
106 try: | |
107 r = self.gi.make_get_request(url, params=params) | |
108 except (requests.exceptions.ConnectionError, ProtocolError) as e: | |
109 msg = str(e) | |
110 r = requests.Response() # empty Response object used when raising ConnectionError | |
111 else: | |
112 if r.status_code == 200: | |
113 if not json: | |
114 return r | |
115 elif not r.content: | |
116 msg = "GET: empty response" | |
117 else: | |
118 try: | |
119 return r.json() | |
120 except ValueError: | |
121 msg = "GET: invalid JSON : %r" % (r.content,) | |
122 else: | |
123 msg = "GET: error %s: %r" % (r.status_code, r.content) | |
124 msg = "%s, %d attempts left" % (msg, attempts_left) | |
125 if attempts_left <= 0: | |
126 bioblend.log.error(msg) | |
127 raise ConnectionError(msg, body=r.text, | |
128 status_code=r.status_code) | |
129 else: | |
130 bioblend.log.warning(msg) | |
131 time.sleep(retry_delay) | |
132 | |
133 def _post(self, payload, id=None, deleted=False, contents=None, url=None, | |
134 files_attached=False): | |
135 """ | |
136 Do a generic POST request, composing the url from the contents of the | |
137 arguments. Alternatively, an explicit ``url`` can be provided to use | |
138 for the request. ``payload`` must be a dict that contains additional | |
139 request arguments which will be sent along with the request body. | |
140 The payload dict may contain file handles (in which case the | |
141 ``files_attached`` flag must be set to true). | |
142 | |
143 If ``files_attached`` is set to ``False``, the request body will be | |
144 JSON-encoded; otherwise, it will be encoded as multipart/form-data. | |
145 | |
146 :return: The decoded response. | |
147 """ | |
148 if not url: | |
149 url = self.gi._make_url(self, module_id=id, deleted=deleted, | |
150 contents=contents) | |
151 return self.gi.make_post_request(url, payload=payload, | |
152 files_attached=files_attached) | |
153 | |
154 def _put(self, payload, id=None, url=None, params=None): | |
155 """ | |
156 Do a generic PUT request, composing the url from the contents of the | |
157 arguments. Alternatively, an explicit ``url`` can be provided to use | |
158 for the request. ``payload`` must be a dict that contains additional | |
159 request arguments which will be sent along with the request body. | |
160 | |
161 :return: The decoded response. | |
162 """ | |
163 if not url: | |
164 url = self.gi._make_url(self, module_id=id) | |
165 return self.gi.make_put_request(url, payload=payload, params=params) | |
166 | |
167 def _patch(self, payload, id=None, url=None, params=None): | |
168 """ | |
169 Do a generic PATCH request, composing the url from the contents of the | |
170 arguments. Alternatively, an explicit ``url`` can be provided to use | |
171 for the request. ``payload`` must be a dict that contains additional | |
172 request arguments which will be sent along with the request body. | |
173 | |
174 :return: The decoded response. | |
175 """ | |
176 if not url: | |
177 url = self.gi._make_url(self, module_id=id) | |
178 return self.gi.make_patch_request(url, payload=payload, params=params) | |
179 | |
180 def _delete(self, payload=None, id=None, deleted=False, contents=None, url=None, params=None): | |
181 """ | |
182 Do a generic DELETE request, composing the url from the contents of the | |
183 arguments. Alternatively, an explicit ``url`` can be provided to use | |
184 for the request. ``payload`` must be a dict that contains additional | |
185 request arguments which will be sent along with the request body. | |
186 | |
187 :return: The decoded response. | |
188 """ | |
189 if not url: | |
190 url = self.gi._make_url(self, module_id=id, deleted=deleted, | |
191 contents=contents) | |
192 r = self.gi.make_delete_request(url, payload=payload, params=params) | |
193 if r.status_code == 200: | |
194 return r.json() | |
195 # @see self.body for HTTP response body | |
196 raise ConnectionError("Unexpected HTTP status code: %s" % r.status_code, | |
197 body=r.text, status_code=r.status_code) |