Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/bioblend/galaxy/client.py @ 0:d30785e31577 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:18:57 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:d30785e31577 |
|---|---|
| 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 | |
| 80 def _make_url(self, module_id=None, deleted=False, contents=False): | |
| 81 """ | |
| 82 Compose a URL based on the provided arguments. | |
| 83 | |
| 84 :type module_id: str | |
| 85 :param module_id: The encoded ID for a specific module (eg, library ID) | |
| 86 | |
| 87 :type deleted: bool | |
| 88 :param deleted: If ``True``, include ``deleted`` in the URL, after the module | |
| 89 name (eg, ``<base_url>/api/libraries/deleted``) | |
| 90 | |
| 91 :type contents: bool | |
| 92 :param contents: If ``True``, include 'contents' in the URL, after the module ID: | |
| 93 ``<base_url>/api/libraries/<encoded_library_id>/contents`` | |
| 94 """ | |
| 95 c_url = '/'.join((self.gi.url, self.module)) | |
| 96 if deleted is True: | |
| 97 c_url = c_url + '/deleted' | |
| 98 if module_id is not None: | |
| 99 c_url = '/'.join((c_url, module_id)) | |
| 100 if contents is True: | |
| 101 c_url = c_url + '/contents' | |
| 102 return c_url | |
| 103 | |
| 104 def _get(self, id=None, deleted=False, contents=None, url=None, | |
| 105 params=None, json=True): | |
| 106 """ | |
| 107 Do a GET request, composing the URL from ``id``, ``deleted`` and | |
| 108 ``contents``. Alternatively, an explicit ``url`` can be provided. | |
| 109 If ``json`` is set to ``True``, return a decoded JSON object | |
| 110 (and treat an empty or undecodable response as an error). | |
| 111 | |
| 112 The request will optionally be retried as configured by | |
| 113 ``max_get_retries`` and ``get_retry_delay``: this offers some | |
| 114 resilience in the presence of temporary failures. | |
| 115 | |
| 116 :return: The decoded response if ``json`` is set to ``True``, otherwise | |
| 117 the response object | |
| 118 """ | |
| 119 if not url: | |
| 120 url = self._make_url(module_id=id, deleted=deleted, contents=contents) | |
| 121 attempts_left = self.max_get_retries() | |
| 122 retry_delay = self.get_retry_delay() | |
| 123 bioblend.log.debug("GET - attempts left: %s; retry delay: %s", | |
| 124 attempts_left, retry_delay) | |
| 125 msg = '' | |
| 126 while attempts_left > 0: | |
| 127 attempts_left -= 1 | |
| 128 try: | |
| 129 r = self.gi.make_get_request(url, params=params) | |
| 130 except (requests.exceptions.ConnectionError, ProtocolError) as e: | |
| 131 msg = str(e) | |
| 132 r = requests.Response() # empty Response object used when raising ConnectionError | |
| 133 else: | |
| 134 if r.status_code == 200: | |
| 135 if not json: | |
| 136 return r | |
| 137 elif not r.content: | |
| 138 msg = "GET: empty response" | |
| 139 else: | |
| 140 try: | |
| 141 return r.json() | |
| 142 except ValueError: | |
| 143 msg = "GET: invalid JSON : %r" % (r.content,) | |
| 144 else: | |
| 145 msg = "GET: error %s: %r" % (r.status_code, r.content) | |
| 146 msg = "%s, %d attempts left" % (msg, attempts_left) | |
| 147 if attempts_left <= 0: | |
| 148 bioblend.log.error(msg) | |
| 149 raise ConnectionError(msg, body=r.text, | |
| 150 status_code=r.status_code) | |
| 151 else: | |
| 152 bioblend.log.warning(msg) | |
| 153 time.sleep(retry_delay) | |
| 154 | |
| 155 def _post(self, payload, id=None, deleted=False, contents=None, url=None, | |
| 156 files_attached=False): | |
| 157 """ | |
| 158 Do a generic POST request, composing the url from the contents of the | |
| 159 arguments. Alternatively, an explicit ``url`` can be provided to use | |
| 160 for the request. ``payload`` must be a dict that contains additional | |
| 161 request arguments which will be sent along with the request body. | |
| 162 The payload dict may contain file handles (in which case the | |
| 163 ``files_attached`` flag must be set to true). | |
| 164 | |
| 165 If ``files_attached`` is set to ``False``, the request body will be | |
| 166 JSON-encoded; otherwise, it will be encoded as multipart/form-data. | |
| 167 | |
| 168 :return: The decoded response. | |
| 169 """ | |
| 170 if not url: | |
| 171 url = self._make_url(module_id=id, deleted=deleted, contents=contents) | |
| 172 return self.gi.make_post_request(url, payload=payload, | |
| 173 files_attached=files_attached) | |
| 174 | |
| 175 def _put(self, payload, id=None, url=None, params=None): | |
| 176 """ | |
| 177 Do a generic PUT request, composing the url from the contents of the | |
| 178 arguments. Alternatively, an explicit ``url`` can be provided to use | |
| 179 for the request. ``payload`` must be a dict that contains additional | |
| 180 request arguments which will be sent along with the request body. | |
| 181 | |
| 182 :return: The decoded response. | |
| 183 """ | |
| 184 if not url: | |
| 185 url = self._make_url(module_id=id) | |
| 186 return self.gi.make_put_request(url, payload=payload, params=params) | |
| 187 | |
| 188 def _patch(self, payload, id=None, url=None, params=None): | |
| 189 """ | |
| 190 Do a generic PATCH request, composing the url from the contents of the | |
| 191 arguments. Alternatively, an explicit ``url`` can be provided to use | |
| 192 for the request. ``payload`` must be a dict that contains additional | |
| 193 request arguments which will be sent along with the request body. | |
| 194 | |
| 195 :return: The decoded response. | |
| 196 """ | |
| 197 if not url: | |
| 198 url = self._make_url(module_id=id) | |
| 199 return self.gi.make_patch_request(url, payload=payload, params=params) | |
| 200 | |
| 201 def _delete(self, payload=None, id=None, deleted=False, contents=None, url=None, params=None): | |
| 202 """ | |
| 203 Do a generic DELETE request, composing the url from the contents of the | |
| 204 arguments. Alternatively, an explicit ``url`` can be provided to use | |
| 205 for the request. ``payload`` must be a dict that contains additional | |
| 206 request arguments which will be sent along with the request body. | |
| 207 | |
| 208 :return: The decoded response. | |
| 209 """ | |
| 210 if not url: | |
| 211 url = self._make_url(module_id=id, deleted=deleted, contents=contents) | |
| 212 r = self.gi.make_delete_request(url, payload=payload, params=params) | |
| 213 if r.status_code == 200: | |
| 214 return r.json() | |
| 215 # @see self.body for HTTP response body | |
| 216 raise ConnectionError("Unexpected HTTP status code: %s" % r.status_code, | |
| 217 body=r.text, status_code=r.status_code) |
