2026-1-6
This commit is contained in:
393
venv/Lib/site-packages/oss2/exceptions.py
Normal file
393
venv/Lib/site-packages/oss2/exceptions.py
Normal file
@@ -0,0 +1,393 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
oss2.exceptions
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
异常类。
|
||||
"""
|
||||
|
||||
import re
|
||||
import base64
|
||||
import xml.etree.ElementTree as ElementTree
|
||||
from xml.parsers import expat
|
||||
|
||||
|
||||
from .compat import to_string
|
||||
from .headers import *
|
||||
|
||||
_OSS_ERROR_TO_EXCEPTION = {} # populated at end of module
|
||||
|
||||
|
||||
OSS_CLIENT_ERROR_STATUS = -1
|
||||
OSS_REQUEST_ERROR_STATUS = -2
|
||||
OSS_INCONSISTENT_ERROR_STATUS = -3
|
||||
OSS_FORMAT_ERROR_STATUS = -4
|
||||
OSS_SELECT_CLIENT_ERROR_STATUS = -5
|
||||
|
||||
|
||||
class OssError(Exception):
|
||||
def __init__(self, status, headers, body, details):
|
||||
#: HTTP 状态码
|
||||
self.status = status
|
||||
|
||||
#: 请求ID,用于跟踪一个OSS请求。提交工单时,最好能够提供请求ID
|
||||
self.request_id = headers.get(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', '')
|
||||
|
||||
#: OSS新的错误码
|
||||
self.ec = self.details.get('EC', '')
|
||||
|
||||
#: header信息
|
||||
self.headers = headers
|
||||
|
||||
def __str__(self):
|
||||
error = {'status': self.status,
|
||||
OSS_REQUEST_ID : self.request_id,
|
||||
'details': self.details}
|
||||
return str(error)
|
||||
|
||||
def _str_with_body(self):
|
||||
error = {'status': self.status,
|
||||
OSS_REQUEST_ID : self.request_id,
|
||||
'details': self.body}
|
||||
return str(error)
|
||||
|
||||
|
||||
class ClientError(OssError):
|
||||
def __init__(self, message):
|
||||
OssError.__init__(self, OSS_CLIENT_ERROR_STATUS, {}, 'ClientError: ' + message, {})
|
||||
|
||||
def __str__(self):
|
||||
return self._str_with_body()
|
||||
|
||||
|
||||
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()
|
||||
|
||||
|
||||
class InconsistentError(OssError):
|
||||
def __init__(self, message, request_id=''):
|
||||
OssError.__init__(self, OSS_INCONSISTENT_ERROR_STATUS, {OSS_REQUEST_ID : request_id}, 'InconsistentError: ' + message, {})
|
||||
|
||||
def __str__(self):
|
||||
return self._str_with_body()
|
||||
|
||||
|
||||
class OpenApiFormatError(OssError):
|
||||
def __init__(self, message):
|
||||
OssError.__init__(self, OSS_FORMAT_ERROR_STATUS, {}, message, {})
|
||||
|
||||
def __str__(self):
|
||||
return self._str_with_body()
|
||||
|
||||
|
||||
class OpenApiServerError(OssError):
|
||||
def __init__(self, status, request_id, message, error_code):
|
||||
OssError.__init__(self, status, {OSS_REQUEST_ID : request_id}, '', {'Code': error_code, 'Message': message})
|
||||
|
||||
|
||||
class ServerError(OssError):
|
||||
pass
|
||||
|
||||
|
||||
class NotFound(ServerError):
|
||||
status = 404
|
||||
code = ''
|
||||
|
||||
|
||||
class MalformedXml(ServerError):
|
||||
status = 400
|
||||
code = 'MalformedXML'
|
||||
|
||||
|
||||
class InvalidRequest(ServerError):
|
||||
status = 400
|
||||
code = 'InvalidRequest'
|
||||
|
||||
|
||||
class OperationNotSupported(ServerError):
|
||||
status = 400
|
||||
code = 'OperationNotSupported'
|
||||
|
||||
|
||||
class RestoreAlreadyInProgress(ServerError):
|
||||
status = 409
|
||||
code = 'RestoreAlreadyInProgress'
|
||||
|
||||
|
||||
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')
|
||||
|
||||
|
||||
class InvalidDigest(ServerError):
|
||||
status = 400
|
||||
code = 'InvalidDigest'
|
||||
|
||||
|
||||
class InvalidObjectName(ServerError):
|
||||
status = 400
|
||||
code = 'InvalidObjectName'
|
||||
|
||||
|
||||
class NotImplemented(ServerError):
|
||||
status = 400
|
||||
code = 'NotImplemented'
|
||||
|
||||
|
||||
class InvalidEncryptionRequest(ServerError):
|
||||
status = 400
|
||||
code = 'InvalidEncryptionRequest'
|
||||
|
||||
class BucketReplicationAlreadyExist(ServerError):
|
||||
status = 400
|
||||
code = 'BucketReplicationAlreadyExist'
|
||||
|
||||
class NoSuchBucket(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchBucket'
|
||||
|
||||
|
||||
class NoSuchKey(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchKey'
|
||||
|
||||
|
||||
class NoSuchUpload(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchUpload'
|
||||
|
||||
|
||||
class NoSuchWebsite(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchWebsiteConfiguration'
|
||||
|
||||
|
||||
class NoSuchLifecycle(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchLifecycle'
|
||||
|
||||
|
||||
class NoSuchCors(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchCORSConfiguration'
|
||||
|
||||
|
||||
class NoSuchLiveChannel(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchLiveChannel'
|
||||
|
||||
|
||||
class NoSuchBucketPolicy(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchBucketPolicy'
|
||||
|
||||
class NoSuchInventory(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchInventory'
|
||||
|
||||
class NoSuchReplicationRule(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchReplicationRule'
|
||||
|
||||
class Conflict(ServerError):
|
||||
status = 409
|
||||
code = ''
|
||||
|
||||
|
||||
class BucketNotEmpty(Conflict):
|
||||
status = 409
|
||||
code = 'BucketNotEmpty'
|
||||
|
||||
|
||||
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[OSS_NEXT_APPEND_POSITION])
|
||||
|
||||
|
||||
class ObjectNotAppendable(Conflict):
|
||||
status = 409
|
||||
code = 'ObjectNotAppendable'
|
||||
|
||||
|
||||
class ChannelStillLive(Conflict):
|
||||
status = 409
|
||||
code = 'ChannelStillLive'
|
||||
|
||||
|
||||
class LiveChannelDisabled(Conflict):
|
||||
status = 409
|
||||
code = 'LiveChannelDisabled'
|
||||
|
||||
|
||||
class PreconditionFailed(ServerError):
|
||||
status = 412
|
||||
code = 'PreconditionFailed'
|
||||
|
||||
|
||||
class NotModified(ServerError):
|
||||
status = 304
|
||||
code = ''
|
||||
|
||||
|
||||
class AccessDenied(ServerError):
|
||||
status = 403
|
||||
code = 'AccessDenied'
|
||||
|
||||
class NoSuchServerSideEncryptionRule(NotFound):
|
||||
status = 404
|
||||
code = 'NoSuchServerSideEncryptionRule'
|
||||
|
||||
class InvalidEncryptionAlgorithmError(ServerError):
|
||||
status = 400
|
||||
code = 'InvalidEncryptionAlgorithmError'
|
||||
|
||||
class SelectOperationFailed(ServerError):
|
||||
code = 'SelectOperationFailed'
|
||||
def __init__(self, status, code, message):
|
||||
self.status = status
|
||||
self.code = code
|
||||
self.message = message
|
||||
|
||||
def __str__(self):
|
||||
error = {'status': self.status,
|
||||
'code': self.code,
|
||||
'details': self.message}
|
||||
return str(error)
|
||||
|
||||
class SelectOperationClientError(OssError):
|
||||
def __init__(self, message, request_id):
|
||||
OssError.__init__(self, OSS_SELECT_CLIENT_ERROR_STATUS, {'x-oss-request-id': request_id}, 'SelectOperationClientError: ' + message, {})
|
||||
|
||||
def __str__(self):
|
||||
error = {'x-oss-request-id':self.request_id,
|
||||
'message': self.message}
|
||||
return str(error)
|
||||
|
||||
class SignatureDoesNotMatch(ServerError):
|
||||
status = 403
|
||||
code = 'SignatureDoesNotMatch'
|
||||
|
||||
class ObjectAlreadyExists(ServerError):
|
||||
status = 400
|
||||
code = 'ObjectAlreadyExists'
|
||||
|
||||
class PartNotSequential(ServerError):
|
||||
status = 400
|
||||
code = 'PartNotSequential'
|
||||
|
||||
class NoSuchWORMConfiguration(ServerError):
|
||||
status = 404
|
||||
code = 'NoSuchWORMConfiguration'
|
||||
|
||||
class WORMConfigurationLocked(ServerError):
|
||||
status = 403
|
||||
code = 'WORMConfigurationLocked'
|
||||
|
||||
class InvalidWORMConfiguration(ServerError):
|
||||
status = 400
|
||||
code = 'InvalidWORMConfiguration'
|
||||
|
||||
class NoSuchTransferAccelerationConfiguration(ServerError):
|
||||
status = 404
|
||||
code = 'NoSuchTransferAccelerationConfiguration'
|
||||
|
||||
def make_exception(resp):
|
||||
status = resp.status
|
||||
headers = resp.headers
|
||||
body = resp.read(4096)
|
||||
if not body and headers.get('x-oss-err') is not None:
|
||||
try:
|
||||
value = base64.b64decode(to_string(headers.get('x-oss-err')))
|
||||
except:
|
||||
value = body
|
||||
details = _parse_error_body(value)
|
||||
else:
|
||||
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
|
||||
Reference in New Issue
Block a user