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