Skip to content

Commit f3888f8

Browse files
authored
Merge pull request #324 from tencentyun/feature_libertyzhu_7a81e6b8
Feature libertyzhu 7a81e6b8
2 parents b25d5b1 + 3a16f3b commit f3888f8

File tree

5 files changed

+70
-7
lines changed

5 files changed

+70
-7
lines changed

qcloud_cos/cos_client.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4037,7 +4037,8 @@ def _check_all_upload_parts(self, bucket, key, uploadid, local_path, parts_num,
40374037
already_exist_parts[part_num] = part['ETag']
40384038
return True
40394039

4040-
def download_file(self, Bucket, Key, DestFilePath, PartSize=20, MAXThread=5, EnableCRC=False, progress_callback=None, DumpRecordDir=None, KeySimplifyCheck=True, DisableTempDestFilePath=False, **Kwargs):
4040+
def download_file(self, Bucket, Key, DestFilePath, PartSize=20, MAXThread=5, EnableCRC=False, progress_callback=None,
4041+
DumpRecordDir=None, KeySimplifyCheck=True, DisableTempDestFilePath=False, MaxPartCount=10000, **Kwargs):
40414042
"""小于等于20MB的文件简单下载,大于20MB的文件使用续传下载
40424043
40434044
:param Bucket(string): 存储桶名称.
@@ -4049,10 +4050,11 @@ def download_file(self, Bucket, Key, DestFilePath, PartSize=20, MAXThread=5, Ena
40494050
:param DumpRecordDir(string): 指定保存断点信息的文件路径
40504051
:param KeySimplifyCheck(bool): 是否对Key进行posix路径语义归并检查
40514052
:param DisableTempDestFilePath(bool): 简单下载写入目标文件时,不使用临时文件
4053+
:param MaxPartCount(int): 分块下载的最大分块数
40524054
:param kwargs(dict): 设置请求headers.
40534055
"""
40544056
logger.debug("Start to download file, bucket: {0}, key: {1}, dest_filename: {2}, part_size: {3}MB,\
4055-
max_thread: {4}".format(Bucket, Key, DestFilePath, PartSize, MAXThread))
4057+
max_thread: {4}, max_part_count: {5}".format(Bucket, Key, DestFilePath, PartSize, MAXThread, MaxPartCount))
40564058

40574059
head_headers = dict()
40584060
# SSE-C对象在head时也要求传入加密头域
@@ -4075,7 +4077,7 @@ def download_file(self, Bucket, Key, DestFilePath, PartSize=20, MAXThread=5, Ena
40754077
if progress_callback:
40764078
callback = ProgressCallback(file_size, progress_callback)
40774079

4078-
downloader = ResumableDownLoader(self, Bucket, Key, DestFilePath, object_info, PartSize, MAXThread, EnableCRC,
4080+
downloader = ResumableDownLoader(self, Bucket, Key, DestFilePath, object_info, PartSize, MAXThread, MaxPartCount, EnableCRC,
40794081
callback, DumpRecordDir, KeySimplifyCheck, **Kwargs)
40804082
downloader.start()
40814083

qcloud_cos/cos_comm.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
'ResponseContentEncoding': 'response-content-encoding',
3838
'Metadata': 'Metadata',
3939
'ACL': 'x-cos-acl',
40+
'Tagging': 'x-cos-tagging',
4041
'GrantFullControl': 'x-cos-grant-full-control',
4142
'GrantWrite': 'x-cos-grant-write',
4243
'GrantRead': 'x-cos-grant-read',
@@ -63,7 +64,8 @@
6364
'Referer': 'Referer',
6465
'PicOperations': 'Pic-Operations',
6566
'TrafficLimit': 'x-cos-traffic-limit',
66-
'Accept': 'Accept'
67+
'Accept': 'Accept',
68+
'AcceptEncoding': 'Accept-Encoding',
6769
}
6870

6971

qcloud_cos/cos_exception.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding=utf-8
22

33
import xml.dom.minidom
4+
from requests.structures import CaseInsensitiveDict
45

56

67
class CosException(Exception):
@@ -51,7 +52,7 @@ class CosServiceError(CosException):
5152

5253
def __init__(self, method, message, status_code):
5354
CosException.__init__(self, message)
54-
if isinstance(message, dict):
55+
if isinstance(message, dict) or isinstance(message, CaseInsensitiveDict):
5556
self._origin_msg = ''
5657
self._digest_msg = message
5758
else:

qcloud_cos/resumable_downloader.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
class ResumableDownLoader(object):
2020
def __init__(self, cos_client, bucket, key, dest_filename, object_info, part_size=20, max_thread=5,
21-
enable_crc=False, progress_callback=None, dump_record_dir=None, key_simplify_check=True, **kwargs):
21+
max_part_count=100, enable_crc=False, progress_callback=None, dump_record_dir=None, key_simplify_check=True, **kwargs):
2222
self.__cos_client = cos_client
2323
self.__bucket = bucket
2424
self.__key = key
@@ -30,7 +30,7 @@ def __init__(self, cos_client, bucket, key, dest_filename, object_info, part_siz
3030
self.__headers = kwargs
3131
self.__key_simplify_check = key_simplify_check
3232

33-
self.__max_part_count = 100 # 取决于服务端是否对并发有限制
33+
self.__max_part_count = max_part_count # 取决于服务端是否对并发有限制
3434
self.__min_part_size = 1024 * 1024 # 1M
3535
self.__part_size = self.__determine_part_size_internal(int(object_info['Content-Length']), part_size)
3636
self.__finished_parts = []

ut/test.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ def token(self):
7878
SecretKey=SECRET_KEY,
7979
)
8080

81+
anonymous_conf = CosConfig(Appid=APPID, Region=REGION, Anonymous=True)
82+
anonymous_client = CosS3Client(anonymous_conf)
83+
8184
client = CosS3Client(conf, retry=3)
8285
meta_insight_client = MetaInsightClient(metaConf, retry=3)
8386
ai_recognition_client = AIRecognitionClient(conf, retry=3)
@@ -6606,6 +6609,61 @@ def test_cos_client_retry_2():
66066609
do_retry_test(client2, err_retry_bucket, 'shutdown', 1, False)
66076610

66086611

6612+
def test_head_exception():
6613+
"""正确解析head请求响应的非404错误码"""
6614+
try:
6615+
anonymous_client.head_bucket(Bucket=test_bucket)
6616+
except CosServiceError as e:
6617+
assert 'x-cos-request-id' in e.get_digest_msg()
6618+
assert 403 == e.get_status_code()
6619+
6620+
try:
6621+
anonymous_client.head_object(Bucket=test_bucket, Key='foobar')
6622+
except CosServiceError as e:
6623+
assert 'x-cos-request-id' in e.get_digest_msg()
6624+
assert 403 == e.get_status_code()
6625+
6626+
6627+
def test_put_object_with_tagging():
6628+
"""上传对象时设置标签"""
6629+
key = 'tagging.obj'
6630+
# 设置单个tag: key=value
6631+
client.put_object(Bucket=test_bucket, Key=key, Body=b'hello', Tagging='A=B')
6632+
resp = client.get_object_tagging(Bucket=test_bucket, Key=key)
6633+
print(resp)
6634+
tag = resp['TagSet']['Tag']
6635+
assert tag[0]['Key'] == 'A'
6636+
assert tag[0]['Value'] == 'B'
6637+
resp = client.delete_object(Bucket=test_bucket, Key=key)
6638+
# 设置多个tag: key1=value1&key2=value2
6639+
client.put_object(Bucket=test_bucket, Key=key, Body=b'hello', Tagging='tagKey1=tagValue1&tagKey2=tagValue2')
6640+
resp = client.get_object_tagging(Bucket=test_bucket, Key=key)
6641+
print(resp)
6642+
tag = resp['TagSet']['Tag']
6643+
assert tag[0]['Key'] == 'tagKey1'
6644+
assert tag[0]['Value'] == 'tagValue1'
6645+
assert tag[1]['Key'] == 'tagKey2'
6646+
assert tag[1]['Value'] == 'tagValue2'
6647+
resp = client.delete_object(Bucket=test_bucket, Key=key)
6648+
6649+
# 高级接口upload_file
6650+
filename = 'BIG_20M'
6651+
gen_file(filename, 20)
6652+
6653+
resp = client.upload_file(Bucket=test_bucket, Key=key, LocalFilePath=filename, PartSize=1, Tagging='A=B')
6654+
print(resp)
6655+
resp = client.get_object_tagging(Bucket=test_bucket, Key=key)
6656+
print(resp)
6657+
tag = resp['TagSet']['Tag']
6658+
assert tag[0]['Key'] == 'A'
6659+
assert tag[0]['Value'] == 'B'
6660+
resp = client.delete_object(Bucket=test_bucket, Key=key)
6661+
6662+
if os.path.exists(filename):
6663+
os.remove(filename)
6664+
6665+
6666+
66096667
if __name__ == "__main__":
66106668
setUp()
66116669
"""

0 commit comments

Comments
 (0)