From 350fb94fc2525280c4849f8e7b068590ba73ed80 Mon Sep 17 00:00:00 2001 From: "obs.manager" Date: Wed, 27 May 2020 11:20:07 +0800 Subject: [PATCH] upload 3.20.1 --- .../huaweicloud-obs-sdk-python_3.20.1.tar.gz | Bin 0 -> 103045 bytes ...icloud-obs-sdk-python_3.20.1.tar.gz.sha256 | 1 + src/obs/__init__.py | 4 +- src/obs/auth.py | 2 +- src/obs/bucket.py | 5 +- src/obs/bulktasks.py | 424 +++++++++--------- src/obs/cache.py | 84 ++-- src/obs/client.py | 348 +++++++------- src/obs/const.py | 2 +- src/obs/convertor.py | 21 +- src/obs/extension.py | 236 +++++----- src/obs/model.py | 22 +- src/obs/transfer.py | 36 +- src/setup.py | 2 +- 14 files changed, 627 insertions(+), 560 deletions(-) create mode 100644 release/huaweicloud-obs-sdk-python_3.20.1.tar.gz create mode 100644 release/huaweicloud-obs-sdk-python_3.20.1.tar.gz.sha256 diff --git a/release/huaweicloud-obs-sdk-python_3.20.1.tar.gz b/release/huaweicloud-obs-sdk-python_3.20.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..1f085898983e144dcc8ea9206b72cda71539c9e9 GIT binary patch literal 103045 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

dM5CcHc15i$cQt9J~fmmk)pSkLLYmu=BHoP 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 value['expire']: - value = None - return value - - def set(self, key, value): - self.weak[key] = strongRef = self.Dict(value) - self.strong.append(strongRef) - - +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Copyright 2019 Huawei Technologies Co.,Ltd. +# 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. + +import weakref, collections +import time + + +class _LocalCacheThread(object): + class Dict(dict): + def __del__(self): + pass + + def __init__(self, maxlen=10): + self.weak = weakref.WeakValueDictionary() + self.strong = collections.deque(maxlen=maxlen) + + @staticmethod + def nowTime(): + return int(time.time()) + + def get(self, key): + value = self.weak.get(key) + if value is not None and hasattr(value, 'expire') and self.nowTime() > value['expire']: + value = None + return value + + def set(self, key, value): + self.weak[key] = strongRef = self.Dict(value) + self.strong.append(strongRef) + + LocalCache = _LocalCacheThread \ No newline at end of file diff --git a/src/obs/client.py b/src/obs/client.py index 88483f7..d51b88c 100644 --- a/src/obs/client.py +++ b/src/obs/client.py @@ -58,7 +58,7 @@ def __init__(self, msg, location, result=None): self.msg = msg self.location = location self.result = result - + def __str__(self): return self.msg @@ -349,23 +349,23 @@ def _generate_object_url(self, ret, bucketName, objectKey): if ret and ret.status < 300 and ret.body: ret.body.objectUrl = self.calling_format.get_full_url(self.is_secure, self.server, self.port, bucketName, objectKey, {}) - def _make_options_request(self, bucketName, objectKey=None, pathArgs=None, headers=None, methodName=None): - return self._make_request_with_retry(const.HTTP_METHOD_OPTIONS, bucketName, objectKey, pathArgs, headers, methodName=methodName) + def _make_options_request(self, bucketName, objectKey=None, pathArgs=None, headers=None, methodName=None, extensionHeaders=None): + return self._make_request_with_retry(const.HTTP_METHOD_OPTIONS, bucketName, objectKey, pathArgs, headers, methodName=methodName, extensionHeaders=extensionHeaders) - def _make_head_request(self, bucketName, objectKey=None, pathArgs=None, headers=None, methodName=None, skipAuthentication=False): - return self._make_request_with_retry(const.HTTP_METHOD_HEAD, bucketName, objectKey, pathArgs, headers, methodName=methodName, skipAuthentication=skipAuthentication) + def _make_head_request(self, bucketName, objectKey=None, pathArgs=None, headers=None, methodName=None, skipAuthentication=False, extensionHeaders=None): + return self._make_request_with_retry(const.HTTP_METHOD_HEAD, bucketName, objectKey, pathArgs, headers, methodName=methodName, skipAuthentication=skipAuthentication, extensionHeaders=extensionHeaders) - def _make_get_request(self, bucketName='', objectKey=None, pathArgs=None, headers=None, methodName=None, parseMethod=None, readable=False): - return self._make_request_with_retry(const.HTTP_METHOD_GET, bucketName, objectKey, pathArgs, headers, methodName=methodName, parseMethod=parseMethod, readable=readable) + def _make_get_request(self, bucketName='', objectKey=None, pathArgs=None, headers=None, methodName=None, parseMethod=None, readable=False, extensionHeaders=None): + return self._make_request_with_retry(const.HTTP_METHOD_GET, bucketName, objectKey, pathArgs, headers, methodName=methodName, parseMethod=parseMethod, readable=readable, extensionHeaders=extensionHeaders) - def _make_delete_request(self, bucketName, objectKey=None, pathArgs=None, headers=None, entity=None, methodName=None): - return self._make_request_with_retry(const.HTTP_METHOD_DELETE, bucketName, objectKey, pathArgs, headers, entity, methodName=methodName) + def _make_delete_request(self, bucketName, objectKey=None, pathArgs=None, headers=None, entity=None, methodName=None, extensionHeaders=None): + return self._make_request_with_retry(const.HTTP_METHOD_DELETE, bucketName, objectKey, pathArgs, headers, entity, methodName=methodName, extensionHeaders=extensionHeaders) - def _make_post_request(self, bucketName, objectKey=None, pathArgs=None, headers=None, entity=None, chunkedMode=False, methodName=None, readable=False): - return self._make_request_with_retry(const.HTTP_METHOD_POST, bucketName, objectKey, pathArgs, headers, entity, chunkedMode, methodName=methodName, readable=readable) + def _make_post_request(self, bucketName, objectKey=None, pathArgs=None, headers=None, entity=None, chunkedMode=False, methodName=None, readable=False, extensionHeaders=None): + return self._make_request_with_retry(const.HTTP_METHOD_POST, bucketName, objectKey, pathArgs, headers, entity, chunkedMode, methodName=methodName, readable=readable, extensionHeaders=extensionHeaders) - def _make_put_request(self, bucketName, objectKey=None, pathArgs=None, headers=None, entity=None, chunkedMode=False, methodName=None, readable=False): - return self._make_request_with_retry(const.HTTP_METHOD_PUT, bucketName, objectKey, pathArgs, headers, entity, chunkedMode, methodName=methodName, readable=readable) + def _make_put_request(self, bucketName, objectKey=None, pathArgs=None, headers=None, entity=None, chunkedMode=False, methodName=None, readable=False, extensionHeaders=None): + return self._make_request_with_retry(const.HTTP_METHOD_PUT, bucketName, objectKey, pathArgs, headers, entity, chunkedMode, methodName=methodName, readable=readable, extensionHeaders=extensionHeaders) def _make_error_result(self, e, ret): self.log_client.log(ERROR, 'request error, %s' % e) @@ -375,7 +375,7 @@ def _make_error_result(self, e, ret): raise e def _make_request_with_retry(self, methodType, bucketName, objectKey=None, pathArgs=None, headers=None, - entity=None, chunkedMode=False, methodName=None, readable=False, parseMethod=None, redirectLocation=None, skipAuthentication=False): + entity=None, chunkedMode=False, methodName=None, readable=False, parseMethod=None, redirectLocation=None, skipAuthentication=False, extensionHeaders=None): flag = 0 redirect_count = 0 conn = None @@ -383,7 +383,7 @@ def _make_request_with_retry(self, methodType, bucketName, objectKey=None, pathA redirectFlag = False while True: try: - conn = self._make_request_internal(methodType, bucketName, objectKey, pathArgs, headers, entity, chunkedMode, _redirectLocation, skipAuthentication=skipAuthentication, redirectFlag=redirectFlag) + conn = self._make_request_internal(methodType, bucketName, objectKey, pathArgs, headers, entity, chunkedMode, _redirectLocation, skipAuthentication=skipAuthentication, redirectFlag=redirectFlag, extensionHeaders=extensionHeaders) return self._parse_xml(conn, methodName, readable) if not parseMethod else parseMethod(conn) except Exception as e: ret = None @@ -399,8 +399,6 @@ def _make_request_with_retry(self, methodType, bucketName, objectKey=None, pathA ret = e.result if methodType == const.HTTP_METHOD_GET and e.result.status == 302: redirectFlag = True - else: - redirectFlag = False if redirect_count >= self.max_redirect_count: self.log_client.log(ERROR, 'request redirect count [%d] greater than max redirect count [%d]' % ( redirect_count, self.max_redirect_count)) @@ -414,7 +412,7 @@ def _make_request_with_retry(self, methodType, bucketName, objectKey=None, pathA break def _make_request_internal(self, method, bucketName='', objectKey=None, pathArgs=None, headers=None, entity=None, - chunkedMode=False, redirectLocation=None, skipAuthentication=False, redirectFlag=False): + chunkedMode=False, redirectLocation=None, skipAuthentication=False, redirectFlag=False, extensionHeaders=None): objectKey = util.safe_encode(objectKey) if objectKey is None: objectKey = '' @@ -431,7 +429,7 @@ def _make_request_internal(self, method, bucketName='', objectKey=None, pathArgs query = redirectLocation.query path = _path + '?' + query if query else _path skipAuthentication = True - if not redirectFlag and not path: + if not redirectFlag: skipAuthentication = False else: @@ -445,6 +443,15 @@ def _make_request_internal(self, method, bucketName='', objectKey=None, pathArgs if not path: path = self.calling_format.get_url(bucketName, objectKey, pathArgs) + extension_headers = self.convertor.trans_get_extension_headers(extensionHeaders) + if len(extension_headers) > 0: + if headers is None or not isinstance(headers, dict): + headers = {} + else: + headers = headers.copy() + for key, value in extension_headers.items(): + headers[key] = value + headers = self._rename_request_headers(headers, method) if entity is not None and not callable(entity): @@ -1109,178 +1116,185 @@ def _getApiVersion(self, bucketName=''): return const.V2_SIGNATURE, res @funcCache - def listBuckets(self, isQueryLocation=True): + def listBuckets(self, isQueryLocation=True, extensionHeaders=None): if self.is_cname: raise Exception('listBuckets is not allowed in customdomain mode') - return self._make_get_request(methodName='listBuckets', **self.convertor.trans_list_buckets(isQueryLocation=isQueryLocation)) + return self._make_get_request(methodName='listBuckets', extensionHeaders=extensionHeaders, **self.convertor.trans_list_buckets(isQueryLocation=isQueryLocation)) @funcCache - def createBucket(self, bucketName, header=CreateBucketHeader(), location=None): + def createBucket(self, bucketName, header=CreateBucketHeader(), location=None, extensionHeaders=None): if self.is_cname: raise Exception('createBucket is not allowed in customdomain mode') - res = self._make_put_request(bucketName, **self.convertor.trans_create_bucket(header=header, location=location)) + res = self._make_put_request(bucketName, extensionHeaders=extensionHeaders, **self.convertor.trans_create_bucket(header=header, location=location)) try: if self.is_signature_negotiation and res.status == 400 and res.errorMessage == 'Unsupported Authorization Type' and self.thread_local.signature == const.OBS_SIGNATURE: self.thread_local.signature = const.V2_SIGNATURE - res = self._make_put_request(bucketName, **self.convertor.trans_create_bucket(header=header, location=location)) + res = self._make_put_request(bucketName, extensionHeaders=extensionHeaders, **self.convertor.trans_create_bucket(header=header, location=location)) finally: return res @funcCache - def listObjects(self, bucketName, prefix=None, marker=None, max_keys=None, delimiter=None): - return self._make_get_request(bucketName, methodName='listObjects', + def listObjects(self, bucketName, prefix=None, marker=None, max_keys=None, delimiter=None, extensionHeaders=None): + return self._make_get_request(bucketName, methodName='listObjects', extensionHeaders=extensionHeaders, **self.convertor.trans_list_objects(prefix=prefix, marker=marker, max_keys=max_keys, delimiter=delimiter)) @funcCache - def headBucket(self, bucketName): - return self._make_head_request(bucketName) + def headBucket(self, bucketName, extensionHeaders=None): + return self._make_head_request(bucketName, extensionHeaders=extensionHeaders) @funcCache - def getBucketMetadata(self, bucketName, origin=None, requestHeaders=None): - return self._make_head_request(bucketName, methodName='getBucketMetadata', **self.convertor.trans_get_bucket_metadata(origin=origin, requestHeaders=requestHeaders)) + def headObject(self, bucketName, objectKey, versionId=None, extensionHeaders=None): + pathArgs = {} + if versionId: + pathArgs[const.VERSION_ID_PARAM] = util.to_string(versionId) + return self._make_head_request(bucketName, objectKey, pathArgs=pathArgs, extensionHeaders=extensionHeaders) @funcCache - def getBucketLocation(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'location':None}, methodName='getBucketLocation') + def getBucketMetadata(self, bucketName, origin=None, requestHeaders=None, extensionHeaders=None): + return self._make_head_request(bucketName, methodName='getBucketMetadata', extensionHeaders=extensionHeaders, **self.convertor.trans_get_bucket_metadata(origin=origin, requestHeaders=requestHeaders)) @funcCache - def deleteBucket(self, bucketName): - return self._make_delete_request(bucketName) + def getBucketLocation(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'location':None}, methodName='getBucketLocation', extensionHeaders=extensionHeaders) @funcCache - def setBucketQuota(self, bucketName, quota): + def deleteBucket(self, bucketName, extensionHeaders=None): + return self._make_delete_request(bucketName, extensionHeaders=extensionHeaders) + + @funcCache + def setBucketQuota(self, bucketName, quota, extensionHeaders=None): self._assert_not_null(quota, 'quota is empty') - return self._make_put_request(bucketName, pathArgs={'quota': None}, entity=self.convertor.trans_quota(quota)) + return self._make_put_request(bucketName, pathArgs={'quota': None}, entity=self.convertor.trans_quota(quota), extensionHeaders=extensionHeaders) @funcCache - def getBucketQuota(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'quota': None}, methodName='getBucketQuota') + def getBucketQuota(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'quota': None}, methodName='getBucketQuota', extensionHeaders=extensionHeaders) @funcCache - def getBucketStorageInfo(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'storageinfo': None}, methodName='getBucketStorageInfo') + def getBucketStorageInfo(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'storageinfo': None}, methodName='getBucketStorageInfo', extensionHeaders=extensionHeaders) @funcCache - def setBucketAcl(self, bucketName, acl=ACL(), aclControl=None): + def setBucketAcl(self, bucketName, acl=ACL(), aclControl=None, extensionHeaders=None): if acl is not None and len(acl) > 0 and aclControl is not None: raise Exception('Both acl and aclControl are set') if not acl and not aclControl: raise Exception('Both acl and aclControl are not set') - return self._make_put_request(bucketName, **self.convertor.trans_set_bucket_acl(acl=acl, aclControl=aclControl)) + return self._make_put_request(bucketName, extensionHeaders=extensionHeaders, **self.convertor.trans_set_bucket_acl(acl=acl, aclControl=aclControl)) @funcCache - def getBucketAcl(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'acl': None}, methodName='getBucketAcl') + def getBucketAcl(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'acl': None}, methodName='getBucketAcl', extensionHeaders=extensionHeaders) @funcCache - def setBucketPolicy(self, bucketName, policyJSON): + def setBucketPolicy(self, bucketName, policyJSON, extensionHeaders=None): self._assert_not_null(policyJSON, 'policyJSON is empty') - return self._make_put_request(bucketName, pathArgs={'policy' : None}, entity=policyJSON) + return self._make_put_request(bucketName, pathArgs={'policy' : None}, entity=policyJSON, extensionHeaders=extensionHeaders) @funcCache - def getBucketPolicy(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'policy' : None}, methodName='getBucketPolicy') + def getBucketPolicy(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'policy' : None}, methodName='getBucketPolicy', extensionHeaders=extensionHeaders) @funcCache - def deleteBucketPolicy(self, bucketName): - return self._make_delete_request(bucketName, pathArgs={'policy' : None}) + def deleteBucketPolicy(self, bucketName, extensionHeaders=None): + return self._make_delete_request(bucketName, pathArgs={'policy' : None}, extensionHeaders=extensionHeaders) @funcCache - def setBucketVersioning(self, bucketName, status): + def setBucketVersioning(self, bucketName, status, extensionHeaders=None): self._assert_not_null(status, 'status is empty') - return self._make_put_request(bucketName, pathArgs={'versioning' : None}, entity=self.convertor.trans_version_status(status)) + return self._make_put_request(bucketName, pathArgs={'versioning' : None}, entity=self.convertor.trans_version_status(status), extensionHeaders=extensionHeaders) @funcCache - def getBucketVersioning(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'versioning' : None}, methodName='getBucketVersioning') + def getBucketVersioning(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'versioning' : None}, methodName='getBucketVersioning', extensionHeaders=extensionHeaders) @funcCache - def listVersions(self, bucketName, version=Versions()): - return self._make_get_request(bucketName, methodName='listVersions', **self.convertor.trans_list_versions(version=version)) + def listVersions(self, bucketName, version=Versions(), extensionHeaders=None): + return self._make_get_request(bucketName, methodName='listVersions', extensionHeaders=extensionHeaders, **self.convertor.trans_list_versions(version=version)) @funcCache - def listMultipartUploads(self, bucketName, multipart=ListMultipartUploadsRequest()): - return self._make_get_request(bucketName, methodName='listMultipartUploads', **self.convertor.trans_list_multipart_uploads(multipart=multipart)) + def listMultipartUploads(self, bucketName, multipart=ListMultipartUploadsRequest(), extensionHeaders=None): + return self._make_get_request(bucketName, methodName='listMultipartUploads', extensionHeaders=extensionHeaders, **self.convertor.trans_list_multipart_uploads(multipart=multipart)) @funcCache - def deleteBucketLifecycle(self, bucketName): - return self._make_delete_request(bucketName, pathArgs={'lifecycle':None}) + def deleteBucketLifecycle(self, bucketName, extensionHeaders=None): + return self._make_delete_request(bucketName, pathArgs={'lifecycle':None}, extensionHeaders=extensionHeaders) @funcCache - def setBucketLifecycle(self, bucketName, lifecycle): + def setBucketLifecycle(self, bucketName, lifecycle, extensionHeaders=None): self._assert_not_null(lifecycle, 'lifecycle is empty') - return self._make_put_request(bucketName, **self.convertor.trans_set_bucket_lifecycle(lifecycle=lifecycle)) + return self._make_put_request(bucketName, extensionHeaders=extensionHeaders, **self.convertor.trans_set_bucket_lifecycle(lifecycle=lifecycle)) @funcCache - def getBucketLifecycle(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'lifecycle':None}, methodName='getBucketLifecycle') + def getBucketLifecycle(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'lifecycle':None}, methodName='getBucketLifecycle', extensionHeaders=extensionHeaders) @funcCache - def deleteBucketWebsite(self, bucketName): - return self._make_delete_request(bucketName, pathArgs={'website':None}) + def deleteBucketWebsite(self, bucketName, extensionHeaders=None): + return self._make_delete_request(bucketName, pathArgs={'website':None}, extensionHeaders=extensionHeaders) @funcCache - def setBucketWebsite(self, bucketName, website): + def setBucketWebsite(self, bucketName, website, extensionHeaders=None): self._assert_not_null(website, 'website is empty') - return self._make_put_request(bucketName, pathArgs={'website':None}, entity=self.convertor.trans_website(website)) + return self._make_put_request(bucketName, pathArgs={'website':None}, entity=self.convertor.trans_website(website), extensionHeaders=extensionHeaders) @funcCache - def getBucketWebsite(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'website':None}, methodName='getBucketWebsite') + def getBucketWebsite(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'website':None}, methodName='getBucketWebsite', extensionHeaders=extensionHeaders) @funcCache - def setBucketLogging(self, bucketName, logstatus=Logging()): + def setBucketLogging(self, bucketName, logstatus=Logging(), extensionHeaders=None): if logstatus is None: logstatus = Logging() - return self._make_put_request(bucketName, pathArgs={'logging':None}, entity=self.convertor.trans_logging(logstatus)) + return self._make_put_request(bucketName, pathArgs={'logging':None}, entity=self.convertor.trans_logging(logstatus), extensionHeaders=extensionHeaders) @funcCache - def getBucketLogging(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'logging':None}, methodName='getBucketLogging') + def getBucketLogging(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'logging':None}, methodName='getBucketLogging', extensionHeaders=extensionHeaders) @funcCache - def getBucketTagging(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'tagging' : None}, methodName='getBucketTagging') + def getBucketTagging(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'tagging' : None}, methodName='getBucketTagging', extensionHeaders=extensionHeaders) @funcCache - def setBucketTagging(self, bucketName, tagInfo): + def setBucketTagging(self, bucketName, tagInfo, extensionHeaders=None): self._assert_not_null(tagInfo, 'tagInfo is empty') - return self._make_put_request(bucketName, **self.convertor.trans_set_bucket_tagging(tagInfo=tagInfo)) + return self._make_put_request(bucketName, extensionHeaders=extensionHeaders, **self.convertor.trans_set_bucket_tagging(tagInfo=tagInfo)) @funcCache - def deleteBucketTagging(self, bucketName): - return self._make_delete_request(bucketName, pathArgs={'tagging' : None}) + def deleteBucketTagging(self, bucketName, extensionHeaders=None): + return self._make_delete_request(bucketName, pathArgs={'tagging' : None}, extensionHeaders=extensionHeaders) @funcCache - def setBucketCors(self, bucketName, corsRuleList): + def setBucketCors(self, bucketName, corsRuleList, extensionHeaders=None): self._assert_not_null(corsRuleList, 'corsRuleList is empty') - return self._make_put_request(bucketName, **self.convertor.trans_set_bucket_cors(corsRuleList=corsRuleList)) + return self._make_put_request(bucketName, extensionHeaders=extensionHeaders, **self.convertor.trans_set_bucket_cors(corsRuleList=corsRuleList)) @funcCache - def deleteBucketCors(self, bucketName): - return self._make_delete_request(bucketName, pathArgs={'cors' : None}) + def deleteBucketCors(self, bucketName, extensionHeaders=None): + return self._make_delete_request(bucketName, pathArgs={'cors' : None}, extensionHeaders=extensionHeaders) @funcCache - def getBucketCors(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'cors': None}, methodName='getBucketCors') + def getBucketCors(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'cors': None}, methodName='getBucketCors', extensionHeaders=extensionHeaders) @funcCache - def optionsBucket(self, bucketName, option): - return self.optionsObject(bucketName, None, option=option) + def optionsBucket(self, bucketName, option, extensionHeaders=None): + return self.optionsObject(bucketName, None, option=option, extensionHeaders=extensionHeaders) @funcCache - def setBucketNotification(self, bucketName, notification=Notification()): + def setBucketNotification(self, bucketName, notification=Notification(), extensionHeaders=None): if notification is None: notification = Notification() - return self._make_put_request(bucketName, pathArgs={'notification': None}, entity=self.convertor.trans_notification(notification)) + return self._make_put_request(bucketName, pathArgs={'notification': None}, entity=self.convertor.trans_notification(notification), extensionHeaders=extensionHeaders) @funcCache - def getBucketNotification(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'notification': None}, methodName='getBucketNotification') + def getBucketNotification(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'notification': None}, methodName='getBucketNotification', extensionHeaders=extensionHeaders) @funcCache - def optionsObject(self, bucketName, objectKey, option): + def optionsObject(self, bucketName, objectKey, option, extensionHeaders=None): headers = {} if option is not None: if option.get('origin') is not None: @@ -1289,10 +1303,10 @@ def optionsObject(self, bucketName, objectKey, option): headers[const.ACCESS_CONTROL_REQUEST_METHOD_HEADER] = option['accessControlRequestMethods'] if option.get('accessControlRequestHeaders') is not None: headers[const.ACCESS_CONTROL_REQUEST_HEADERS_HEADER] = option['accessControlRequestHeaders'] - return self._make_options_request(bucketName, objectKey, headers=headers, methodName='optionsBucket') + return self._make_options_request(bucketName, objectKey, headers=headers, methodName='optionsBucket', extensionHeaders=extensionHeaders) @funcCache - def getObjectMetadata(self, bucketName, objectKey, versionId=None, sseHeader=None, origin=None, requestHeaders=None): + def getObjectMetadata(self, bucketName, objectKey, versionId=None, sseHeader=None, origin=None, requestHeaders=None, extensionHeaders=None): pathArgs = {} if versionId: pathArgs[const.VERSION_ID_PARAM] = util.to_string(versionId) @@ -1303,39 +1317,39 @@ def getObjectMetadata(self, bucketName, objectKey, versionId=None, sseHeader=Non if _requestHeaders: headers[const.ACCESS_CONTROL_REQUEST_HEADERS_HEADER] = util.to_string(_requestHeaders) return self._make_head_request(bucketName, objectKey, pathArgs=pathArgs, - headers=self.convertor._set_sse_header(sseHeader, headers=headers, onlySseCHeader=True), methodName='getObjectMetadata') + headers=self.convertor._set_sse_header(sseHeader, headers=headers, onlySseCHeader=True), methodName='getObjectMetadata', extensionHeaders=extensionHeaders) @funcCache - def setObjectMetadata(self, bucketName, objectKey, metadata=None, headers=None, versionId=None): + def setObjectMetadata(self, bucketName, objectKey, metadata=None, headers=None, versionId=None, extensionHeaders=None): if headers is None: headers = SetObjectMetadataHeader() - return self._make_put_request(bucketName, objectKey, methodName='setObjectMetadata', **self.convertor.trans_set_object_metadata(metadata=metadata, headers=headers, versionId=versionId)) + return self._make_put_request(bucketName, objectKey, methodName='setObjectMetadata', extensionHeaders=extensionHeaders, **self.convertor.trans_set_object_metadata(metadata=metadata, headers=headers, versionId=versionId)) @funcCache def getObject(self, bucketName, objectKey, downloadPath=None, getObjectRequest=GetObjectRequest(), - headers=GetObjectHeader(), loadStreamInMemory=False, progressCallback=None): + headers=GetObjectHeader(), loadStreamInMemory=False, progressCallback=None, extensionHeaders=None): _parse_content = self._parse_content CHUNKSIZE = self.chunk_size readable = False if progressCallback is None else True def parseMethod(conn): return _parse_content(conn, objectKey, downloadPath, CHUNKSIZE, loadStreamInMemory, progressCallback) - return self._make_get_request(bucketName, objectKey, parseMethod=parseMethod, readable=readable, **self.convertor.trans_get_object(getObjectRequest=getObjectRequest, headers=headers)) + return self._make_get_request(bucketName, objectKey, parseMethod=parseMethod, readable=readable, extensionHeaders=extensionHeaders, **self.convertor.trans_get_object(getObjectRequest=getObjectRequest, headers=headers)) @funcCache def _getObjectWithNotifier(self, bucketName, objectKey, getObjectRequest=GetObjectRequest(), - headers=GetObjectHeader(), downloadPath=None, notifier=None): + headers=GetObjectHeader(), downloadPath=None, notifier=None, extensionHeaders=None): _parse_content_with_notifier = self._parse_content_with_notifier CHUNKSIZE = self.chunk_size readable = False if notifier is None else True def parseMethod(conn): return _parse_content_with_notifier(conn, objectKey, CHUNKSIZE, downloadPath, notifier) - return self._make_get_request(bucketName, objectKey, parseMethod=parseMethod, readable=readable, **self.convertor.trans_get_object(getObjectRequest=getObjectRequest, headers=headers)) + return self._make_get_request(bucketName, objectKey, parseMethod=parseMethod, readable=readable, extensionHeaders=extensionHeaders, **self.convertor.trans_get_object(getObjectRequest=getObjectRequest, headers=headers)) @funcCache - def appendObject(self, bucketName, objectKey, content=None, metadata=None, headers=None, progressCallback=None, autoClose=True): + def appendObject(self, bucketName, objectKey, content=None, metadata=None, headers=None, progressCallback=None, autoClose=True, extensionHeaders=None): objectKey = util.safe_encode(objectKey) if objectKey is None: objectKey = '' @@ -1406,7 +1420,7 @@ def appendObject(self, bucketName, objectKey, content=None, metadata=None, heade if notifier is not None: notifier.start() ret = self._make_post_request(bucketName, objectKey, pathArgs={'append': None, 'position': util.to_string(content['position']) if content.get('position') is not None else 0}, - headers=headers, entity=entity, chunkedMode=chunkedMode, methodName='appendObject', readable=readable) + headers=headers, entity=entity, chunkedMode=chunkedMode, methodName='appendObject', readable=readable, extensionHeaders=extensionHeaders) finally: if notifier is not None: notifier.end() @@ -1414,7 +1428,7 @@ def appendObject(self, bucketName, objectKey, content=None, metadata=None, heade return ret @funcCache - def putContent(self, bucketName, objectKey, content=None, metadata=None, headers=None, progressCallback=None, autoClose=True): + def putContent(self, bucketName, objectKey, content=None, metadata=None, headers=None, progressCallback=None, autoClose=True, extensionHeaders=None): objectKey = util.safe_encode(objectKey) if objectKey is None: objectKey = '' @@ -1444,18 +1458,18 @@ def putContent(self, bucketName, objectKey, content=None, metadata=None, headers entity = util.get_readable_entity_by_totalcount(entity, totalCount, self.chunk_size, notifier, autoClose) notifier.start() - ret = self._make_put_request(bucketName, objectKey, headers=_headers, entity=entity, chunkedMode=chunkedMode, methodName='putContent', readable=readable) + ret = self._make_put_request(bucketName, objectKey, headers=_headers, entity=entity, chunkedMode=chunkedMode, methodName='putContent', readable=readable, extensionHeaders=extensionHeaders) finally: if notifier is not None: notifier.end() self._generate_object_url(ret, bucketName, objectKey) return ret - def putObject(self, bucketName, objectKey, content, metadata=None, headers=None, progressCallback=None, autoClose=True): - return self.putContent(bucketName, objectKey, content, metadata, headers, progressCallback, autoClose) + def putObject(self, bucketName, objectKey, content, metadata=None, headers=None, progressCallback=None, autoClose=True, extensionHeaders=None): + return self.putContent(bucketName, objectKey, content, metadata, headers, progressCallback, autoClose, extensionHeaders=extensionHeaders) @funcCache - def putFile(self, bucketName, objectKey, file_path, metadata=None, headers=None, progressCallback=None): + def putFile(self, bucketName, objectKey, file_path, metadata=None, headers=None, progressCallback=None, extensionHeaders=None): file_path = util.safe_encode(file_path) if not os.path.exists(file_path): file_path = util.safe_trans_to_gb2312(file_path) @@ -1480,7 +1494,7 @@ def putFile(self, bucketName, objectKey, file_path, metadata=None, headers=None, key = util.safe_trans_to_gb2312('{0}/'.format(os.path.split(file_path)[1]) + f) else: key = '{0}/'.format(objectKey) + util.safe_trans_to_gb2312(f) - result = self.putFile(bucketName, key, __file_path, metadata, headers) + result = self.putFile(bucketName, key, __file_path, metadata, headers, extensionHeaders=extensionHeaders) results.append((key, result)) return results @@ -1514,15 +1528,15 @@ def putFile(self, bucketName, objectKey, file_path, metadata=None, headers=None, entity = util.get_file_entity_by_totalcount(file_path, totalCount, self.chunk_size, notifier) try: notifier.start() - ret = self._make_put_request(bucketName, objectKey, headers=_headers, entity=entity, methodName='putContent', readable=readable) + ret = self._make_put_request(bucketName, objectKey, headers=_headers, entity=entity, methodName='putContent', readable=readable, extensionHeaders=extensionHeaders) finally: notifier.end() self._generate_object_url(ret, bucketName, objectKey) return ret - + @funcCache def uploadPart(self, bucketName, objectKey, partNumber, uploadId, object=None, isFile=False, partSize=None, - offset=0, sseHeader=None, isAttachMd5=False, md5=None, content=None, progressCallback=None, autoClose=True): + offset=0, sseHeader=None, isAttachMd5=False, md5=None, content=None, progressCallback=None, autoClose=True, extensionHeaders=None): self._assert_not_null(partNumber, 'partNumber is empty') self._assert_not_null(uploadId, 'uploadId is empty') @@ -1592,7 +1606,7 @@ def uploadPart(self, bucketName, objectKey, partNumber, uploadId, object=None, i if notifier is not None: notifier.start() ret = self._make_put_request(bucketName, objectKey, pathArgs={'partNumber': partNumber, 'uploadId': uploadId}, - headers=headers, entity=entity, chunkedMode=chunkedMode, methodName='uploadPart', readable=readable) + headers=headers, entity=entity, chunkedMode=chunkedMode, methodName='uploadPart', readable=readable, extensionHeaders=extensionHeaders) finally: if notifier is not None: notifier.end() @@ -1600,7 +1614,7 @@ def uploadPart(self, bucketName, objectKey, partNumber, uploadId, object=None, i @funcCache def _uploadPartWithNotifier(self, bucketName, objectKey, partNumber, uploadId, content=None, isFile=False, partSize=None, - offset=0, sseHeader=None, isAttachMd5=False, md5=None, notifier=None): + offset=0, sseHeader=None, isAttachMd5=False, md5=None, notifier=None, extensionHeaders=None): self._assert_not_null(partNumber, 'partNumber is empty') self._assert_not_null(uploadId, 'uploadId is empty') @@ -1656,11 +1670,11 @@ def _uploadPartWithNotifier(self, bucketName, objectKey, partNumber, uploadId, c self.convertor._set_sse_header(sseHeader, headers, True) ret = self._make_put_request(bucketName, objectKey, pathArgs={'partNumber': partNumber, 'uploadId': uploadId}, - headers=headers, entity=entity, chunkedMode=chunkedMode, methodName='uploadPart', readable=readable) + headers=headers, entity=entity, chunkedMode=chunkedMode, methodName='uploadPart', readable=readable, extensionHeaders=extensionHeaders) return ret @funcCache - def copyObject(self, sourceBucketName, sourceObjectKey, destBucketName, destObjectKey, metadata=None, headers=None, versionId=None): + def copyObject(self, sourceBucketName, sourceObjectKey, destBucketName, destObjectKey, metadata=None, headers=None, versionId=None, extensionHeaders=None): self._assert_not_null(sourceBucketName, 'sourceBucketName is empty') sourceObjectKey = util.safe_encode(sourceObjectKey) if sourceObjectKey is None: @@ -1673,46 +1687,46 @@ def copyObject(self, sourceBucketName, sourceObjectKey, destBucketName, destObje headers = CopyObjectHeader() return self._make_put_request(destBucketName, destObjectKey, - methodName='copyObject', **self.convertor.trans_copy_object(metadata=metadata, headers=headers, versionId=versionId, + methodName='copyObject', extensionHeaders=extensionHeaders, **self.convertor.trans_copy_object(metadata=metadata, headers=headers, versionId=versionId, sourceBucketName=sourceBucketName, sourceObjectKey=sourceObjectKey)) @funcCache - def setObjectAcl(self, bucketName, objectKey, acl=ACL(), versionId=None, aclControl=None): + def setObjectAcl(self, bucketName, objectKey, acl=ACL(), versionId=None, aclControl=None, extensionHeaders=None): if acl is not None and len(acl) > 0 and aclControl is not None: raise Exception('Both acl and aclControl are set') if not acl and not aclControl: raise Exception('Both acl and aclControl are not set') - return self._make_put_request(bucketName, objectKey, **self.convertor.trans_set_object_acl(acl=acl, versionId=versionId, aclControl=aclControl)) + return self._make_put_request(bucketName, objectKey, extensionHeaders=extensionHeaders, **self.convertor.trans_set_object_acl(acl=acl, versionId=versionId, aclControl=aclControl)) @funcCache - def getObjectAcl(self, bucketName, objectKey, versionId=None): + def getObjectAcl(self, bucketName, objectKey, versionId=None, extensionHeaders=None): pathArgs = {'acl': None} if versionId: pathArgs[const.VERSION_ID_PARAM] = util.to_string(versionId) - return self._make_get_request(bucketName, objectKey, pathArgs=pathArgs, methodName='getObjectAcl') + return self._make_get_request(bucketName, objectKey, pathArgs=pathArgs, methodName='getObjectAcl', extensionHeaders=extensionHeaders) @funcCache - def deleteObject(self, bucketName, objectKey, versionId=None): + def deleteObject(self, bucketName, objectKey, versionId=None, extensionHeaders=None): path_args = {} if versionId: path_args[const.VERSION_ID_PARAM] = util.to_string(versionId) - return self._make_delete_request(bucketName, objectKey, pathArgs=path_args, methodName='deleteObject') + return self._make_delete_request(bucketName, objectKey, pathArgs=path_args, methodName='deleteObject', extensionHeaders=extensionHeaders) @funcCache - def deleteObjects(self, bucketName, deleteObjectsRequest): + def deleteObjects(self, bucketName, deleteObjectsRequest, extensionHeaders=None): self._assert_not_null(deleteObjectsRequest, 'deleteObjectsRequest is empty') - return self._make_post_request(bucketName, methodName='deleteObjects', **self.convertor.trans_delete_objects(deleteObjectsRequest=deleteObjectsRequest)) + return self._make_post_request(bucketName, methodName='deleteObjects', extensionHeaders=extensionHeaders, **self.convertor.trans_delete_objects(deleteObjectsRequest=deleteObjectsRequest)) @funcCache - def restoreObject(self, bucketName, objectKey, days, tier=None, versionId=None): + def restoreObject(self, bucketName, objectKey, days, tier=None, versionId=None, extensionHeaders=None): self._assert_not_null(days, 'days is empty') - return self._make_post_request(bucketName, objectKey, **self.convertor.trans_restore_object(days=days, tier=tier, versionId=versionId)) + return self._make_post_request(bucketName, objectKey, extensionHeaders=extensionHeaders, **self.convertor.trans_restore_object(days=days, tier=tier, versionId=versionId)) @funcCache def initiateMultipartUpload(self, bucketName, objectKey, acl=None, storageClass=None, - metadata=None, websiteRedirectLocation=None, contentType=None, sseHeader=None, expires=None, extensionGrants=None): + metadata=None, websiteRedirectLocation=None, contentType=None, sseHeader=None, expires=None, extensionGrants=None, extensionHeaders=None): objectKey = util.safe_encode(objectKey) if objectKey is None: objectKey = '' @@ -1720,85 +1734,93 @@ def initiateMultipartUpload(self, bucketName, objectKey, acl=None, storageClass= if contentType is None: contentType = const.MIME_TYPES.get(objectKey[objectKey.rfind('.') + 1:].lower()) - return self._make_post_request(bucketName, objectKey, methodName='initiateMultipartUpload', + return self._make_post_request(bucketName, objectKey, methodName='initiateMultipartUpload', extensionHeaders=extensionHeaders, **self.convertor.trans_initiate_multipart_upload(acl=acl, storageClass=storageClass, metadata=metadata, websiteRedirectLocation=websiteRedirectLocation, contentType=contentType, sseHeader=sseHeader, expires=expires, extensionGrants=extensionGrants)) @funcCache - def copyPart(self, bucketName, objectKey, partNumber, uploadId, copySource, copySourceRange=None, destSseHeader=None, sourceSseHeader=None): + def copyPart(self, bucketName, objectKey, partNumber, uploadId, copySource, copySourceRange=None, destSseHeader=None, sourceSseHeader=None, extensionHeaders=None): self._assert_not_null(partNumber, 'partNumber is empty') self._assert_not_null(uploadId, 'uploadId is empty') self._assert_not_null(copySource, 'copySource is empty') - return self._make_put_request(bucketName, objectKey, methodName='copyPart', **self.convertor.trans_copy_part(partNumber=partNumber, uploadId=uploadId, copySource=copySource, + return self._make_put_request(bucketName, objectKey, methodName='copyPart', extensionHeaders=extensionHeaders, **self.convertor.trans_copy_part(partNumber=partNumber, uploadId=uploadId, copySource=copySource, copySourceRange=copySourceRange, destSseHeader=destSseHeader, sourceSseHeader=sourceSseHeader)) @funcCache - def completeMultipartUpload(self, bucketName, objectKey, uploadId, completeMultipartUploadRequest): + def completeMultipartUpload(self, bucketName, objectKey, uploadId, completeMultipartUploadRequest, extensionHeaders=None): self._assert_not_null(uploadId, 'uploadId is empty') self._assert_not_null(completeMultipartUploadRequest, 'completeMultipartUploadRequest is empty') ret = self._make_post_request(bucketName, objectKey, pathArgs={'uploadId':uploadId}, - entity=self.convertor.trans_complete_multipart_upload_request(completeMultipartUploadRequest), methodName='completeMultipartUpload') + entity=self.convertor.trans_complete_multipart_upload_request(completeMultipartUploadRequest), methodName='completeMultipartUpload', extensionHeaders=extensionHeaders) self._generate_object_url(ret, bucketName, objectKey) return ret @funcCache - def abortMultipartUpload(self, bucketName, objectKey, uploadId): + def abortMultipartUpload(self, bucketName, objectKey, uploadId, extensionHeaders=None): self._assert_not_null(uploadId, 'uploadId is empty') - return self._make_delete_request(bucketName, objectKey, pathArgs={'uploadId' : uploadId}) + return self._make_delete_request(bucketName, objectKey, pathArgs={'uploadId' : uploadId}, extensionHeaders=extensionHeaders) @funcCache - def listParts(self, bucketName, objectKey, uploadId, maxParts=None, partNumberMarker=None): + def listParts(self, bucketName, objectKey, uploadId, maxParts=None, partNumberMarker=None, extensionHeaders=None): self._assert_not_null(uploadId, 'uploadId is empty') pathArgs = {'uploadId': uploadId} if maxParts is not None: pathArgs['max-parts'] = maxParts if partNumberMarker is not None: pathArgs['part-number-marker'] = partNumberMarker - return self._make_get_request(bucketName, objectKey, pathArgs=pathArgs, methodName='listParts') + return self._make_get_request(bucketName, objectKey, pathArgs=pathArgs, methodName='listParts', extensionHeaders=extensionHeaders) @funcCache - def getBucketStoragePolicy(self, bucketName): - return self._make_get_request(bucketName, methodName='getBucketStoragePolicy', **self.convertor.trans_get_bucket_storage_policy()) + def getBucketStoragePolicy(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, methodName='getBucketStoragePolicy', extensionHeaders=extensionHeaders, **self.convertor.trans_get_bucket_storage_policy()) @funcCache - def setBucketStoragePolicy(self, bucketName, storageClass): + def setBucketStoragePolicy(self, bucketName, storageClass, extensionHeaders=None): self._assert_not_null(storageClass, 'storageClass is empty') - return self._make_put_request(bucketName, **self.convertor.trans_set_bucket_storage_policy(storageClass=storageClass)) + return self._make_put_request(bucketName, extensionHeaders=extensionHeaders, **self.convertor.trans_set_bucket_storage_policy(storageClass=storageClass)) @funcCache - def setBucketEncryption(self, bucketName, encryption, key=None): + def setBucketEncryption(self, bucketName, encryption, key=None, extensionHeaders=None): self._assert_not_null(encryption, 'encryption is empty') - return self._make_put_request(bucketName, pathArgs={'encryption': None}, entity=self.convertor.trans_encryption(encryption=encryption, key=key)) + return self._make_put_request(bucketName, pathArgs={'encryption': None}, entity=self.convertor.trans_encryption(encryption=encryption, key=key), extensionHeaders=extensionHeaders) @funcCache - def getBucketEncryption(self, bucketName): - return self._make_get_request(bucketName, methodName='getBucketEncryption', pathArgs={'encryption':None}) + def getBucketEncryption(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, methodName='getBucketEncryption', pathArgs={'encryption':None}, extensionHeaders=extensionHeaders) @funcCache - def deleteBucketEncryption(self, bucketName): - return self._make_delete_request(bucketName, pathArgs={'encryption':None}) + def deleteBucketEncryption(self, bucketName, extensionHeaders=None): + return self._make_delete_request(bucketName, pathArgs={'encryption':None}, extensionHeaders=extensionHeaders) @funcCache - def setBucketReplication(self, bucketName, replication): + def setBucketReplication(self, bucketName, replication, extensionHeaders=None): self._assert_not_null(replication, 'replication is empty') - return self._make_put_request(bucketName, **self.convertor.trans_set_bucket_replication(replication=replication)) + return self._make_put_request(bucketName, extensionHeaders=extensionHeaders, **self.convertor.trans_set_bucket_replication(replication=replication)) @funcCache - def getBucketReplication(self, bucketName): - return self._make_get_request(bucketName, pathArgs={'replication':None}, methodName='getBucketReplication') + def getBucketReplication(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'replication':None}, methodName='getBucketReplication', extensionHeaders=extensionHeaders) @funcCache - def deleteBucketReplication(self, bucketName): - return self._make_delete_request(bucketName, pathArgs={'replication':None}) - + def deleteBucketReplication(self, bucketName, extensionHeaders=None): + return self._make_delete_request(bucketName, pathArgs={'replication':None}, extensionHeaders=extensionHeaders) + + @funcCache + def setBucketRequestPayment(self, bucketName, payer, extensionHeaders=None): + self._assert_not_null(payer, 'payer is empty') + return self._make_put_request(bucketName, pathArgs={'requestPayment': None}, entity=self.convertor.trans_bucket_request_payment(payer=payer), extensionHeaders=extensionHeaders) + + @funcCache + def getBucketRequestPayment(self, bucketName, extensionHeaders=None): + return self._make_get_request(bucketName, pathArgs={'requestPayment': None}, methodName='getBucketRequestPayment', extensionHeaders=extensionHeaders) @funcCache def uploadFile(self, bucketName, objectKey, uploadFile, partSize=9 * 1024 * 1024, taskNum=1, enableCheckpoint=False, checkpointFile=None, - checkSum=False, metadata=None, progressCallback=None, headers=None): + checkSum=False, metadata=None, progressCallback=None, headers=None, extensionHeaders=None): self.log_client.log(INFO, 'enter resume upload file...') self._assert_not_null(bucketName, 'bucketName is empty') self._assert_not_null(objectKey, 'objectKey is empty') @@ -1816,11 +1838,11 @@ def uploadFile(self, bucketName, objectKey, uploadFile, partSize=9 * 1024 * 1024 taskNum = 1 else: taskNum = int(math.ceil(taskNum)) - return _resumer_upload(bucketName, objectKey, uploadFile, partSize, taskNum, enableCheckpoint, checkpointFile, checkSum, metadata, progressCallback, self, headers) + return _resumer_upload(bucketName, objectKey, uploadFile, partSize, taskNum, enableCheckpoint, checkpointFile, checkSum, metadata, progressCallback, self, headers, extensionHeaders=extensionHeaders) @funcCache def _downloadFileWithNotifier(self, bucketName, objectKey, downloadFile=None, partSize=5 * 1024 * 1024, taskNum=1, enableCheckpoint=False, - checkpointFile=None, header=None, versionId=None, progressCallback=None, imageProcess=None, notifier=progress.NONE_NOTIFIER): + checkpointFile=None, header=None, versionId=None, progressCallback=None, imageProcess=None, notifier=progress.NONE_NOTIFIER, extensionHeaders=None): self.log_client.log(INFO, 'enter resume download...') self._assert_not_null(bucketName, 'bucketName is empty') self._assert_not_null(objectKey, 'objectKey is empty') @@ -1842,18 +1864,18 @@ def _downloadFileWithNotifier(self, bucketName, objectKey, downloadFile=None, pa else: taskNum = int(math.ceil(taskNum)) return _resumer_download(bucketName, objectKey, downloadFile, partSize, taskNum, enableCheckpoint, checkpointFile, header, versionId, progressCallback, self, - imageProcess, notifier) + imageProcess, notifier, extensionHeaders=extensionHeaders) def downloadFile(self, bucketName, objectKey, downloadFile=None, partSize=5 * 1024 * 1024, taskNum=1, enableCheckpoint=False, - checkpointFile=None, header=None, versionId=None, progressCallback=None, imageProcess=None): - return self._downloadFileWithNotifier(bucketName, objectKey, downloadFile, partSize, taskNum, enableCheckpoint, checkpointFile, header, versionId, progressCallback, imageProcess) + checkpointFile=None, header=None, versionId=None, progressCallback=None, imageProcess=None, extensionHeaders=None): + return self._downloadFileWithNotifier(bucketName, objectKey, downloadFile, partSize, taskNum, enableCheckpoint, checkpointFile, header, versionId, progressCallback, imageProcess, extensionHeaders=extensionHeaders) def downloadFiles(self, bucketName, prefix, downloadFolder=None, taskNum=const.DEFAULT_TASK_NUM, taskQueueSize=const.DEFAULT_TASK_QUEUE_SIZE, headers=GetObjectHeader(), imageProcess=None, interval=const.DEFAULT_BYTE_INTTERVAL, taskCallback=None, progressCallback=None, - threshold=const.DEFAULT_MAXIMUM_SIZE, partSize=5*1024*1024, subTaskNum=1, enableCheckpoint=False, checkpointFile=None): + threshold=const.DEFAULT_MAXIMUM_SIZE, partSize=5*1024*1024, subTaskNum=1, enableCheckpoint=False, checkpointFile=None, extensionHeaders=None): return _download_files(self, bucketName, prefix, downloadFolder, taskNum, taskQueueSize, headers, imageProcess, - interval, taskCallback, progressCallback, threshold, partSize, subTaskNum, enableCheckpoint, checkpointFile) + interval, taskCallback, progressCallback, threshold, partSize, subTaskNum, enableCheckpoint, checkpointFile, extensionHeaders=extensionHeaders) diff --git a/src/obs/const.py b/src/obs/const.py index 15904ac..8e2bc0b 100644 --- a/src/obs/const.py +++ b/src/obs/const.py @@ -87,7 +87,7 @@ DEFAULT_TASK_QUEUE_SIZE = 20000 -OBS_SDK_VERSION = '3.19.11' +OBS_SDK_VERSION = '3.20.1' V2_META_HEADER_PREFIX = 'x-amz-meta-' V2_HEADER_PREFIX = 'x-amz-' diff --git a/src/obs/convertor.py b/src/obs/convertor.py index afc6fd7..65aa2ec 100644 --- a/src/obs/convertor.py +++ b/src/obs/convertor.py @@ -164,6 +164,9 @@ def next_position_header(self): def object_type_header(self): return 'x-obs-object-type' + + def request_payer_header(self): + return self._get_header_prefix() + 'request-payer' def adapt_group(self, group): if self.is_obs: @@ -908,7 +911,18 @@ def trans_replication(self, replication): if replicationRule.get('storageClass') is not None: ET.SubElement(destinationEle, 'Bucket').text = self.ha.adapt_storage_class(replicationRule['storageClass']) return ET.tostring(root, 'UTF-8') - + + def trans_bucket_request_payment(self, payer): + root = ET.Element('RequestPaymentConfiguration') + ET.SubElement(root, 'Payer').text = util.to_string(payer) + return ET.tostring(root, 'UTF-8') + + def trans_get_extension_headers(self, headers): + _headers = {} + if headers is not None and len(headers) > 0: + self._put_key_value(_headers, self.ha.request_payer_header(), (headers.get('requesterPayer'))) + return _headers + def _find_item(self, root, itemname): result = root.find(itemname) if result is None: @@ -1628,3 +1642,8 @@ def parseGetBucketReplication(self, xml, headers=None): replication = Replication(agency=agency, replicationRules=_rules) return replication + def parseGetBucketRequestPayment(self, xml, headers=None): + root = ET.fromstring(xml) + payer =self._find_item(root, 'Payer') + payment = GetBucketRequestPaymentResponse(payer=payer) + return payment \ No newline at end of file diff --git a/src/obs/extension.py b/src/obs/extension.py index 6d41b84..2e321f4 100644 --- a/src/obs/extension.py +++ b/src/obs/extension.py @@ -1,119 +1,119 @@ -#!/usr/bin/python -# -*- coding:utf-8 -*- -# Copyright 2019 Huawei Technologies Co.,Ltd. -# 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. - -import os -import traceback -from obs import const, util, progress, bulktasks -from obs.model import GetObjectRequest -from obs.model import GetObjectHeader -from obs.ilog import ERROR - -def _download_files(obsClient, bucketName, prefix, downloadFolder=None, taskNum=const.DEFAULT_TASK_NUM, taskQueueSize=const.DEFAULT_TASK_QUEUE_SIZE, - headers=GetObjectHeader(), imageProcess=None, interval=const.DEFAULT_BYTE_INTTERVAL, taskCallback=None, progressCallback=None, - threshold=const.DEFAULT_MAXIMUM_SIZE, partSize=5*1024*1024, subTaskNum=1, enableCheckpoint=False, checkpointFile=None): - try: - executor = None - notifier = None - if downloadFolder is None or not os.path.isdir(downloadFolder): - raise Exception('%s is not a Folder' % downloadFolder) - - if taskCallback is not None and not callable(taskCallback): - raise Exception('Invalid taskCallback') - - (taskNum, taskQueueSize, interval, threshold) = bulktasks._checkBulkTasksPara(taskNum, taskQueueSize, interval, threshold) - - taskCallback = taskCallback if taskCallback is not None else util.lazyCallback - executor = bulktasks.ThreadPool(taskNum, taskQueueSize) - state = bulktasks.ExecuteProgress() - totalTasks = const.LONG(0) - totalAmount = const.LONG(0) - notifier = progress.ProgressNotifier(progressCallback, totalAmount, interval) if progressCallback is not None else progress.NONE_NOTIFIER - notifier.start() - - query = GetObjectRequest(imageProcess=imageProcess) - - prefix = prefix if prefix is not None else '' - prefixDir = prefix[:prefix.rfind('/')+1] - - for content in _list_objects(obsClient, bucketName, prefix=prefix): - objectKey = content.key - totalTasks += 1 - totalAmount += content.size - objectPath = objectKey.replace(prefixDir, '', 1) - if objectPath.startswith('/') or objectPath.find('//') != -1 or objectPath.find('\\') != -1: - state._failed_increment() - taskCallback(objectKey, Exception('illegal path: %s' % objectKey)) - obsClient.log_client.log(ERROR, 'illegal path: %s' % objectKey) - continue - - downloadPath = os.path.join(downloadFolder, objectPath) - downloadPath = util.safe_encode(downloadPath) - if const.IS_WINDOWS: - downloadPath = util.safe_trans_to_gb2312(downloadPath) - - dirName = os.path.dirname(downloadPath) - if not os.path.exists(dirName): - try: - os.makedirs(dirName, 0o755) - except Exception as e: - state._failed_increment() - taskCallback(objectKey, e) - obsClient.log_client.log(ERROR, traceback.format_exc()) - continue - - if objectKey.endswith(('/')): - state._successful_increment() - elif content.size < threshold: - executor.execute(_task_wrap, obsClient, obsClient._getObjectWithNotifier, key=objectKey, taskCallback=taskCallback, state=state, bucketName=bucketName, - objectKey=objectKey, getObjectRequest=query, headers=headers, downloadPath=downloadPath, notifier=notifier) - else: - executor.execute(_task_wrap, obsClient, obsClient._downloadFileWithNotifier, key=objectKey, taskCallback=taskCallback, state=state, bucketName=bucketName, - objectKey=objectKey, downloadFile=downloadPath, partSize=partSize, taskNum=subTaskNum, enableCheckpoint=enableCheckpoint, - checkpointFile=checkpointFile, header=headers, imageProcess=imageProcess, notifier=notifier) - - state.total_tasks = totalTasks - notifier.totalAmount = totalAmount - finally: - if executor is not None: - executor.shutdown() - if notifier is not None: - notifier.end() - - return state - -def _task_wrap(obsClient, func, key, taskCallback=None, state=None, **kwargs): - try: - res = func(**kwargs) - if res.status < 300: - state._successful_increment() - else: - state._failed_increment() - taskCallback(key, res) - except Exception as e: - state._failed_increment() - taskCallback(key, e) - obsClient.log_client.log(ERROR, traceback.format_exc()) - -def _list_objects(obsClient, bucketName, prefix=None, marker=None, max_keys=None, delimiter=None): - while True: - resp = obsClient.listObjects(bucketName, max_keys=max_keys, marker=marker, prefix=prefix, delimiter=delimiter) - if resp.status < 300: - for content in resp.body.contents: - yield content - if not resp.body.is_truncated: - break - marker = resp.body.next_marker - else: - obsClient.log_client.log(ERROR, 'listObjects Error: errorCode:%s, errorMessage:%s' % (resp.errorCode, resp.errorMessage)) +#!/usr/bin/python +# -*- coding:utf-8 -*- +# Copyright 2019 Huawei Technologies Co.,Ltd. +# 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. + +import os +import traceback +from obs import const, util, progress, bulktasks +from obs.model import GetObjectRequest +from obs.model import GetObjectHeader +from obs.ilog import ERROR + +def _download_files(obsClient, bucketName, prefix, downloadFolder=None, taskNum=const.DEFAULT_TASK_NUM, taskQueueSize=const.DEFAULT_TASK_QUEUE_SIZE, + headers=GetObjectHeader(), imageProcess=None, interval=const.DEFAULT_BYTE_INTTERVAL, taskCallback=None, progressCallback=None, + threshold=const.DEFAULT_MAXIMUM_SIZE, partSize=5*1024*1024, subTaskNum=1, enableCheckpoint=False, checkpointFile=None, extensionHeaders=None): + try: + executor = None + notifier = None + if downloadFolder is None or not os.path.isdir(downloadFolder): + raise Exception('%s is not a Folder' % downloadFolder) + + if taskCallback is not None and not callable(taskCallback): + raise Exception('Invalid taskCallback') + + (taskNum, taskQueueSize, interval, threshold) = bulktasks._checkBulkTasksPara(taskNum, taskQueueSize, interval, threshold) + + taskCallback = taskCallback if taskCallback is not None else util.lazyCallback + executor = bulktasks.ThreadPool(taskNum, taskQueueSize) + state = bulktasks.ExecuteProgress() + totalTasks = const.LONG(0) + totalAmount = const.LONG(0) + notifier = progress.ProgressNotifier(progressCallback, totalAmount, interval) if progressCallback is not None else progress.NONE_NOTIFIER + notifier.start() + + query = GetObjectRequest(imageProcess=imageProcess) + + prefix = prefix if prefix is not None else '' + prefixDir = prefix[:prefix.rfind('/')+1] + + for content in _list_objects(obsClient, bucketName, prefix=prefix, extensionHeaders=extensionHeaders): + objectKey = content.key + totalTasks += 1 + totalAmount += content.size + objectPath = objectKey.replace(prefixDir, '', 1) + if objectPath.startswith('/') or objectPath.find('//') != -1 or objectPath.find('\\') != -1: + state._failed_increment() + taskCallback(objectKey, Exception('illegal path: %s' % objectKey)) + obsClient.log_client.log(ERROR, 'illegal path: %s' % objectKey) + continue + + downloadPath = os.path.join(downloadFolder, objectPath) + downloadPath = util.safe_encode(downloadPath) + if const.IS_WINDOWS: + downloadPath = util.safe_trans_to_gb2312(downloadPath) + + dirName = os.path.dirname(downloadPath) + if not os.path.exists(dirName): + try: + os.makedirs(dirName, 0o755) + except Exception as e: + state._failed_increment() + taskCallback(objectKey, e) + obsClient.log_client.log(ERROR, traceback.format_exc()) + continue + + if objectKey.endswith(('/')): + state._successful_increment() + elif content.size < threshold: + executor.execute(_task_wrap, obsClient, obsClient._getObjectWithNotifier, key=objectKey, taskCallback=taskCallback, state=state, bucketName=bucketName, + objectKey=objectKey, getObjectRequest=query, headers=headers, downloadPath=downloadPath, notifier=notifier, extensionHeaders=extensionHeaders) + else: + executor.execute(_task_wrap, obsClient, obsClient._downloadFileWithNotifier, key=objectKey, taskCallback=taskCallback, state=state, bucketName=bucketName, + objectKey=objectKey, downloadFile=downloadPath, partSize=partSize, taskNum=subTaskNum, enableCheckpoint=enableCheckpoint, + checkpointFile=checkpointFile, header=headers, imageProcess=imageProcess, notifier=notifier, extensionHeaders=extensionHeaders) + + state.total_tasks = totalTasks + notifier.totalAmount = totalAmount + finally: + if executor is not None: + executor.shutdown() + if notifier is not None: + notifier.end() + + return state + +def _task_wrap(obsClient, func, key, taskCallback=None, state=None, **kwargs): + try: + res = func(**kwargs) + if res.status < 300: + state._successful_increment() + else: + state._failed_increment() + taskCallback(key, res) + except Exception as e: + state._failed_increment() + taskCallback(key, e) + obsClient.log_client.log(ERROR, traceback.format_exc()) + +def _list_objects(obsClient, bucketName, prefix=None, marker=None, max_keys=None, delimiter=None, extensionHeaders=None): + while True: + resp = obsClient.listObjects(bucketName, max_keys=max_keys, marker=marker, prefix=prefix, delimiter=delimiter, extensionHeaders=extensionHeaders) + if resp.status < 300: + for content in resp.body.contents: + yield content + if not resp.body.is_truncated: + break + marker = resp.body.next_marker + else: + obsClient.log_client.log(ERROR, 'listObjects Error: errorCode:%s, errorMessage:%s' % (resp.errorCode, resp.errorMessage)) break \ No newline at end of file diff --git a/src/obs/model.py b/src/obs/model.py index 557ad9d..7c5f383 100644 --- a/src/obs/model.py +++ b/src/obs/model.py @@ -111,7 +111,10 @@ 'ResponseWrapper', 'ObjectStream', 'GetBucketEncryptionResponse', - 'UploadFileHeader' + 'UploadFileHeader', + 'GetBucketRequestPaymentResponse', + 'Payer', + 'ExtensionHeader' ] @@ -1146,7 +1149,17 @@ def __init__(self, etag=None, sseKms=None, sseKmsKey=None, sseC=None, sseCKeyMd5 self.sseKmsKey = sseKmsKey self.sseC = sseC self.sseCKeyMd5 = sseCKeyMd5 - + +class GetBucketRequestPaymentResponse(BaseModel): + allowedAttr = {'payer': BASESTRING} + def __init__(self, payer=None): + self.payer = payer + +class Payer(object): + BUCKET_OWNER_PAYER = "BucketOwner" + REQUESTER_PAYER = "Requester" + REQUESTER = "requester" + class ResponseWrapper(object): def __init__(self, conn, result, connHolder, contentLength=None, notifier=None): self.conn = conn @@ -1228,3 +1241,8 @@ def __init__(self, response=None, buffer=None, size=None, url=None, deleteMarker self.sseC = sseC self.sseCKeyMd5 = sseCKeyMd5 +class ExtensionHeader(BaseModel): + allowedAttr = {'requesterPayer': BASESTRING} + + def __init__(self, requesterPayer=None): + self.requesterPayer = requesterPayer \ No newline at end of file diff --git a/src/obs/transfer.py b/src/obs/transfer.py index d77cc24..16eeb93 100644 --- a/src/obs/transfer.py +++ b/src/obs/transfer.py @@ -36,16 +36,16 @@ import queue -def _resumer_upload(bucketName, objectKey, uploadFile, partSize, taskNum, enableCheckPoint, checkPointFile, checkSum, metadata, progressCallback, obsClient, headers): +def _resumer_upload(bucketName, objectKey, uploadFile, partSize, taskNum, enableCheckPoint, checkPointFile, checkSum, metadata, progressCallback, obsClient, headers, extensionHeaders=None): upload_operation = uploadOperation(util.to_string(bucketName), util.to_string(objectKey), util.to_string(uploadFile), partSize, taskNum, enableCheckPoint, - util.to_string(checkPointFile), checkSum, metadata, progressCallback, obsClient, headers) + util.to_string(checkPointFile), checkSum, metadata, progressCallback, obsClient, headers, extensionHeaders=extensionHeaders) return upload_operation._upload() def _resumer_download(bucketName, objectKey, downloadFile, partSize, taskNum, enableCheckPoint, checkPointFile, - header, versionId, progressCallback, obsClient, imageProcess=None, notifier=progress.NONE_NOTIFIER): + header, versionId, progressCallback, obsClient, imageProcess=None, notifier=progress.NONE_NOTIFIER, extensionHeaders=None): down_operation = downloadOperation(util.to_string(bucketName), util.to_string(objectKey), util.to_string(downloadFile), partSize, taskNum, enableCheckPoint, util.to_string(checkPointFile), - header, versionId, progressCallback, obsClient, imageProcess, notifier) + header, versionId, progressCallback, obsClient, imageProcess, notifier, extensionHeaders=extensionHeaders) if down_operation.size == 0: down_operation._delete_record() down_operation._delete_tmp_file() @@ -109,12 +109,13 @@ def _write_record(self, record): class uploadOperation(Operation): def __init__(self, bucketName, objectKey, uploadFile, partSize, taskNum, enableCheckPoint, checkPointFile, - checkSum, metadata, progressCallback, obsClient, headers): + checkSum, metadata, progressCallback, obsClient, headers, extensionHeaders=None): super(uploadOperation, self).__init__(bucketName, objectKey, uploadFile, partSize, taskNum, enableCheckPoint, checkPointFile, progressCallback, obsClient) self.checkSum = checkSum self.metadata = metadata self.headers = headers + self.extensionHeaders = extensionHeaders try: self.size = os.path.getsize(self.fileName) @@ -123,7 +124,7 @@ def __init__(self, bucketName, objectKey, uploadFile, partSize, taskNum, enableC self._delete_record() self.obsClient.log_client.log(ERROR, 'something is happened when obtain uploadFile information. Please check') raise e - resp = self.obsClient.headBucket(self.bucketName) + resp = self.obsClient.headBucket(self.bucketName, extensionHeaders=extensionHeaders) if resp.status > 300: raise Exception('head bucket {0} failed. Please check. Status:{1}.'.format(self.bucketName, resp.status)) @@ -157,7 +158,7 @@ def _upload(self): thread_pools.run() if self._abort: - self.obsClient.abortMultipartUpload(self.bucketName, self.objectKey, self._record['uploadId']) + self.obsClient.abortMultipartUpload(self.bucketName, self.objectKey, self._record['uploadId'], extensionHeaders=self.extensionHeaders) self.obsClient.log_client.log(ERROR, 'the code from server is 4**, please check space态persimission and so on.') self._delete_record() if self._exception is not None: @@ -166,7 +167,7 @@ def _upload(self): for p in self._record['uploadParts']: if not p['isCompleted']: if not self.enableCheckPoint: - self.obsClient.abortMultipartUpload(self.bucketName, self.objectKey, self._record['uploadId']) + self.obsClient.abortMultipartUpload(self.bucketName, self.objectKey, self._record['uploadId'], extensionHeaders=self.extensionHeaders) raise Exception('some parts are failed when upload. Please try again') part_Etags = [] @@ -174,18 +175,18 @@ def _upload(self): part_Etags.append(CompletePart(partNum=part['partNum'], etag=part['etag'])) self.obsClient.log_client.log(INFO, 'Completing to upload multiparts') resp = self.obsClient.completeMultipartUpload(self.bucketName, self.objectKey, self._record['uploadId'], - CompleteMultipartUploadRequest(part_Etags)) + CompleteMultipartUploadRequest(part_Etags), extensionHeaders=self.extensionHeaders) if resp.status < 300: if self.enableCheckPoint: self._delete_record() else: if not self.enableCheckPoint: - self.obsClient.abortMultipartUpload(self.bucketName, self.objectKey, self._record['uploadId']) + self.obsClient.abortMultipartUpload(self.bucketName, self.objectKey, self._record['uploadId'], extensionHeaders=self.extensionHeaders) self.obsClient.log_client.log(ERROR, 'something is wrong when complete multipart.ErrorCode:{0}. ErrorMessage:{1}'.format( resp.errorCode, resp.errorMessage)) else: if resp.status > 300 and resp.status < 500: - self.obsClient.abortMultipartUpload(self.bucketName, self.objectKey, self._record['uploadId']) + self.obsClient.abortMultipartUpload(self.bucketName, self.objectKey, self._record['uploadId'], extensionHeaders=self.extensionHeaders) self.obsClient.log_client.log(ERROR, 'something is wrong when complete multipart.ErrorCode:{0}. ErrorMessage:{1}'.format( resp.errorCode, resp.errorMessage)) self._delete_record() @@ -197,7 +198,7 @@ def _load(self): self._record = self._get_record() if self._record and not (self._type_check(self._record) and self._check_upload_record(self._record)): if self._record['bucketName'] and self._record['objectKey'] and self._record['uploadId'] is not None: - self.obsClient.abortMultipartUpload(self._record['bucketName'], self._record['objectKey'], self._record['uploadId']) + self.obsClient.abortMultipartUpload(self._record['bucketName'], self._record['objectKey'], self._record['uploadId'], extensionHeaders=self.extensionHeaders) self.obsClient.log_client.log(ERROR, 'checkpointFile is invalid') self._delete_record() self._record = None @@ -276,7 +277,7 @@ def _prepare(self): resp = self.obsClient.initiateMultipartUpload(self.bucketName, self.objectKey, metadata=self.metadata, acl=self.headers.acl, storageClass=self.headers.storageClass, websiteRedirectLocation=self.headers.websiteRedirectLocation, contentType=self.headers.contentType, sseHeader=self.headers.sseHeader, expires=self.headers.expires, - extensionGrants=self.headers.extensionGrants) + extensionGrants=self.headers.extensionGrants, extensionHeaders=self.extensionHeaders) if resp.status > 300: raise Exception('initiateMultipartUpload failed. ErrorCode:{0}. ErrorMessage:{1}'.format(resp.errorCode, resp.errorMessage)) uploadId = resp.body.uploadId @@ -301,7 +302,7 @@ def _upload_part(self, part): if not self._is_abort(): try: resp = self.obsClient._uploadPartWithNotifier(self.bucketName, self.objectKey, part['partNumber'], self._record['uploadId'], self.fileName, - isFile=True, partSize=part['length'], offset=part['offset'], notifier=self.notifier) + isFile=True, partSize=part['length'], offset=part['offset'], notifier=self.notifier, extensionHeaders=self.extensionHeaders) if resp.status < 300: self._record['uploadParts'][part['partNumber']-1]['isCompleted'] = True self._record['partEtags'].append(CompletePart(util.to_int(part['partNumber']), resp.body.etag)) @@ -319,19 +320,20 @@ def _upload_part(self, part): class downloadOperation(Operation): def __init__(self, bucketName, objectKey, downloadFile, partSize, taskNum, enableCheckPoint, checkPointFile, - header, versionId, progressCallback, obsClient, imageProcess=None, notifier=progress.NONE_NOTIFIER): + header, versionId, progressCallback, obsClient, imageProcess=None, notifier=progress.NONE_NOTIFIER, extensionHeaders=None): super(downloadOperation, self).__init__(bucketName, objectKey, downloadFile, partSize, taskNum, enableCheckPoint, checkPointFile, progressCallback, obsClient, notifier) self.header = header self.versionId = versionId self.imageProcess = imageProcess + self.extensionHeaders = extensionHeaders parent_dir = os.path.dirname(self.fileName) if not os.path.exists(parent_dir): os.makedirs(parent_dir, exist_ok=True) self._tmp_file = self.fileName + '.tmp' - metedata_resp = self.obsClient.getObjectMetadata(self.bucketName, self.objectKey, self.versionId) + metedata_resp = self.obsClient.getObjectMetadata(self.bucketName, self.objectKey, self.versionId, extensionHeaders=self.extensionHeaders) if metedata_resp.status < 300: self.lastModified = metedata_resp.body.lastModified self.size = metedata_resp.body.contentLength if metedata_resp.body.contentLength is not None and metedata_resp.body.contentLength >= 0 else 0 @@ -517,7 +519,7 @@ def _download_part(self, part): response = None try: resp = self.obsClient._getObjectWithNotifier(bucketName=self.bucketName, objectKey=self.objectKey, - getObjectRequest=get_object_request, headers=get_object_header, notifier=self.notifier) + getObjectRequest=get_object_request, headers=get_object_header, notifier=self.notifier, extensionHeaders=self.extensionHeaders) if resp.status < 300: respone = resp.body.response chunk_size = 65536 diff --git a/src/setup.py b/src/setup.py index 8fcf672..c709ebb 100644 --- a/src/setup.py +++ b/src/setup.py @@ -23,7 +23,7 @@ setup( name='esdk-obs-python', - version='3.19.11', + version='3.20.1', packages=find_packages(), zip_safe=False, description='OBS Python SDK',