Vehicle-Anti-Theft-Face-Rec.../venv/Lib/site-packages/gcloud/exceptions.py

224 lines
5.9 KiB
Python

# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Custom exceptions for :mod:`gcloud` package.
See: https://cloud.google.com/storage/docs/json_api/v1/status-codes
"""
import copy
import json
import six
_HTTP_CODE_TO_EXCEPTION = {} # populated at end of module
class GCloudError(Exception):
"""Base error class for gcloud errors (abstract).
Each subclass represents a single type of HTTP error response.
"""
code = None
"""HTTP status code. Concrete subclasses *must* define.
See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
"""
def __init__(self, message, errors=()):
super(GCloudError, self).__init__()
# suppress deprecation warning under 2.6.x
self.message = message
self._errors = errors
def __str__(self):
return '%d %s' % (self.code, self.message)
@property
def errors(self):
"""Detailed error information.
:rtype: list(dict)
:returns: a list of mappings describing each error.
"""
return [copy.deepcopy(error) for error in self._errors]
class Redirection(GCloudError):
"""Base for 3xx responses
This class is abstract.
"""
class MovedPermanently(Redirection):
"""Exception mapping a '301 Moved Permanently' response."""
code = 301
class NotModified(Redirection):
"""Exception mapping a '304 Not Modified' response."""
code = 304
class TemporaryRedirect(Redirection):
"""Exception mapping a '307 Temporary Redirect' response."""
code = 307
class ResumeIncomplete(Redirection):
"""Exception mapping a '308 Resume Incomplete' response."""
code = 308
class ClientError(GCloudError):
"""Base for 4xx responses
This class is abstract
"""
class BadRequest(ClientError):
"""Exception mapping a '400 Bad Request' response."""
code = 400
class Unauthorized(ClientError):
"""Exception mapping a '401 Unauthorized' response."""
code = 401
class Forbidden(ClientError):
"""Exception mapping a '403 Forbidden' response."""
code = 403
class NotFound(ClientError):
"""Exception mapping a '404 Not Found' response."""
code = 404
class MethodNotAllowed(ClientError):
"""Exception mapping a '405 Method Not Allowed' response."""
code = 405
class Conflict(ClientError):
"""Exception mapping a '409 Conflict' response."""
code = 409
class LengthRequired(ClientError):
"""Exception mapping a '411 Length Required' response."""
code = 411
class PreconditionFailed(ClientError):
"""Exception mapping a '412 Precondition Failed' response."""
code = 412
class RequestRangeNotSatisfiable(ClientError):
"""Exception mapping a '416 Request Range Not Satisfiable' response."""
code = 416
class TooManyRequests(ClientError):
"""Exception mapping a '429 Too Many Requests' response."""
code = 429
class ServerError(GCloudError):
"""Base for 5xx responses: (abstract)"""
class InternalServerError(ServerError):
"""Exception mapping a '500 Internal Server Error' response."""
code = 500
class MethodNotImplemented(ServerError):
"""Exception mapping a '501 Not Implemented' response."""
code = 501
class ServiceUnavailable(ServerError):
"""Exception mapping a '503 Service Unavailable' response."""
code = 503
def make_exception(response, content, error_info=None, use_json=True):
"""Factory: create exception based on HTTP response code.
:type response: :class:`httplib2.Response` or other HTTP response object
:param response: A response object that defines a status code as the
status attribute.
:type content: string or dictionary
:param content: The body of the HTTP error response.
:type error_info: string
:param error_info: Optional string giving extra information about the
failed request.
:type use_json: bool
:param use_json: Flag indicating if ``content`` is expected to be JSON.
:rtype: instance of :class:`GCloudError`, or a concrete subclass.
:returns: Exception specific to the error response.
"""
if isinstance(content, six.binary_type):
content = content.decode('utf-8')
if isinstance(content, six.string_types):
payload = None
if use_json:
try:
payload = json.loads(content)
except ValueError:
# Expected JSON but received something else.
pass
if payload is None:
payload = {'error': {'message': content}}
else:
payload = content
message = payload.get('error', {}).get('message', '')
errors = payload.get('error', {}).get('errors', ())
if error_info is not None:
message += ' (%s)' % (error_info,)
try:
klass = _HTTP_CODE_TO_EXCEPTION[response.status]
except KeyError:
error = GCloudError(message, errors)
error.code = response.status
else:
error = klass(message, errors)
return error
def _walk_subclasses(klass):
"""Recursively walk subclass tree."""
for sub in klass.__subclasses__():
yield sub
for subsub in _walk_subclasses(sub):
yield subsub
# Build the code->exception class mapping.
for _eklass in _walk_subclasses(GCloudError):
code = getattr(_eklass, 'code', None)
if code is not None:
_HTTP_CODE_TO_EXCEPTION[code] = _eklass