diff env/lib/python3.7/site-packages/bioblend/galaxy/client.py @ 0:26e78fe6e8c4 draft

"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author shellac
date Sat, 02 May 2020 07:14:21 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/env/lib/python3.7/site-packages/bioblend/galaxy/client.py	Sat May 02 07:14:21 2020 -0400
@@ -0,0 +1,197 @@
+"""
+An interface the clients should implement.
+
+This class is primarily a helper for the library and user code
+should not use it directly.
+"""
+
+import time
+
+import requests
+from requests.packages.urllib3.exceptions import ProtocolError
+
+import bioblend
+# The following import must be preserved for compatibility because
+# ConnectionError class was originally defined here
+from bioblend import ConnectionError  # noqa: I202
+
+
+class Client(object):
+
+    # Class variables that configure GET request retries.  Note that since these
+    # are class variables their values are shared by all Client instances --
+    # i.e., HistoryClient, WorkflowClient, etc.
+    #
+    # Number of attempts before giving up on a GET request.
+    _max_get_retries = 1
+    # Delay in seconds between subsequent retries.
+    _get_retry_delay = 10
+
+    @classmethod
+    def max_get_retries(cls):
+        """
+        The maximum number of attempts for a GET request.
+        """
+        return cls._max_get_retries
+
+    @classmethod
+    def set_max_get_retries(cls, value):
+        """
+        Set the maximum number of attempts for GET requests. A value greater
+        than one causes failed GET requests to be retried `value` - 1 times.
+
+        Default: 1
+        """
+        if value < 1:
+            raise ValueError("Number of retries must be >= 1 (got: %s)" % value)
+        cls._max_get_retries = value
+        return cls
+
+    @classmethod
+    def get_retry_delay(cls):
+        """
+        The delay (in seconds) to wait before retrying a failed GET
+        request.
+        """
+        return cls._get_retry_delay
+
+    @classmethod
+    def set_get_retry_delay(cls, value):
+        """
+        Set the delay (in seconds) to wait before retrying a failed GET
+        request. Default: 10
+        """
+        if value < 0:
+            raise ValueError("Retry delay must be >= 0 (got: %s)" % value)
+        cls._get_retry_delay = value
+        return cls
+
+    def __init__(self, galaxy_instance):
+        """
+        A generic Client interface defining the common fields.
+
+        All clients *must* define the following field (which will be
+        used as part of the URL composition (e.g.,
+        ``http://<galaxy_instance>/api/libraries``): ``self.module =
+        'workflows' | 'libraries' | 'histories' | ...``
+        """
+        self.gi = galaxy_instance
+        self.url = '/'.join([self.gi.url, self.module])
+
+    def _get(self, id=None, deleted=False, contents=None, url=None,
+             params=None, json=True):
+        """
+        Do a GET request, composing the URL from ``id``, ``deleted`` and
+        ``contents``.  Alternatively, an explicit ``url`` can be provided.
+        If ``json`` is set to ``True``, return a decoded JSON object
+        (and treat an empty or undecodable response as an error).
+
+        The request will optionally be retried as configured by
+        ``max_get_retries`` and ``get_retry_delay``: this offers some
+        resilience in the presence of temporary failures.
+
+        :return: The decoded response if ``json`` is set to ``True``, otherwise
+          the response object
+        """
+        if not url:
+            url = self.gi._make_url(self, module_id=id, deleted=deleted,
+                                    contents=contents)
+        attempts_left = self.max_get_retries()
+        retry_delay = self.get_retry_delay()
+        bioblend.log.debug("GET - attempts left: %s; retry delay: %s",
+                           attempts_left, retry_delay)
+        msg = ''
+        while attempts_left > 0:
+            attempts_left -= 1
+            try:
+                r = self.gi.make_get_request(url, params=params)
+            except (requests.exceptions.ConnectionError, ProtocolError) as e:
+                msg = str(e)
+                r = requests.Response()  # empty Response object used when raising ConnectionError
+            else:
+                if r.status_code == 200:
+                    if not json:
+                        return r
+                    elif not r.content:
+                        msg = "GET: empty response"
+                    else:
+                        try:
+                            return r.json()
+                        except ValueError:
+                            msg = "GET: invalid JSON : %r" % (r.content,)
+                else:
+                    msg = "GET: error %s: %r" % (r.status_code, r.content)
+            msg = "%s, %d attempts left" % (msg, attempts_left)
+            if attempts_left <= 0:
+                bioblend.log.error(msg)
+                raise ConnectionError(msg, body=r.text,
+                                      status_code=r.status_code)
+            else:
+                bioblend.log.warning(msg)
+                time.sleep(retry_delay)
+
+    def _post(self, payload, id=None, deleted=False, contents=None, url=None,
+              files_attached=False):
+        """
+        Do a generic POST request, composing the url from the contents of the
+        arguments. Alternatively, an explicit ``url`` can be provided to use
+        for the request. ``payload`` must be a dict that contains additional
+        request arguments which will be sent along with the request body.
+        The payload dict may contain file handles (in which case the
+        ``files_attached`` flag must be set to true).
+
+        If ``files_attached`` is set to ``False``, the request body will be
+        JSON-encoded; otherwise, it will be encoded as multipart/form-data.
+
+        :return: The decoded response.
+        """
+        if not url:
+            url = self.gi._make_url(self, module_id=id, deleted=deleted,
+                                    contents=contents)
+        return self.gi.make_post_request(url, payload=payload,
+                                         files_attached=files_attached)
+
+    def _put(self, payload, id=None, url=None, params=None):
+        """
+        Do a generic PUT request, composing the url from the contents of the
+        arguments. Alternatively, an explicit ``url`` can be provided to use
+        for the request. ``payload`` must be a dict that contains additional
+        request arguments which will be sent along with the request body.
+
+        :return: The decoded response.
+        """
+        if not url:
+            url = self.gi._make_url(self, module_id=id)
+        return self.gi.make_put_request(url, payload=payload, params=params)
+
+    def _patch(self, payload, id=None, url=None, params=None):
+        """
+        Do a generic PATCH request, composing the url from the contents of the
+        arguments. Alternatively, an explicit ``url`` can be provided to use
+        for the request. ``payload`` must be a dict that contains additional
+        request arguments which will be sent along with the request body.
+
+        :return: The decoded response.
+        """
+        if not url:
+            url = self.gi._make_url(self, module_id=id)
+        return self.gi.make_patch_request(url, payload=payload, params=params)
+
+    def _delete(self, payload=None, id=None, deleted=False, contents=None, url=None, params=None):
+        """
+        Do a generic DELETE request, composing the url from the contents of the
+        arguments. Alternatively, an explicit ``url`` can be provided to use
+        for the request. ``payload`` must be a dict that contains additional
+        request arguments which will be sent along with the request body.
+
+        :return: The decoded response.
+        """
+        if not url:
+            url = self.gi._make_url(self, module_id=id, deleted=deleted,
+                                    contents=contents)
+        r = self.gi.make_delete_request(url, payload=payload, params=params)
+        if r.status_code == 200:
+            return r.json()
+        # @see self.body for HTTP response body
+        raise ConnectionError("Unexpected HTTP status code: %s" % r.status_code,
+                              body=r.text, status_code=r.status_code)