Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/bioblend/galaxyclient.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
| author | shellac |
|---|---|
| date | Sat, 02 May 2020 07:14:21 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:26e78fe6e8c4 |
|---|---|
| 1 """ | |
| 2 Helper class for Galaxy and ToolShed Instance object | |
| 3 | |
| 4 This class is primarily a helper for the library and user code | |
| 5 should not use it directly. | |
| 6 A base representation of an instance | |
| 7 """ | |
| 8 import base64 | |
| 9 import json | |
| 10 | |
| 11 import requests | |
| 12 import six | |
| 13 from requests_toolbelt import MultipartEncoder | |
| 14 from six.moves.urllib.parse import urljoin, urlparse | |
| 15 | |
| 16 from bioblend import ConnectionError | |
| 17 from bioblend.util import FileStream | |
| 18 | |
| 19 | |
| 20 class GalaxyClient(object): | |
| 21 | |
| 22 def __init__(self, url, key=None, email=None, password=None, verify=True, timeout=None): | |
| 23 """ | |
| 24 :param verify: Whether to verify the server's TLS certificate | |
| 25 :type verify: bool | |
| 26 :param timeout: Timeout for requests operations, set to None for no timeout (the default). | |
| 27 :type timeout: float | |
| 28 """ | |
| 29 # Make sure the url scheme is defined (otherwise requests will not work) | |
| 30 if not urlparse(url).scheme: | |
| 31 url = "http://" + url | |
| 32 # All of Galaxy's and ToolShed's API's are rooted at <url>/api so make that the url | |
| 33 self.base_url = url | |
| 34 self.url = urljoin(url, 'api') | |
| 35 # If key has been supplied, use it; otherwise just set email and | |
| 36 # password and grab user's key before first request. | |
| 37 if key: | |
| 38 self._key = key | |
| 39 else: | |
| 40 self._key = None | |
| 41 self.email = email | |
| 42 self.password = password | |
| 43 self.json_headers = {'Content-Type': 'application/json'} | |
| 44 self.verify = verify | |
| 45 self.timeout = timeout | |
| 46 | |
| 47 def _make_url(self, module, module_id=None, deleted=False, contents=False): | |
| 48 """ | |
| 49 Compose a URL based on the provided arguments. | |
| 50 | |
| 51 :type module: :class:`~.galaxy.Client` subclass | |
| 52 :param module: The base module for which to make the URL. For | |
| 53 example: an object of class LibraryClient, WorkflowClient, | |
| 54 HistoryClient, ToolShedClient | |
| 55 | |
| 56 :type module_id: str | |
| 57 :param module_id: The encoded ID for a specific module (eg, library ID) | |
| 58 | |
| 59 :type deleted: bool | |
| 60 :param deleted: If ``True``, include ``deleted`` in the URL, after the module | |
| 61 name (eg, ``<base_url>/api/libraries/deleted``) | |
| 62 | |
| 63 :type contents: bool | |
| 64 :param contents: If ``True``, include 'contents' in the URL, after the module ID: | |
| 65 ``<base_url>/api/libraries/<encoded_library_id>/contents`` | |
| 66 """ | |
| 67 c_url = '/'.join([self.url, module.module]) | |
| 68 if deleted is True: | |
| 69 c_url = '/'.join([c_url, 'deleted']) | |
| 70 if module_id is not None: | |
| 71 c_url = '/'.join([c_url, module_id]) | |
| 72 if contents is True: | |
| 73 c_url = '/'.join([c_url, 'contents']) | |
| 74 return c_url | |
| 75 | |
| 76 def make_get_request(self, url, **kwargs): | |
| 77 """ | |
| 78 Make a GET request using the provided ``url``. | |
| 79 | |
| 80 Keyword arguments are the same as in requests.request. | |
| 81 | |
| 82 If ``verify`` is not provided, ``self.verify`` will be used. | |
| 83 | |
| 84 If the ``params`` are not provided, use ``default_params`` class field. | |
| 85 If params are provided and the provided dict does not have ``key`` key, | |
| 86 the default ``self.key`` value will be included in what's passed to | |
| 87 the server via the request. | |
| 88 | |
| 89 :rtype: requests.Response | |
| 90 :return: the response object. | |
| 91 """ | |
| 92 params = kwargs.get('params') | |
| 93 if params is not None and params.get('key', False) is False: | |
| 94 params['key'] = self.key | |
| 95 else: | |
| 96 params = self.default_params | |
| 97 kwargs['params'] = params | |
| 98 kwargs.setdefault('verify', self.verify) | |
| 99 kwargs.setdefault('timeout', self.timeout) | |
| 100 r = requests.get(url, **kwargs) | |
| 101 return r | |
| 102 | |
| 103 def make_post_request(self, url, payload, params=None, files_attached=False): | |
| 104 """ | |
| 105 Make a POST request using the provided ``url`` and ``payload``. | |
| 106 The ``payload`` must be a dict that contains the request values. | |
| 107 The payload dict may contain file handles (in which case the files_attached | |
| 108 flag must be set to true). | |
| 109 | |
| 110 If the ``params`` are not provided, use ``default_params`` class field. | |
| 111 If params are provided and the provided dict does not have ``key`` key, | |
| 112 the default ``self.key`` value will be included in what's passed to | |
| 113 the server via the request. | |
| 114 | |
| 115 :return: The decoded response. | |
| 116 """ | |
| 117 | |
| 118 def my_dumps(d): | |
| 119 """ | |
| 120 Apply ``json.dumps()`` to the values of the dict ``d`` if they are | |
| 121 not of type ``FileStream``. | |
| 122 """ | |
| 123 for k, v in d.items(): | |
| 124 if not isinstance(v, FileStream): | |
| 125 d[k] = json.dumps(v) | |
| 126 return d | |
| 127 | |
| 128 if params is not None and params.get('key', False) is False: | |
| 129 params['key'] = self.key | |
| 130 else: | |
| 131 params = self.default_params | |
| 132 | |
| 133 # Compute data, headers, params arguments for request.post, | |
| 134 # leveraging the requests-toolbelt library if any files have | |
| 135 # been attached. | |
| 136 if files_attached: | |
| 137 payload = my_dumps(payload) | |
| 138 payload.update(params) | |
| 139 payload = MultipartEncoder(fields=payload) | |
| 140 headers = self.json_headers.copy() | |
| 141 headers['Content-Type'] = payload.content_type | |
| 142 post_params = {} | |
| 143 else: | |
| 144 payload = json.dumps(payload) | |
| 145 headers = self.json_headers | |
| 146 post_params = params | |
| 147 | |
| 148 r = requests.post(url, data=payload, headers=headers, | |
| 149 verify=self.verify, params=post_params, | |
| 150 timeout=self.timeout) | |
| 151 if r.status_code == 200: | |
| 152 try: | |
| 153 return r.json() | |
| 154 except Exception as e: | |
| 155 raise ConnectionError("Request was successful, but cannot decode the response content: %s" % | |
| 156 e, body=r.content, status_code=r.status_code) | |
| 157 # @see self.body for HTTP response body | |
| 158 raise ConnectionError("Unexpected HTTP status code: %s" % r.status_code, | |
| 159 body=r.text, status_code=r.status_code) | |
| 160 | |
| 161 def make_delete_request(self, url, payload=None, params=None): | |
| 162 """ | |
| 163 Make a DELETE request using the provided ``url`` and the optional | |
| 164 arguments. | |
| 165 | |
| 166 If the ``params`` are not provided, use ``default_params`` class field. | |
| 167 If params are provided and the provided dict does not have ``key`` key, | |
| 168 the default ``self.key`` value will be included in what's passed to | |
| 169 the server via the request. | |
| 170 | |
| 171 :type payload: dict | |
| 172 :param payload: a JSON-serializable dictionary | |
| 173 | |
| 174 :rtype: requests.Response | |
| 175 :return: the response object. | |
| 176 """ | |
| 177 if params is not None and params.get('key', False) is False: | |
| 178 params['key'] = self.key | |
| 179 else: | |
| 180 params = self.default_params | |
| 181 if payload is not None: | |
| 182 payload = json.dumps(payload) | |
| 183 headers = self.json_headers | |
| 184 r = requests.delete(url, verify=self.verify, data=payload, params=params, | |
| 185 headers=headers, timeout=self.timeout) | |
| 186 return r | |
| 187 | |
| 188 def make_put_request(self, url, payload=None, params=None): | |
| 189 """ | |
| 190 Make a PUT request using the provided ``url`` with required payload. | |
| 191 | |
| 192 :type payload: dict | |
| 193 :param payload: a JSON-serializable dictionary | |
| 194 | |
| 195 :return: The decoded response. | |
| 196 """ | |
| 197 if params is not None and params.get('key', False) is False: | |
| 198 params['key'] = self.key | |
| 199 else: | |
| 200 params = self.default_params | |
| 201 | |
| 202 payload = json.dumps(payload) | |
| 203 headers = self.json_headers | |
| 204 r = requests.put(url, data=payload, params=params, headers=headers, | |
| 205 verify=self.verify, timeout=self.timeout) | |
| 206 if r.status_code == 200: | |
| 207 try: | |
| 208 return r.json() | |
| 209 except Exception as e: | |
| 210 raise ConnectionError("Request was successful, but cannot decode the response content: %s" % | |
| 211 e, body=r.content, status_code=r.status_code) | |
| 212 # @see self.body for HTTP response body | |
| 213 raise ConnectionError("Unexpected HTTP status code: %s" % r.status_code, | |
| 214 body=r.text, status_code=r.status_code) | |
| 215 | |
| 216 def make_patch_request(self, url, payload=None, params=None): | |
| 217 """ | |
| 218 Make a PATCH request using the provided ``url`` with required payload. | |
| 219 | |
| 220 :type payload: dict | |
| 221 :param payload: a JSON-serializable dictionary | |
| 222 | |
| 223 :return: The decoded response. | |
| 224 """ | |
| 225 if params is not None and params.get('key', False) is False: | |
| 226 params['key'] = self.key | |
| 227 else: | |
| 228 params = self.default_params | |
| 229 | |
| 230 payload = json.dumps(payload) | |
| 231 headers = self.json_headers | |
| 232 r = requests.patch(url, data=payload, params=params, headers=headers, | |
| 233 verify=self.verify, timeout=self.timeout) | |
| 234 if r.status_code == 200: | |
| 235 try: | |
| 236 return r.json() | |
| 237 except Exception as e: | |
| 238 raise ConnectionError("Request was successful, but cannot decode the response content: %s" % | |
| 239 e, body=r.content, status_code=r.status_code) | |
| 240 # @see self.body for HTTP response body | |
| 241 raise ConnectionError("Unexpected HTTP status code: %s" % r.status_code, | |
| 242 body=r.text, status_code=r.status_code) | |
| 243 | |
| 244 @property | |
| 245 def key(self): | |
| 246 if not self._key and self.email is not None and self.password is not None: | |
| 247 unencoded_credentials = "%s:%s" % (self.email, self.password) | |
| 248 authorization = base64.b64encode(unencoded_credentials.encode()) | |
| 249 headers = self.json_headers.copy() | |
| 250 headers["Authorization"] = authorization | |
| 251 auth_url = "%s/authenticate/baseauth" % self.url | |
| 252 # make_post_request uses default_params, which uses this and | |
| 253 # sets wrong headers - so using lower level method. | |
| 254 r = requests.get(auth_url, verify=self.verify, headers=headers) | |
| 255 if r.status_code != 200: | |
| 256 raise Exception("Failed to authenticate user.") | |
| 257 response = r.json() | |
| 258 if isinstance(response, (six.string_types, six.text_type)): | |
| 259 # bug in Tool Shed | |
| 260 response = json.loads(response) | |
| 261 self._key = response["api_key"] | |
| 262 return self._key | |
| 263 | |
| 264 @property | |
| 265 def default_params(self): | |
| 266 return {'key': self.key} |
