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) |
