Source code for oss2.exceptions

# -*- coding: utf-8 -*-

"""
oss2.exceptions
~~~~~~~~~~~~~~

异常类。
"""

import re

import xml.etree.ElementTree as ElementTree
from xml.parsers import expat


from .compat import to_string


_OSS_ERROR_TO_EXCEPTION = {}  # populated at end of module


OSS_CLIENT_ERROR_STATUS = -1
OSS_REQUEST_ERROR_STATUS = -2
OSS_INCONSISTENT_ERROR_STATUS = -3


[docs]class OssError(Exception): def __init__(self, status, headers, body, details): #: HTTP 状态码 self.status = status #: 请求ID,用于跟踪一个OSS请求。提交工单时,最好能够提供请求ID self.request_id = headers.get('x-oss-request-id', '') #: HTTP响应体(部分) self.body = body #: 详细错误信息,是一个string到string的dict self.details = details #: OSS错误码 self.code = self.details.get('Code', '') #: OSS错误信息 self.message = self.details.get('Message', '') def __str__(self): error = {'status': self.status, 'request-id': self.request_id, 'details': self.details} return str(error) def _str_with_body(self): error = {'status': self.status, 'request-id': self.request_id, 'details': self.body} return str(error)
[docs]class ClientError(OssError): def __init__(self, message): OssError.__init__(self, OSS_CLIENT_ERROR_STATUS, {}, 'ClientError: ' + message, {}) def __str__(self): return self._str_with_body()
[docs]class RequestError(OssError): def __init__(self, e): OssError.__init__(self, OSS_REQUEST_ERROR_STATUS, {}, 'RequestError: ' + str(e), {}) self.exception = e def __str__(self): return self._str_with_body()
[docs]class InconsistentError(OssError): def __init__(self, message, request_id=''): OssError.__init__(self, OSS_INCONSISTENT_ERROR_STATUS, {'x-oss-request-id': request_id}, 'InconsistentError: ' + message, {}) def __str__(self): return self._str_with_body()
[docs]class ServerError(OssError): pass
[docs]class NotFound(ServerError): status = 404 code = ''
[docs]class MalformedXml(ServerError): status = 400 code = 'MalformedXML'
[docs]class InvalidRequest(ServerError): status = 400 code = 'InvalidRequest'
[docs]class OperationNotSupported(ServerError): status = 400 code = 'OperationNotSupported'
[docs]class RestoreAlreadyInProgress(ServerError): status = 409 code = 'RestoreAlreadyInProgress'
[docs]class InvalidArgument(ServerError): status = 400 code = 'InvalidArgument' def __init__(self, status, headers, body, details): super(InvalidArgument, self).__init__(status, headers, body, details) self.name = details.get('ArgumentName') self.value = details.get('ArgumentValue')
[docs]class InvalidDigest(ServerError): status = 400 code = 'InvalidDigest'
[docs]class InvalidObjectName(ServerError): status = 400 code = 'InvalidObjectName'
[docs]class NoSuchBucket(NotFound): status = 404 code = 'NoSuchBucket'
[docs]class NoSuchKey(NotFound): status = 404 code = 'NoSuchKey'
[docs]class NoSuchUpload(NotFound): status = 404 code = 'NoSuchUpload'
[docs]class NoSuchWebsite(NotFound): status = 404 code = 'NoSuchWebsiteConfiguration'
[docs]class NoSuchLifecycle(NotFound): status = 404 code = 'NoSuchLifecycle'
[docs]class NoSuchCors(NotFound): status = 404 code = 'NoSuchCORSConfiguration'
[docs]class NoSuchLiveChannel(NotFound): status = 404 code = 'NoSuchLiveChannel'
[docs]class Conflict(ServerError): status = 409 code = ''
[docs]class BucketNotEmpty(Conflict): status = 409 code = 'BucketNotEmpty'
[docs]class PositionNotEqualToLength(Conflict): status = 409 code = 'PositionNotEqualToLength' def __init__(self, status, headers, body, details): super(PositionNotEqualToLength, self).__init__(status, headers, body, details) self.next_position = int(headers['x-oss-next-append-position'])
[docs]class ObjectNotAppendable(Conflict): status = 409 code = 'ObjectNotAppendable'
[docs]class ChannelStillLive(Conflict): status = 409 code = 'ChannelStillLive'
[docs]class LiveChannelDisabled(Conflict): status = 409 code = 'LiveChannelDisabled'
[docs]class PreconditionFailed(ServerError): status = 412 code = 'PreconditionFailed'
[docs]class NotModified(ServerError): status = 304 code = ''
[docs]class AccessDenied(ServerError): status = 403 code = 'AccessDenied'
[docs]def make_exception(resp): status = resp.status headers = resp.headers body = resp.read(4096) details = _parse_error_body(body) code = details.get('Code', '') try: klass = _OSS_ERROR_TO_EXCEPTION[(status, code)] return klass(status, headers, body, details) except KeyError: return ServerError(status, headers, body, details)
def _walk_subclasses(klass): for sub in klass.__subclasses__(): yield sub for subsub in _walk_subclasses(sub): yield subsub for klass in _walk_subclasses(ServerError): status = getattr(klass, 'status', None) code = getattr(klass, 'code', None) if status is not None and code is not None: _OSS_ERROR_TO_EXCEPTION[(status, code)] = klass # XML parsing exceptions have changed in Python2.7 and ElementTree 1.3 if hasattr(ElementTree, 'ParseError'): ElementTreeParseError = (ElementTree.ParseError, expat.ExpatError) else: ElementTreeParseError = (expat.ExpatError) def _parse_error_body(body): try: root = ElementTree.fromstring(body) if root.tag != 'Error': return {} details = {} for child in root: details[child.tag] = child.text return details except ElementTreeParseError: return _guess_error_details(body) def _guess_error_details(body): details = {} body = to_string(body) if '<Error>' not in body or '</Error>' not in body: return details m = re.search('<Code>(.*)</Code>', body) if m: details['Code'] = m.group(1) m = re.search('<Message>(.*)</Message>', body) if m: details['Message'] = m.group(1) return details