Example #1
0
    def make_put_request(self, url, payload=None, params=None):
        """
        Make a PUT request using the provided ``url`` with required payload.
        The ``payload`` must be a dict that can be converted into a JSON
        object (via ``json.dumps``).

        :return: The decoded response.
        """
        if params is not None and params.get('key', False) is False:
            params['key'] = self.key
        else:
            params = self.default_params

        payload = json.dumps(payload)
        headers = self.json_headers
        r = requests.put(url,
                         data=payload,
                         params=params,
                         headers=headers,
                         verify=self.verify)
        if r.status_code == 200:
            try:
                return r.json()
            except Exception as e:
                raise ConnectionError(
                    "Request was successful, but cannot decode the response content: %s"
                    % e,
                    body=r.content,
                    status_code=r.status_code)
        # @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)
Example #2
0
    def make_patch_request(self, url, payload=None, params=None):
        """
        Make a PATCH request using the provided ``url`` with required payload.

        :type payload: dict
        :param payload: a JSON-serializable dictionary

        :return: The decoded response.
        """
        payload = json.dumps(payload)
        headers = self.json_headers
        r = requests.patch(url,
                           data=payload,
                           params=params,
                           headers=headers,
                           verify=self.verify,
                           timeout=self.timeout,
                           allow_redirects=False)
        if r.status_code == 200:
            try:
                return r.json()
            except Exception as e:
                raise ConnectionError(
                    "Request was successful, but cannot decode the response content: %s"
                    % e,
                    body=r.content,
                    status_code=r.status_code)
        # @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)
Example #3
0
    def make_post_request(self,
                          url,
                          payload,
                          params=None,
                          files_attached=False):
        """
        Make a POST request using the provided ``url`` and ``payload``.
        The ``payload`` must be a dict that contains the request values.
        The payload dict may contain file handles (in which case the files_attached
        flag must be set to true).

        If the ``params`` are not provided, use ``default_params`` class field.
        If params are provided and the provided dict does not have ``key`` key,
        the default ``self.key`` value will be included in what's passed to
        the server via the request.

        :return: The decoded response.
        """
        if params is not None and params.get('key', False) is False:
            params['key'] = self.key
        else:
            params = self.default_params

        # Compute data, headers, params arguments for request.post,
        # leveraging the requests-toolbelt library if any files have
        # been attached.
        if files_attached:
            payload.update(params)
            payload = MultipartEncoder(fields=payload)
            headers = self.json_headers.copy()
            headers['Content-Type'] = payload.content_type
            post_params = {}
        else:
            payload = json.dumps(payload)
            headers = self.json_headers
            post_params = params

        r = requests.post(url,
                          data=payload,
                          headers=headers,
                          verify=self.verify,
                          params=post_params)
        if r.status_code == 200:
            try:
                return r.json()
            except Exception as e:
                raise ConnectionError(
                    "Request was successful, but cannot decode the response content: %s"
                    % e,
                    body=r.content,
                    status_code=r.status_code)
        # @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)
Example #4
0
    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)
Example #5
0
    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)
Example #6
0
    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.

        :type payload: dict
        :param payload: additional parameters to send in the body of the request

        :return: The decoded response.
        """
        if not url:
            url = self._make_url(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(
            f"Unexpected HTTP status code: {r.status_code}",
            body=r.text,
            status_code=r.status_code,
        )
Example #7
0
    def make_post_request(self, url, payload=None, params=None, files_attached=False):
        """
        Make a POST request using the provided ``url`` and ``payload``.
        The ``payload`` must be a dict that contains the request values.
        The payload dict may contain file handles (in which case the files_attached
        flag must be set to true).

        If the ``params`` are not provided, use ``default_params`` class field.
        If params are provided and the provided dict does not have ``key`` key,
        the default ``self.key`` value will be included in what's passed to
        the server via the request.

        :return: The decoded response.
        """

        def my_dumps(d):
            """
            Apply ``json.dumps()`` to the values of the dict ``d`` if they are
            not of type ``FileStream``.
            """
            for k, v in d.items():
                if not isinstance(v, FileStream):
                    d[k] = json.dumps(v)
            return d

        # Compute data, headers, params arguments for request.post,
        # leveraging the requests-toolbelt library if any files have
        # been attached.
        if files_attached:
            payload = my_dumps(payload)
            if params:
                payload.update(params)
            payload = MultipartEncoder(fields=payload)
            headers = self.json_headers.copy()
            headers['Content-Type'] = payload.content_type
            post_params = None
        else:
            if payload is not None:
                payload = json.dumps(payload)
            headers = self.json_headers
            post_params = params

        r = requests.post(
            url,
            params=post_params,
            data=payload,
            headers=headers,
            timeout=self.timeout,
            allow_redirects=False,
            verify=self.verify,
        )
        if r.status_code == 200:
            try:
                return r.json()
            except Exception as e:
                raise ConnectionError(
                    f"Request was successful, but cannot decode the response content: {e}",
                    body=r.content,
                    status_code=r.status_code,
                )
        # @see self.body for HTTP response body
        raise ConnectionError(
            f"Unexpected HTTP status code: {r.status_code}",
            body=r.text,
            status_code=r.status_code,
        )