Source code for contentful_management.errors
"""
contentful_management.errors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This module implements the Error classes.
API reference: https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/errors
:copyright: (c) 2018 by Contentful GmbH.
:license: MIT, see LICENSE for more details.
"""
[docs]class HTTPError(Exception):
    """
    Base HTTP error class.
    """
    def __init__(self, response):
        self.response = response
        self.status_code = response.status_code
        message = self._best_available_message(response)
        super(HTTPError, self).__init__(message)
    def _default_error_message(self):
        return "The following error was received: {0}".format(self.response.text)
    def _handle_details(self, details):
        return "{0}".format(details)
    def _has_additional_error_info(self):
        return False
    def _additional_error_info(self):
        return []
    def _best_available_message(self, response):
        from .utils import json_error_class
        response_json = None
        error_message = [
          "HTTP status code: {0}".format(self.status_code),
        ]
        try:
            response_json = response.json()
            message = response_json.get('message', None)
            details = response_json.get('details', None)
            request_id = response_json.get('requestId', None)
            if message is not None:
                error_message.append("Message: {0}".format(message))
            else:
                error_message.append("Message: {0}".format(self._default_error_message()))
            if details is not None:
                error_message.append("Details: {0}".format(self._handle_details(details)))
            if request_id is not None:
                error_message.append("Request ID: {0}".format(request_id))
        except json_error_class():
            error_message.append("Message: {0}".format(self._default_error_message()))
        if self._has_additional_error_info():
            error_message += self._additional_error_info()
        return "\n".join(error_message) 
[docs]class BadRequestError(HTTPError):
    """
    400
    """
    def _default_error_message(self):
        return "The request was malformed or missing a required parameter."
    def _handle_details(self, details):
        from .utils import string_class
        if isinstance(details, string_class()):
            return details
        def _handle_detail(detail):
            if isinstance(detail, string_class()):
                return detail
            return detail.get('details', None)
        if 'errors' in details:
            inner_details = [_handle_detail(detail) for detail in details['errors']]
            inner_details = [detail for detail in inner_details if detail is not None]  # This works in both Py2 and Py3
            return "\n\t".join(inner_details)
        return str(details) 
[docs]class UnauthorizedError(HTTPError):
    """
    401
    """
    def _default_error_message(self):
        return "The authorization token was invalid." 
[docs]class AccessDeniedError(HTTPError):
    """
    403
    """
    def _default_error_message(self):
        return "The specified token does not have access to the requested resource."
    def _handle_details(self, details):
        return "\n\tReasons:\n\t\t{0}".format("\n\t\t".join(details['reasons'])) 
[docs]class NotFoundError(HTTPError):
    """
    404
    """
    def _default_error_message(self):
        return "The requested resource or endpoint could not be found."
    def _handle_details(self, details):
        from .utils import string_class
        if isinstance(details, string_class()):
            return details
        message = "The requested {0} could not be found.".format(details['type'])
        resource_id = details.get('id', None)
        if resource_id is not None:
            message += " ID: {0}.".format(resource_id)
        return message 
[docs]class VersionMismatchError(HTTPError):
    """
    409
    """
    def _default_error_message(self):
        return 'Version mismatch error. The version you specified was incorrect. This may be due to someone else editing the content.' 
[docs]class UnprocessableEntityError(HTTPError):
    """
    422
    """
    def _default_error_message(self):
        return 'The resource you sent in the body is invalid.'
    def _handle_error(self, error):
        message = ''
        if 'name' in error and 'path' in error:
            message = "\t* Name: {0} - Path: '{1}'".format(
                error['name'],
                error['path']
            )
        else:
            message = self._default_error_message()
        if 'value' in error:
            message = "{0} - Value: '{1}'".format(
                message,
                error['value']
            )
        return message
    def _handle_details(self, details):
        errors = []
        for error in details['errors']:
            errors.append(self._handle_error(error))
        return '\n{0}'.format('\n'.join(errors)) 
[docs]class RateLimitExceededError(HTTPError):
    """
    429
    """
    RATE_LIMIT_RESET_HEADER_KEY = 'x-contentful-ratelimit-reset'
    def _has_reset_time(self):
        return self.RATE_LIMIT_RESET_HEADER_KEY in self.response.headers
[docs]    def reset_time(self):
        """Returns the reset time in seconds until next available request."""
        return int(self.response.headers[
            self.RATE_LIMIT_RESET_HEADER_KEY
        ]) 
    def _has_additional_error_info(self):
        return self._has_reset_time()
    def _additional_error_info(self):
        return ["Time until reset (seconds): {0}".format(self.reset_time())]
    def _default_error_message(self):
        return "Rate limit exceeded. Too many requests." 
[docs]class ServerError(HTTPError):
    """
    500
    """
    def _default_error_message(self):
        return "Internal server error." 
[docs]class BadGatewayError(HTTPError):
    """
    502
    """
    def _default_error_message(self):
        return "The requested space is hibernated." 
[docs]class ServiceUnavailableError(HTTPError):
    """
    503
    """
    def _default_error_message(self):
        return "The request was malformed or missing a required parameter." 
[docs]def get_error(response):
    """
    Gets Error by HTTP status code.
    """
    errors = {
        400: BadRequestError,
        401: UnauthorizedError,
        403: AccessDeniedError,
        404: NotFoundError,
        409: VersionMismatchError,
        422: UnprocessableEntityError,
        429: RateLimitExceededError,
        500: ServerError,
        502: BadGatewayError,
        503: ServiceUnavailableError
    }
    error_class = HTTPError
    if response.status_code in errors:
        error_class = errors[response.status_code]
    return error_class(response)