Example #1
0
    def response(self, timeout=None, fallback_result=SENTINEL, exceptions_to_catch=FALLBACK_EXCEPTIONS):
        """Blocking call to wait for the HTTP response.

        :param timeout: Number of seconds to wait for a response. Defaults to
            None which means wait indefinitely.
        :type timeout: float
        :param fallback_result: either the swagger result or a callable that accepts an exception as argument
            and returns the swagger result to use in case of errors
        :type fallback_result: Optional[Union[Any, Callable[[Exception], Any]]]
        :param exceptions_to_catch: Exception classes to catch and call `fallback_result`
            with. Has no effect if `fallback_result` is not provided. By default, `fallback_result`
            will be called for read timeout and server errors (HTTP 5XX).
        :type exceptions_to_catch: List/Tuple of Exception classes.
        :return: A BravadoResponse instance containing the swagger result and response metadata.
        """
        incoming_response = None
        exc_info = None
        request_end_time = None
        if self.request_config.force_fallback_result:
            exceptions_to_catch = tuple(chain(exceptions_to_catch, (ForcedFallbackResultError,)))

        try:
            incoming_response = self._get_incoming_response(timeout)
            request_end_time = monotonic.monotonic()

            swagger_result = self._get_swagger_result(incoming_response)

            if self.operation is None and incoming_response.status_code >= 300:
                raise make_http_exception(response=incoming_response)

            # Trigger fallback_result if the option is set
            if fallback_result is not SENTINEL and self.request_config.force_fallback_result:
                if self.operation.swagger_spec.config['bravado'].disable_fallback_results:
                    log.warning(
                        'force_fallback_result set in request options and disable_fallback_results '
                        'set in client config; not using fallback result.'
                    )
                else:
                    # raise an exception to trigger fallback result handling
                    raise ForcedFallbackResultError()

        except exceptions_to_catch as e:
            if request_end_time is None:
                request_end_time = monotonic.monotonic()
            # the Python 2 documentation states that we shouldn't assign the traceback to a local variable,
            # as that would cause a circular reference. We'll store a string representation of the traceback
            # instead.
            exc_info = list(sys.exc_info()[:2])
            exc_info.append(traceback.format_exc())
            if (
                fallback_result is not SENTINEL and
                self.operation and
                not self.operation.swagger_spec.config['bravado'].disable_fallback_results
            ):
                swagger_result = fallback_result(e) if callable(fallback_result) else fallback_result
            else:
                six.reraise(*sys.exc_info())

        metadata_class = self.operation.swagger_spec.config['bravado'].response_metadata_class
        response_metadata = metadata_class(
            incoming_response=incoming_response,
            swagger_result=swagger_result,
            start_time=self._start_time,
            request_end_time=request_end_time,
            handled_exception_info=exc_info,
            request_config=self.request_config,
        )
        return BravadoResponse(
            result=swagger_result,
            metadata=response_metadata,
        )
Example #2
0
    def response(
            self,
            timeout=None,  # type: typing.Optional[float]
            fallback_result=SENTINEL,  # type: typing.Union[_SENTINEL, T, typing.Callable[[BaseException], T]]  # noqa
            exceptions_to_catch=FALLBACK_EXCEPTIONS,  # type: typing.Tuple[typing.Type[BaseException], ...]
    ):
        # type: (...) -> BravadoResponse[T]
        """Blocking call to wait for the HTTP response.

        :param timeout: Number of seconds to wait for a response. Defaults to
            None which means wait indefinitely.
        :type timeout: float
        :param fallback_result: either the swagger result or a callable that accepts an exception as argument
            and returns the swagger result to use in case of errors
        :param exceptions_to_catch: Exception classes to catch and call `fallback_result`
            with. Has no effect if `fallback_result` is not provided. By default, `fallback_result`
            will be called for read timeout and server errors (HTTP 5XX).
        :return: A BravadoResponse instance containing the swagger result and response metadata.
        """
        incoming_response = None
        exc_info = None  # type: typing.Optional[typing.List[typing.Union[typing.Type[BaseException], BaseException, typing.Text]]]  # noqa: E501
        request_end_time = None
        if self.request_config.force_fallback_result:
            exceptions_to_catch = tuple(
                chain(exceptions_to_catch, (ForcedFallbackResultError, )))

        try:
            incoming_response = self._get_incoming_response(timeout)
            request_end_time = monotonic.monotonic()

            swagger_result = self._get_swagger_result(incoming_response)

            if self.operation is None and incoming_response.status_code >= 300:
                raise make_http_exception(response=incoming_response)

            # Trigger fallback_result if the option is set
            if fallback_result is not SENTINEL and self.request_config.force_fallback_result:
                if self._bravado_config.disable_fallback_results:
                    log.warning(
                        'force_fallback_result set in request options and disable_fallback_results '
                        'set in client config; not using fallback result.')
                else:
                    # raise an exception to trigger fallback result handling
                    raise ForcedFallbackResultError()

        except exceptions_to_catch as e:
            if request_end_time is None:
                request_end_time = monotonic.monotonic()
            exc_info = []
            # the return values of exc_info are annotated as Optional, but we know they are set in this case.
            # additionally, we can't use a cast() since that caused a runtime exception on some older versions
            # of Python 3.5.
            exc_info.extend(sys.exc_info()[:2])  # type: ignore
            # the Python 2 documentation states that we shouldn't assign the traceback to a local variable,
            # as that would cause a circular reference. We'll store a string representation of the traceback
            # instead.
            exc_info.append(traceback.format_exc())

            if (fallback_result is not SENTINEL and self.operation
                    and not self.operation.swagger_spec.config['bravado'].
                    disable_fallback_results):
                if callable(fallback_result):
                    swagger_result = fallback_result(e)
                else:
                    swagger_result = typing.cast(T, fallback_result)
            else:
                six.reraise(*sys.exc_info())

        metadata_class = self._bravado_config.response_metadata_class
        response_metadata = metadata_class(
            incoming_response=incoming_response,
            swagger_result=swagger_result,
            start_time=self._start_time,
            request_end_time=request_end_time,
            handled_exception_info=exc_info,
            request_config=self.request_config,
        )
        return BravadoResponse(
            result=swagger_result,
            metadata=response_metadata,
        )