Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/bioblend/galaxyclient.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
comparison
equal
deleted
inserted
replaced
4:79f47841a781 | 5:9b1c78e6ba9c |
---|---|
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} |