From 22050174157d139e7a88b71bee2219d1914f6504 Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Tue, 25 Jul 2017 22:12:58 +0800 Subject: [PATCH 01/71] Add test File --- qcloud_cos/cos_client.py | 53 +++++++++++++++++-- qcloud_cos/test.py | 108 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 qcloud_cos/test.py diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 955182b8..745bd2ad 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -14,7 +14,11 @@ logger = logging.getLogger(__name__) fs_coding = sys.getfilesystemencoding() -maplist = {'CacheControl':'Cache-Control', +maplist = { + 'ContentLength':'Content-Length', + 'ContentType':'Content-Type', + 'ContentMD5':'Content-MD5', + 'CacheControl':'Cache-Control', 'ContentDisposition':'Content-Disposition', 'ContentEncoding':'Content-Encoding', 'Expires':'Expires', @@ -24,6 +28,13 @@ 'GrantWrite':'x-cos-grant-write', 'GrantRead':'x-cos-grant-read', 'StorageClass':'x-cos-storage-class', + 'PartNumber':'partNumber', + 'UploadId':'uploadId', + 'Delimiter':'delimiter', + 'Marker':'marker', + 'MaxKeys':'max-keys', + 'Prefix':'prefix', + 'EncodingType':'encoding-type' } def to_unicode(s): @@ -140,8 +151,33 @@ def delete_object(self, Bucket, Key, **kwargs): if rt.status_code == 204: break return rt - - + + def create_multipart_upload(self, Bucket, Key, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?uploads") + for j in range(self._retry): + rt = self._session.post(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) + if rt.status_code == 200: + break + return rt + + def upload_part(self, Bucket, Key, PartNumber="", UploadId="", **kwargs): + headers,params = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?partNumber={PartNumber}&uploadId={UploadId}".format(PartNumber=PartNumber, UploadId=UploadId)) + for j in range(self._retry): + rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body) + if rt.status_code == 200: + break + return rt + + def complete_multipart_upload(self, Bucket, Key, UploadId="", **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) + for j in range(self._retry): + rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=data) + if rt.status_code == 200: + break + return rt class BucketInterface(object): @@ -156,7 +192,7 @@ def __init__(self, conf, session=None): else: self._session = session - def put_bucket(self, Bucket, **kwargs): + def create_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) for j in range(self._retry): @@ -175,6 +211,15 @@ def delete_bucket(self, Bucket, **kwargs): break return rt + def list_objects(self, Bucket ,**kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path="?max-keys=1") + for j in range(self._retry): + rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) + if rt.status_code == 200: + break + return rt + class CosS3Client(object): diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py new file mode 100644 index 00000000..3e868735 --- /dev/null +++ b/qcloud_cos/test.py @@ -0,0 +1,108 @@ +# -*- coding=utf-8 +from qcloud_cos import cos_client +import logging +import random +import sys +import os +import datetime +reload(sys) +sys.setdefaultencoding('utf-8') +logger = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(asctime)s - %(message)s") +access_id = "AKID15IsskiBQKTZbAo6WhgcBqVls9SmuG00" +access_key = "ciivKvnnrMvSvQpMAWuIz12pThGGlWRW" +file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) +file_list = [] +test_num = 20 + + +def gen_file(path, size): + file = open(path, 'w') + file.seek(1024*1024*size) + file.write('\x00') + file.close() + + +def setUp(): + print "config" + conf = cos_client.CosConfig( + appid="1252448703", + region="cn-north", + access_id=access_id, + access_key=access_key, + ) + client = cos_client.CosS3Client(conf) + global obj_int + obj_int = client.obj_int() + + conf = cos_client.CosConfig( + appid="1252448703", + region="cn-north", + access_id=access_id, + access_key=access_key, + ) + client = cos_client.CosS3Client(conf) + global buc_int + buc_int = client.buc_int() + +def tearDown(): + print "function teardown" + + +def Test(): + file_size = 3.1 + 0.1 + file_name = "tmp" + file_id + "_" + str(file_size) + "MB" + headers = { + 'Content-Encoding':'url'} + print "Test put " + file_name + sys.stdout.flush() + + conf = cos_client.CosConfig( + appid="1252448703", + region="cn-north", + access_id=access_id, + access_key=access_key, + ) + client = cos_client.CosS3Client(conf) + obj_int = client.obj_int() + rt = obj_int.put_object( + Bucket='lewzylu06', + Body='123'*1232, + Key=file_name, + CacheControl='string', + ContentDisposition='string', + ContentEncoding='string', + ContentLanguage='string', + ContentType='string') + assert rt.status_code==200 + + print "Test get " + file_name + rt = obj_int.get_object(Bucket='lewzylu06', + Key=file_name) + assert rt.status_code==200 + + print "Test delete " + file_name + rt = obj_int.delete_object( + Bucket='lewzylu06', + Key=file_name, + ) + assert rt.status_code==204 + + print "Test create bucket" + rt = buc_int.create_bucket( + Bucket='lewzylu999' + ) + + print "Test delete bucket" + rt = buc_int.delete_bucket( + Bucket='lewzylu999', + MaxKeys = '1' + ) + assert rt.status_code==204 + rt = buc_int.list_objects(Bucket='lewzylu06') + print rt.content + print rt.status_code + +if __name__ == "__main__": + setUp() + Test() From 4107a6f2a16d7529021fecd307794fb9c3863839 Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Tue, 25 Jul 2017 22:36:26 +0800 Subject: [PATCH 02/71] Combine two interface --- qcloud_cos/test.py | 50 ++++++++++++++++++---------------------------- tox.ini | 15 -------------- 2 files changed, 19 insertions(+), 46 deletions(-) delete mode 100644 tox.ini diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 3e868735..da115022 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -9,8 +9,6 @@ sys.setdefaultencoding('utf-8') logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(asctime)s - %(message)s") -access_id = "AKID15IsskiBQKTZbAo6WhgcBqVls9SmuG00" -access_key = "ciivKvnnrMvSvQpMAWuIz12pThGGlWRW" file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_list = [] test_num = 20 @@ -24,26 +22,7 @@ def gen_file(path, size): def setUp(): - print "config" - conf = cos_client.CosConfig( - appid="1252448703", - region="cn-north", - access_id=access_id, - access_key=access_key, - ) - client = cos_client.CosS3Client(conf) - global obj_int - obj_int = client.obj_int() - - conf = cos_client.CosConfig( - appid="1252448703", - region="cn-north", - access_id=access_id, - access_key=access_key, - ) - client = cos_client.CosS3Client(conf) - global buc_int - buc_int = client.buc_int() + print "start test" def tearDown(): print "function teardown" @@ -60,12 +39,11 @@ def Test(): conf = cos_client.CosConfig( appid="1252448703", region="cn-north", - access_id=access_id, - access_key=access_key, + access_id=ACCESS_ID, + access_key=ACCESS_KEY, ) client = cos_client.CosS3Client(conf) - obj_int = client.obj_int() - rt = obj_int.put_object( + rt = client.put_object( Bucket='lewzylu06', Body='123'*1232, Key=file_name, @@ -77,32 +55,42 @@ def Test(): assert rt.status_code==200 print "Test get " + file_name - rt = obj_int.get_object(Bucket='lewzylu06', + rt = client.get_object(Bucket='lewzylu06', Key=file_name) assert rt.status_code==200 print "Test delete " + file_name - rt = obj_int.delete_object( + rt = client.delete_object( Bucket='lewzylu06', Key=file_name, ) assert rt.status_code==204 + + + conf = cos_client.CosConfig( + appid="1252448703", + region="cn-north", + access_id=ACCESS_ID, + access_key=ACCESS_KEY, + ) + client = cos_client.CosS3Client(conf) print "Test create bucket" - rt = buc_int.create_bucket( + rt = client.create_bucket( Bucket='lewzylu999' ) print "Test delete bucket" - rt = buc_int.delete_bucket( + rt = client.delete_bucket( Bucket='lewzylu999', MaxKeys = '1' ) assert rt.status_code==204 - rt = buc_int.list_objects(Bucket='lewzylu06') + rt = client.list_objects(Bucket='lewzylu06') print rt.content print rt.status_code if __name__ == "__main__": setUp() Test() + diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 611174cd..00000000 --- a/tox.ini +++ /dev/null @@ -1,15 +0,0 @@ -[tox] -envlist = py26,py27 -[testenv] -deps= - requests - lxml - -commands= - coscmd -h - coscmd config -h - coscmd upload -h - coscmd config -a AKID52nXBd1vnTxHPOuwSmtobGixzpSstB1f -s ay9MVSGsIagct1SmygHgtuiLm14vc9Uh -u 1252448703 -b sdktestgz -r cn-south - # dd if=/dev/urandom of=10m.txt bs=1M count=10 - # coscmd -v upload 10m.txt upload/10m.txt - From 9c7941ca62738a5a8a1898f3d295591e6fb13f96 Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Tue, 25 Jul 2017 22:36:43 +0800 Subject: [PATCH 03/71] Update test file --- qcloud_cos/cos_auth.py | 4 +- qcloud_cos/cos_client.py | 140 ++++++++++++++++----------------------- qcloud_cos/test.py | 91 +++++++++++++------------ 3 files changed, 102 insertions(+), 133 deletions(-) diff --git a/qcloud_cos/cos_auth.py b/qcloud_cos/cos_auth.py index 6635cbb3..549cfe2d 100644 --- a/qcloud_cos/cos_auth.py +++ b/qcloud_cos/cos_auth.py @@ -4,13 +4,12 @@ import urllib import hashlib import logging -import requests from urllib import quote from urlparse import urlparse from requests.auth import AuthBase logger = logging.getLogger(__name__) -#fix a bug which can't send header + class CosS3Auth(AuthBase): def __init__(self, access_id, secret_key, expire=10000): @@ -72,4 +71,3 @@ def __call__(self, r): if __name__ == "__main__": url = 'http://lewzylu01-1252448703.cn-south.myqcloud.com/a.txt' - \ No newline at end of file diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 745bd2ad..7ccb6749 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -1,42 +1,37 @@ # -*- coding=utf-8 from cos_auth import CosS3Auth -from cos_threadpool import SimpleThreadPool -import time import requests -from os import path -from contextlib import closing -from xml.dom import minidom import logging import sys -import os import copy logger = logging.getLogger(__name__) fs_coding = sys.getfilesystemencoding() maplist = { - 'ContentLength':'Content-Length', - 'ContentType':'Content-Type', - 'ContentMD5':'Content-MD5', - 'CacheControl':'Cache-Control', - 'ContentDisposition':'Content-Disposition', - 'ContentEncoding':'Content-Encoding', - 'Expires':'Expires', - 'Metadata':'x-cos-meta- *', - 'ACL':'x-cos-acl', - 'GrantFullControl':'x-cos-grant-full-control', - 'GrantWrite':'x-cos-grant-write', - 'GrantRead':'x-cos-grant-read', - 'StorageClass':'x-cos-storage-class', - 'PartNumber':'partNumber', - 'UploadId':'uploadId', - 'Delimiter':'delimiter', - 'Marker':'marker', - 'MaxKeys':'max-keys', - 'Prefix':'prefix', - 'EncodingType':'encoding-type' + 'ContentLength': 'Content-Length', + 'ContentType': 'Content-Type', + 'ContentMD5': 'Content-MD5', + 'CacheControl': 'Cache-Control', + 'ContentDisposition': 'Content-Disposition', + 'ContentEncoding': 'Content-Encoding', + 'Expires': 'Expires', + 'Metadata': 'x-cos-meta- *', + 'ACL': 'x-cos-acl', + 'GrantFullControl': 'x-cos-grant-full-control', + 'GrantWrite': 'x-cos-grant-write', + 'GrantRead': 'x-cos-grant-read', + 'StorageClass': 'x-cos-storage-class', + 'PartNumber': 'partNumber', + 'UploadId': 'uploadId', + 'Delimiter': 'delimiter', + 'Marker': 'marker', + 'MaxKeys': 'max-keys', + 'Prefix': 'prefix', + 'EncodingType': 'encoding-type' } + def to_unicode(s): if isinstance(s, unicode): return s @@ -66,28 +61,26 @@ def getTagText(root, tag): if node.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE): rc = rc + node.data + def mapped(headers): - _headers = copy.copy(headers) + _headers = copy.copy(headers) for i in headers.keys(): if i in maplist: del _headers[i] _headers[maplist[i]] = headers[i] return _headers + class CosConfig(object): - def __init__(self, appid, region, access_id, access_key, part_size=1, max_thread=5, *args, **kwargs): - self._appid = appid - self._region = region - self._access_id = access_id - self._access_key = access_key - self._part_size = min(10, part_size) - self._max_thread = min(10, max_thread) - logger.info("config parameter-> appid: {appid}, region: {region}, part_size: {part_size}, max_thread: {max_thread}".format( - appid=appid, - region=region, - part_size=part_size, - max_thread=max_thread)) + def __init__(self, Appid, Region, Access_id, Access_key, *args, **kwargs): + self._appid = Appid + self._region = Region + self._access_id = Access_id + self._access_key = Access_key + logger.info("config parameter-> appid: {appid}, region: {region}".format( + appid=Appid, + region=Region)) def uri(self, bucket, path=None): if path: @@ -106,7 +99,7 @@ def uri(self, bucket, path=None): return url -class ObjectInterface(object): +class CosS3Client(object): def __init__(self, conf, session=None): self._conf = conf @@ -123,13 +116,11 @@ def __init__(self, conf, session=None): else: self._session = session - def put_object(self, Bucket, Body, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) for j in range(self._retry): - rt = self._session.put(url=url, - auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, headers=headers) + rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, headers=headers) if rt.status_code == 200: break return rt @@ -138,7 +129,7 @@ def get_object(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) for j in range(self._retry): - rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) + rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break return rt @@ -147,12 +138,12 @@ def delete_object(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) for j in range(self._retry): - rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) + rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 204: break return rt - - def create_multipart_upload(self, Bucket, Key, **kwargs): + + def create_multipart_upload(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploads") for j in range(self._retry): @@ -160,44 +151,30 @@ def create_multipart_upload(self, Bucket, Key, **kwargs): if rt.status_code == 200: break return rt - - def upload_part(self, Bucket, Key, PartNumber="", UploadId="", **kwargs): - headers,params = mapped(kwargs) + + def upload_part(self, Bucket, Key, Body, PartNumber="", UploadId="", **kwargs): + headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?partNumber={PartNumber}&uploadId={UploadId}".format(PartNumber=PartNumber, UploadId=UploadId)) for j in range(self._retry): rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body) if rt.status_code == 200: break return rt - + def complete_multipart_upload(self, Bucket, Key, UploadId="", **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) for j in range(self._retry): - rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=data) + rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break return rt -class BucketInterface(object): - - def __init__(self, conf, session=None): - self._conf = conf - self._upload_id = None - self._md5 = [] - self._have_finished = 0 - self._retry = 2 - if session is None: - self._session = requests.session() - else: - self._session = session - def create_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) for j in range(self._retry): - rt = self._session.put(url=url, - auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break return rt @@ -206,33 +183,28 @@ def delete_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) for j in range(self._retry): - rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) + rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 204: break return rt - def list_objects(self, Bucket ,**kwargs): + def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys="", Prefix="", **kwargs): headers = mapped(kwargs) - url = self._conf.uri(bucket=Bucket, path="?max-keys=1") + url = self._conf.uri(bucket=Bucket, + path='''?prefix={Prefix}&delimiter={Delimiter}&encoding-type={EncodingType}&marker={Marker}&max-keys={MaxKeys}'''.format( + Delimiter=Delimiter, + EncodingType=EncodingType, + Prefix=Prefix, + MaxKeys=MaxKeys, + Marker=Marker + ), + ) for j in range(self._retry): - rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) + rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) if rt.status_code == 200: break return rt -class CosS3Client(object): - - def __init__(self, conf): - self._conf = conf - self._session = requests.session() - - def obj_int(self, local_path='', cos_path=''): - return ObjectInterface(conf=self._conf, session=self._session) - - def buc_int(self): - return BucketInterface(conf=self._conf, session=self._session) - - if __name__ == "__main__": pass diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index da115022..ca43ce35 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -1,29 +1,30 @@ # -*- coding=utf-8 -from qcloud_cos import cos_client +import cos_client import logging import random import sys import os -import datetime -reload(sys) -sys.setdefaultencoding('utf-8') + logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(asctime)s - %(message)s") file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_list = [] test_num = 20 +ACCESS_ID = os.environ["ACCESS_ID"] +ACCESS_KEY = os.environ["ACCESS_KEY"] def gen_file(path, size): - file = open(path, 'w') - file.seek(1024*1024*size) - file.write('\x00') - file.close() + _file = open(path, 'w') + _file.seek(1024*1024*size) + _file.write('\x00') + _file.close() def setUp(): print "start test" + def tearDown(): print "function teardown" @@ -31,66 +32,64 @@ def tearDown(): def Test(): file_size = 3.1 + 0.1 file_name = "tmp" + file_id + "_" + str(file_size) + "MB" - headers = { - 'Content-Encoding':'url'} + headers = {'Content-Encoding': 'url'} print "Test put " + file_name sys.stdout.flush() - conf = cos_client.CosConfig( - appid="1252448703", - region="cn-north", - access_id=ACCESS_ID, - access_key=ACCESS_KEY, + Appid="1252448703", + Region="cn-north", + Access_id=ACCESS_ID, + Access_key=ACCESS_KEY, ) client = cos_client.CosS3Client(conf) rt = client.put_object( Bucket='lewzylu06', - Body='123'*1232, + Body='123'*1232, Key=file_name, CacheControl='string', ContentDisposition='string', ContentEncoding='string', ContentLanguage='string', - ContentType='string') - assert rt.status_code==200 - + ContentType='string' + ) + assert rt.status_code == 200 + print "Test get " + file_name rt = client.get_object(Bucket='lewzylu06', - Key=file_name) - assert rt.status_code==200 - + Key=file_name + ) + assert rt.status_code == 200 + print "Test delete " + file_name - rt = client.delete_object( - Bucket='lewzylu06', - Key=file_name, - ) - assert rt.status_code==204 - - - + rt = client.delete_object(Bucket='lewzylu06', + Key=file_name, + ) + assert rt.status_code == 204 + conf = cos_client.CosConfig( - appid="1252448703", - region="cn-north", - access_id=ACCESS_ID, - access_key=ACCESS_KEY, + Appid="1252448703", + Region="cn-north", + Access_id=ACCESS_ID, + Access_key=ACCESS_KEY, ) client = cos_client.CosS3Client(conf) print "Test create bucket" - rt = client.create_bucket( - Bucket='lewzylu999' - ) - + rt = client.create_bucket(Bucket='lewzylu999' + ) + assert rt.status_code == 200 print "Test delete bucket" - rt = client.delete_bucket( - Bucket='lewzylu999', - MaxKeys = '1' - ) - assert rt.status_code==204 - rt = client.list_objects(Bucket='lewzylu06') - print rt.content + rt = client.delete_bucket(Bucket='lewzylu999' + ) + assert rt.status_code == 204 + + print "Test list objects" + rt = client.list_objects(Bucket='lewzylu06', + MaxKeys='1', + ) print rt.status_code + assert rt.status_code == 200 + if __name__ == "__main__": setUp() Test() - From 3c0eef923590991f664ecdf61808c3027f2bbad7 Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Wed, 26 Jul 2017 15:12:41 +0800 Subject: [PATCH 04/71] Fix code format --- qcloud_cos/cos_client.py | 15 ++++++++------- qcloud_cos/test.py | 12 +++++++++--- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 7ccb6749..fc5135d5 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -191,13 +191,14 @@ def delete_bucket(self, Bucket, **kwargs): def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys="", Prefix="", **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, - path='''?prefix={Prefix}&delimiter={Delimiter}&encoding-type={EncodingType}&marker={Marker}&max-keys={MaxKeys}'''.format( - Delimiter=Delimiter, - EncodingType=EncodingType, - Prefix=Prefix, - MaxKeys=MaxKeys, - Marker=Marker - ), + path='''?prefix={Prefix}&delimiter={Delimiter}&encoding-type={EncodingType}&marker={Marker}&max-keys={MaxKeys}''' + .format( + Delimiter=Delimiter, + EncodingType=EncodingType, + Prefix=Prefix, + MaxKeys=MaxKeys, + Marker=Marker + ), ) for j in range(self._retry): rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index ca43ce35..284949dc 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -83,9 +83,15 @@ def Test(): assert rt.status_code == 204 print "Test list objects" - rt = client.list_objects(Bucket='lewzylu06', - MaxKeys='1', - ) + rt = client.list_objects( + Bucket='lewzylu06', + Delimiter='string', + EncodingType='url', + Marker='string', + MaxKeys=123, + Prefix='string', + MaxKeys='1', + ) print rt.status_code assert rt.status_code == 200 From 6b6ba0543c740c142e95df3f307a90c14bd85f52 Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Wed, 26 Jul 2017 15:15:09 +0800 Subject: [PATCH 05/71] Update test file --- qcloud_cos/test.py | 119 ++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 60 deletions(-) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 284949dc..412cebda 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -30,70 +30,69 @@ def tearDown(): def Test(): - file_size = 3.1 + 0.1 - file_name = "tmp" + file_id + "_" + str(file_size) + "MB" - headers = {'Content-Encoding': 'url'} - print "Test put " + file_name - sys.stdout.flush() - conf = cos_client.CosConfig( - Appid="1252448703", - Region="cn-north", - Access_id=ACCESS_ID, - Access_key=ACCESS_KEY, - ) - client = cos_client.CosS3Client(conf) - rt = client.put_object( - Bucket='lewzylu06', - Body='123'*1232, - Key=file_name, - CacheControl='string', - ContentDisposition='string', - ContentEncoding='string', - ContentLanguage='string', - ContentType='string' - ) - assert rt.status_code == 200 + for i in range(test_num): + file_size = 3.1 + 0.1 + file_name = "tmp" + file_id + "_" + str(file_size) + "MB" + headers = {'Content-Encoding': 'url'} + print "Test put " + file_name + conf = cos_client.CosConfig( + Appid="1252448703", + Region="cn-north", + Access_id=ACCESS_ID, + Access_key=ACCESS_KEY, + ) + client = cos_client.CosS3Client(conf) + rt = client.put_object( + Bucket='lewzylu06', + Body='123'*1232, + Key=file_name, + CacheControl='string', + ContentDisposition='string', + ContentEncoding='string', + ContentLanguage='string', + ContentType='string' + ) + assert rt.status_code == 200 - print "Test get " + file_name - rt = client.get_object(Bucket='lewzylu06', - Key=file_name - ) - assert rt.status_code == 200 + print "Test get " + file_name + rt = client.get_object(Bucket='lewzylu06', + Key=file_name + ) + assert rt.status_code == 200 - print "Test delete " + file_name - rt = client.delete_object(Bucket='lewzylu06', - Key=file_name, - ) - assert rt.status_code == 204 + print "Test delete " + file_name + rt = client.delete_object(Bucket='lewzylu06', + Key=file_name, + ) + assert rt.status_code == 204 - conf = cos_client.CosConfig( - Appid="1252448703", - Region="cn-north", - Access_id=ACCESS_ID, - Access_key=ACCESS_KEY, - ) - client = cos_client.CosS3Client(conf) - print "Test create bucket" - rt = client.create_bucket(Bucket='lewzylu999' - ) - assert rt.status_code == 200 - print "Test delete bucket" - rt = client.delete_bucket(Bucket='lewzylu999' - ) - assert rt.status_code == 204 + conf = cos_client.CosConfig( + Appid="1252448703", + Region="cn-north", + Access_id=ACCESS_ID, + Access_key=ACCESS_KEY, + ) + client = cos_client.CosS3Client(conf) + print "Test create bucket" + rt = client.create_bucket(Bucket='lewzylu999' + ) + assert rt.status_code == 200 + print "Test delete bucket" + rt = client.delete_bucket(Bucket='lewzylu999' + ) + assert rt.status_code == 204 - print "Test list objects" - rt = client.list_objects( - Bucket='lewzylu06', - Delimiter='string', - EncodingType='url', - Marker='string', - MaxKeys=123, - Prefix='string', - MaxKeys='1', - ) - print rt.status_code - assert rt.status_code == 200 + print "Test list objects" + rt = client.list_objects( + Bucket='lewzylu06', + Delimiter='string', + EncodingType='url', + Marker='string', + Prefix='string', + MaxKeys='1', + ) + print rt.status_code + assert rt.status_code == 200 if __name__ == "__main__": From db768e4fa22f8a4702ad065c941772f8a1a303bc Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Wed, 26 Jul 2017 15:19:02 +0800 Subject: [PATCH 06/71] Update test file --- qcloud_cos/test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 412cebda..cab34b8a 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -85,13 +85,12 @@ def Test(): print "Test list objects" rt = client.list_objects( Bucket='lewzylu06', - Delimiter='string', + Delimiter='', EncodingType='url', Marker='string', Prefix='string', MaxKeys='1', ) - print rt.status_code assert rt.status_code == 200 From 2a1a2af984973d30c40a81c7b5a5ac2c23c424bb Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Wed, 26 Jul 2017 15:44:22 +0800 Subject: [PATCH 07/71] Update test file --- qcloud_cos/test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index cab34b8a..561a9dcc 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -9,7 +9,7 @@ logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(asctime)s - %(message)s") file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_list = [] -test_num = 20 +test_num = 10 ACCESS_ID = os.environ["ACCESS_ID"] ACCESS_KEY = os.environ["ACCESS_KEY"] @@ -31,7 +31,7 @@ def tearDown(): def Test(): for i in range(test_num): - file_size = 3.1 + 0.1 + file_size = i + 0.1 file_name = "tmp" + file_id + "_" + str(file_size) + "MB" headers = {'Content-Encoding': 'url'} print "Test put " + file_name From 27ba583fb2f55a22e6222a06e392e658f1f66c53 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 27 Jul 2017 21:18:46 +0800 Subject: [PATCH 08/71] write the log and uttest --- qcloud_cos/cos_auth.py | 2 +- qcloud_cos/cos_client.py | 150 ++++++++++++++++++------ qcloud_cos/test.py | 239 +++++++++++++++++++++++---------------- 3 files changed, 261 insertions(+), 130 deletions(-) diff --git a/qcloud_cos/cos_auth.py b/qcloud_cos/cos_auth.py index 549cfe2d..0f49b635 100644 --- a/qcloud_cos/cos_auth.py +++ b/qcloud_cos/cos_auth.py @@ -70,4 +70,4 @@ def __call__(self, r): if __name__ == "__main__": - url = 'http://lewzylu01-1252448703.cn-south.myqcloud.com/a.txt' + pass diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 7ccb6749..2211bdb8 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -4,6 +4,14 @@ import logging import sys import copy +import xml.dom.minidom + + +logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', + datefmt='%a, %d %b %Y %H:%M:%S', + filename='cos_s3.log', + filemode='w') logger = logging.getLogger(__name__) fs_coding = sys.getfilesystemencoding() @@ -38,42 +46,48 @@ def to_unicode(s): else: return s.decode(fs_coding) +def dict_to_xml(data): + doc = xml.dom.minidom.Document() + root = doc.createElement('CompleteMultipartUpload') + doc.appendChild(root) -def to_printable_str(s): - if isinstance(s, unicode): - return s.encode(fs_coding) - else: - return s + if 'Parts' not in data.keys(): + logger.error("Invalid Parameter, Parts Is Required!") + return '' + + for i in data['Parts']: + nodePart = doc.createElement('Part') + if 'PartNumber' not in i.keys(): + logger.error("Invalid Parameter, PartNumber Is Required!") + return '' -def view_bar(num, total): - ret = 1.0*num / total - ag = ret * 100 - ab = "\r [%-50s]%.2f%%" % ('='*int(ret*50), ag, ) - sys.stdout.write(ab) - sys.stdout.flush() + nodeNumber = doc.createElement('PartNumber') + nodeNumber.appendChild(doc.createTextNode(str(i['PartNumber']))) + if 'ETag' not in i.keys(): + logger.error("Invalid Parameter, ETag Is Required!") + return '' -def getTagText(root, tag): - node = root.getElementsByTagName(tag)[0] - rc = "" - for node in node.childNodes: - if node.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE): - rc = rc + node.data + nodeETag = doc.createElement('ETag') + nodeETag.appendChild(doc.createTextNode(str(i['ETag']))) + + nodePart.appendChild(nodeNumber) + nodePart.appendChild(nodeETag) + root.appendChild(nodePart) + return doc.toxml('utf-8') def mapped(headers): - _headers = copy.copy(headers) + _headers = dict() for i in headers.keys(): if i in maplist: - del _headers[i] _headers[maplist[i]] = headers[i] return _headers - class CosConfig(object): - def __init__(self, Appid, Region, Access_id, Access_key, *args, **kwargs): + def __init__(self, Appid, Region, Access_id, Access_key): self._appid = Appid self._region = Region self._access_id = Access_id @@ -107,7 +121,7 @@ def __init__(self, conf, session=None): self._headers = [] self._params = [] self._md5 = [] - self._retry = 2 + self._retry = 1 self._file_num = 0 self._folder_num = 0 self._have_finished = 0 @@ -119,90 +133,158 @@ def __init__(self, conf, session=None): def put_object(self, Bucket, Body, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("put object, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, headers=headers) if rt.status_code == 200: break + logger.error(rt.headers) + return rt def get_object(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("get object, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break + logger.error(rt.headers) return rt def delete_object(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("delete object, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 204: break + logger.error(rt.headers) return rt def create_multipart_upload(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploads") + logger.info("create multipart upload, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.post(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) if rt.status_code == 200: break + logger.error(rt.headers) return rt - def upload_part(self, Bucket, Key, Body, PartNumber="", UploadId="", **kwargs): + def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?partNumber={PartNumber}&uploadId={UploadId}".format(PartNumber=PartNumber, UploadId=UploadId)) + logger.info("put object, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body) if rt.status_code == 200: break + logger.error(rt.headers) return rt - def complete_multipart_upload(self, Bucket, Key, UploadId="", **kwargs): + def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload = {}, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) + logger.info("complete multipart upload, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): - rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=dict_to_xml(MultipartUpload), headers=headers) if rt.status_code == 200: break + logger.error(rt.headers) return rt + def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) + logger.info("abort multipart upload, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) + for j in range(self._retry): + rt = self._session.delete(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + if rt.status_code == 200: + break + logger.error(rt.headers) + return rt + + def list_parts(self, Bucket, Key, UploadId, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) + logger.info("list multipart upload, url=:{url} ,headers=:{headers}".format( + url = url, + headers = headers)) + for j in range(self._retry): + rt = self._session.get(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + if rt.status_code == 200: + break + logger.error(rt.headers) + return rt + def create_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) + logger.info("create bucket, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break + logger.error(rt.headers) return rt def delete_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) + logger.info("delete bucket, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 204: break + logger.error(rt.headers) return rt def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys="", Prefix="", **kwargs): headers = mapped(kwargs) - url = self._conf.uri(bucket=Bucket, - path='''?prefix={Prefix}&delimiter={Delimiter}&encoding-type={EncodingType}&marker={Marker}&max-keys={MaxKeys}'''.format( - Delimiter=Delimiter, - EncodingType=EncodingType, - Prefix=Prefix, - MaxKeys=MaxKeys, - Marker=Marker - ), - ) + url = self._conf.uri(bucket=Bucket) + logger.info("list objects, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) if rt.status_code == 200: break + logger.error(rt.headers) + return rt + + def head_object(self, Bucket, Key): + headers = '' + url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("put object, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) + for j in range(self._retry): + rt = self._session.head(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) + if rt.status_code == 200: + break + logger.error(rt.headers) return rt diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index ca43ce35..97dad441 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -1,95 +1,144 @@ -# -*- coding=utf-8 -import cos_client -import logging -import random -import sys -import os - -logger = logging.getLogger(__name__) -logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(asctime)s - %(message)s") -file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) -file_list = [] -test_num = 20 -ACCESS_ID = os.environ["ACCESS_ID"] -ACCESS_KEY = os.environ["ACCESS_KEY"] - - -def gen_file(path, size): - _file = open(path, 'w') - _file.seek(1024*1024*size) - _file.write('\x00') - _file.close() - - -def setUp(): - print "start test" - - -def tearDown(): - print "function teardown" - - -def Test(): - file_size = 3.1 + 0.1 - file_name = "tmp" + file_id + "_" + str(file_size) + "MB" - headers = {'Content-Encoding': 'url'} - print "Test put " + file_name - sys.stdout.flush() - conf = cos_client.CosConfig( - Appid="1252448703", - Region="cn-north", - Access_id=ACCESS_ID, - Access_key=ACCESS_KEY, - ) - client = cos_client.CosS3Client(conf) - rt = client.put_object( - Bucket='lewzylu06', - Body='123'*1232, - Key=file_name, - CacheControl='string', - ContentDisposition='string', - ContentEncoding='string', - ContentLanguage='string', - ContentType='string' - ) - assert rt.status_code == 200 - - print "Test get " + file_name - rt = client.get_object(Bucket='lewzylu06', - Key=file_name - ) - assert rt.status_code == 200 - - print "Test delete " + file_name - rt = client.delete_object(Bucket='lewzylu06', - Key=file_name, - ) - assert rt.status_code == 204 - - conf = cos_client.CosConfig( - Appid="1252448703", - Region="cn-north", - Access_id=ACCESS_ID, - Access_key=ACCESS_KEY, - ) - client = cos_client.CosS3Client(conf) - print "Test create bucket" - rt = client.create_bucket(Bucket='lewzylu999' - ) - assert rt.status_code == 200 - print "Test delete bucket" - rt = client.delete_bucket(Bucket='lewzylu999' - ) - assert rt.status_code == 204 - - print "Test list objects" - rt = client.list_objects(Bucket='lewzylu06', - MaxKeys='1', - ) - print rt.status_code - assert rt.status_code == 200 - - -if __name__ == "__main__": - setUp() - Test() +import cos_client +import random +import sys +import os +import xml.dom.minidom +from xml.dom.minidom import parse +from cos_client import CosS3Client +from cos_client import CosConfig + +#ACCESS_ID = os.environ["ACCESS_ID"] +#ACCESS_KEY = os.environ["ACCESS_KEY"] + +def gen_file(path, size): + _file = open(path, 'w') + _file.seek(1024*1024*size) + _file.write('cos') + _file.close() + +def get_id_from_xml(data): + tree = xml.dom.minidom.parseString(data) + root = tree.documentElement + result = root.getElementsByTagName('UploadId') + # use childNodes to get a list, if has no child get itself + return result[0].childNodes[0].nodeValue + +def setUp(): + print "start test" + +def tearDown(): + print "function teardown" + + +def Test(): + conf = CosConfig( + Appid="1252448703", + Region="cn-north", + Access_id='AKID15IsskiBQKTZbAo6WhgcBqVls9SmuG00', + Access_key='ciivKvnnrMvSvQpMAWuIz12pThGGlWRW' + ) + client = cos_client.CosS3Client(conf) + + file_size = 2 + file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) + file_name = "tmp" + file_id + "_" + str(file_size) + "MB" + + print "Test Put Object " + file_name + response = client.put_object( + Bucket='test01', + Body='TY'*1024*512*file_size, + Key=file_name, + CacheControl = 'no-cache', + ContentDisposition = 'download.txt', + ACL = 'public-read' + ) + assert response.status_code == 200 + + print "Test Get Object " + file_name + response = client.get_object( + Bucket='test01', + Key=file_name, + ) + assert response.status_code == 200 + + print "Test Head Object " + file_name + response = client.head_object( + Bucket='test01', + Key=file_name + ) + assert response.status_code == 200 + + print "Test Delete Object " + file_name + response = client.delete_object( + Bucket='test01', + Key=file_name + ) + assert response.status_code == 204 + + print "Test List Objects" + response = client.list_objects( + Bucket='test01' + ) + assert response.status_code == 200 + + print "Test Create Bucket" + response = client.create_bucket( + Bucket='test02', + ACL = 'public-read' + ) + assert response.status_code == 200 + + print "Test Delete Bucket" + response = client.delete_bucket( + Bucket='test02' + ) + assert response.status_code == 204 + + print "Test Create MultipartUpload" + response = client.create_multipart_upload( + Bucket='test01', + Key = 'multipartfile.txt', + ) + assert response.status_code == 200 + uploadid = get_id_from_xml(response.text) + + + print "Test Abort MultipartUpload" + response = client.abort_multipart_upload( + Bucket='test01', + Key = 'multipartfile.txt', + UploadId = uploadid + ) + assert response.status_code == 200 + + print "Test Create MultipartUpload" + response = client.create_multipart_upload( + Bucket='test01', + Key = 'multipartfile.txt', + ) + uploadid = get_id_from_xml(response.text) + assert response.status_code == 200 + + print "Test Upload Part" + response = client.upload_part( + Bucket='test01', + Key = 'multipartfile.txt', + UploadId = uploadid, + PartNumber = 1, + Body = 'A'*1024*1024*4 + ) + etag = response.headers['ETag'] + assert response.status_code == 200 + + print "Test Complete MultipartUpload" + response = client.complete_multipart_upload( + Bucket='test01', + Key = 'multipartfile.txt', + UploadId = uploadid, + MultipartUpload = {'Parts':[{'PartNumber':1, 'ETag':etag}]} + ) + assert response.status_code == 200 + +if __name__ == "__main__": + setUp() + Test() From e3506a128e6c418dfd9dcdc8a51079e236b537df Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 27 Jul 2017 21:21:42 +0800 Subject: [PATCH 09/71] write uttest --- qcloud_cos/test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 97dad441..fc331214 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -7,8 +7,8 @@ from cos_client import CosS3Client from cos_client import CosConfig -#ACCESS_ID = os.environ["ACCESS_ID"] -#ACCESS_KEY = os.environ["ACCESS_KEY"] +ACCESS_ID = os.environ["ACCESS_ID"] +ACCESS_KEY = os.environ["ACCESS_KEY"] def gen_file(path, size): _file = open(path, 'w') @@ -34,8 +34,8 @@ def Test(): conf = CosConfig( Appid="1252448703", Region="cn-north", - Access_id='AKID15IsskiBQKTZbAo6WhgcBqVls9SmuG00', - Access_key='ciivKvnnrMvSvQpMAWuIz12pThGGlWRW' + Access_id=ACCESS_ID, + Access_key=ACCESS_KEY ) client = cos_client.CosS3Client(conf) From 34d2bcc973544e63a8de25103991394a13301860 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 27 Jul 2017 21:42:57 +0800 Subject: [PATCH 10/71] fix the ut --- qcloud_cos/test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index fc331214..1920a3be 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -1,3 +1,4 @@ +# -*- coding=utf-8 import cos_client import random import sys From 457d72e00410d3db8c2d11c075f355f3d0c8e152 Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Mon, 24 Jul 2017 23:41:35 +0800 Subject: [PATCH 11/71] Update intface --- qcloud_cos/cos_client.py | 67 +++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index f005c47b..955182b8 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -9,10 +9,22 @@ import logging import sys import os +import copy logger = logging.getLogger(__name__) fs_coding = sys.getfilesystemencoding() +maplist = {'CacheControl':'Cache-Control', + 'ContentDisposition':'Content-Disposition', + 'ContentEncoding':'Content-Encoding', + 'Expires':'Expires', + 'Metadata':'x-cos-meta- *', + 'ACL':'x-cos-acl', + 'GrantFullControl':'x-cos-grant-full-control', + 'GrantWrite':'x-cos-grant-write', + 'GrantRead':'x-cos-grant-read', + 'StorageClass':'x-cos-storage-class', + } def to_unicode(s): if isinstance(s, unicode): @@ -43,35 +55,40 @@ def getTagText(root, tag): if node.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE): rc = rc + node.data +def mapped(headers): + _headers = copy.copy(headers) + for i in headers.keys(): + if i in maplist: + del _headers[i] + _headers[maplist[i]] = headers[i] + return _headers class CosConfig(object): - def __init__(self, appid, region, bucket, access_id, access_key, part_size=1, max_thread=5, *args, **kwargs): + def __init__(self, appid, region, access_id, access_key, part_size=1, max_thread=5, *args, **kwargs): self._appid = appid self._region = region - self._bucket = bucket self._access_id = access_id self._access_key = access_key self._part_size = min(10, part_size) self._max_thread = min(10, max_thread) - logger.info("config parameter-> appid: {appid}, region: {region}, bucket: {bucket}, part_size: {part_size}, max_thread: {max_thread}".format( + logger.info("config parameter-> appid: {appid}, region: {region}, part_size: {part_size}, max_thread: {max_thread}".format( appid=appid, region=region, - bucket=bucket, part_size=part_size, max_thread=max_thread)) - def uri(self, path=None): + def uri(self, bucket, path=None): if path: url = u"http://{bucket}-{uid}.{region}.myqcloud.com/{path}".format( - bucket=self._bucket, + bucket=to_unicode(bucket), uid=self._appid, region=self._region, path=to_unicode(path) ) else: url = u"http://{bucket}-{uid}.{region}.myqcloud.com".format( - bucket=self._bucket, + bucket=to_unicode(bucket), uid=self._appid, region=self._region ) @@ -96,32 +113,36 @@ def __init__(self, conf, session=None): self._session = session - def put_object(self, Body, Key, **kwargs): - url = self._conf.uri(path=Key) + def put_object(self, Bucket, Body, Key, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key) for j in range(self._retry): rt = self._session.put(url=url, - auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, headers=kwargs['headers']) + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, headers=headers) if rt.status_code == 200: break return rt - def get_object(self, Key, **kwargs): - url = self._conf.uri(path=Key) + def get_object(self, Bucket, Key, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key) for j in range(self._retry): - rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=kwargs['headers']) + rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) if rt.status_code == 200: break return rt - def delete_object(self, Key, **kwargs): - url = self._conf.uri(path=Key) + def delete_object(self, Bucket, Key, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key) for j in range(self._retry): - rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=kwargs['headers']) + rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) if rt.status_code == 204: break return rt + class BucketInterface(object): def __init__(self, conf, session=None): @@ -135,19 +156,21 @@ def __init__(self, conf, session=None): else: self._session = session - def put_bucket(self, **kwargs): - url = self._conf.uri(path='') + def put_bucket(self, Bucket, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket) for j in range(self._retry): rt = self._session.put(url=url, - auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=kwargs['headers']) + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break return rt - def delete_bucket(self, Key, **kwargs): - url = self._conf.uri(path='') + def delete_bucket(self, Bucket, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket) for j in range(self._retry): - rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=kwargs['headers']) + rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) if rt.status_code == 204: break return rt From e02086a064c20908640a0c15834b5b097cb15a70 Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Tue, 25 Jul 2017 22:12:58 +0800 Subject: [PATCH 12/71] Add test File --- qcloud_cos/cos_client.py | 53 +++++++++++++++++-- qcloud_cos/test.py | 108 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 qcloud_cos/test.py diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 955182b8..745bd2ad 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -14,7 +14,11 @@ logger = logging.getLogger(__name__) fs_coding = sys.getfilesystemencoding() -maplist = {'CacheControl':'Cache-Control', +maplist = { + 'ContentLength':'Content-Length', + 'ContentType':'Content-Type', + 'ContentMD5':'Content-MD5', + 'CacheControl':'Cache-Control', 'ContentDisposition':'Content-Disposition', 'ContentEncoding':'Content-Encoding', 'Expires':'Expires', @@ -24,6 +28,13 @@ 'GrantWrite':'x-cos-grant-write', 'GrantRead':'x-cos-grant-read', 'StorageClass':'x-cos-storage-class', + 'PartNumber':'partNumber', + 'UploadId':'uploadId', + 'Delimiter':'delimiter', + 'Marker':'marker', + 'MaxKeys':'max-keys', + 'Prefix':'prefix', + 'EncodingType':'encoding-type' } def to_unicode(s): @@ -140,8 +151,33 @@ def delete_object(self, Bucket, Key, **kwargs): if rt.status_code == 204: break return rt - - + + def create_multipart_upload(self, Bucket, Key, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?uploads") + for j in range(self._retry): + rt = self._session.post(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) + if rt.status_code == 200: + break + return rt + + def upload_part(self, Bucket, Key, PartNumber="", UploadId="", **kwargs): + headers,params = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?partNumber={PartNumber}&uploadId={UploadId}".format(PartNumber=PartNumber, UploadId=UploadId)) + for j in range(self._retry): + rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body) + if rt.status_code == 200: + break + return rt + + def complete_multipart_upload(self, Bucket, Key, UploadId="", **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) + for j in range(self._retry): + rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=data) + if rt.status_code == 200: + break + return rt class BucketInterface(object): @@ -156,7 +192,7 @@ def __init__(self, conf, session=None): else: self._session = session - def put_bucket(self, Bucket, **kwargs): + def create_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) for j in range(self._retry): @@ -175,6 +211,15 @@ def delete_bucket(self, Bucket, **kwargs): break return rt + def list_objects(self, Bucket ,**kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path="?max-keys=1") + for j in range(self._retry): + rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) + if rt.status_code == 200: + break + return rt + class CosS3Client(object): diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py new file mode 100644 index 00000000..3e868735 --- /dev/null +++ b/qcloud_cos/test.py @@ -0,0 +1,108 @@ +# -*- coding=utf-8 +from qcloud_cos import cos_client +import logging +import random +import sys +import os +import datetime +reload(sys) +sys.setdefaultencoding('utf-8') +logger = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(asctime)s - %(message)s") +access_id = "AKID15IsskiBQKTZbAo6WhgcBqVls9SmuG00" +access_key = "ciivKvnnrMvSvQpMAWuIz12pThGGlWRW" +file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) +file_list = [] +test_num = 20 + + +def gen_file(path, size): + file = open(path, 'w') + file.seek(1024*1024*size) + file.write('\x00') + file.close() + + +def setUp(): + print "config" + conf = cos_client.CosConfig( + appid="1252448703", + region="cn-north", + access_id=access_id, + access_key=access_key, + ) + client = cos_client.CosS3Client(conf) + global obj_int + obj_int = client.obj_int() + + conf = cos_client.CosConfig( + appid="1252448703", + region="cn-north", + access_id=access_id, + access_key=access_key, + ) + client = cos_client.CosS3Client(conf) + global buc_int + buc_int = client.buc_int() + +def tearDown(): + print "function teardown" + + +def Test(): + file_size = 3.1 + 0.1 + file_name = "tmp" + file_id + "_" + str(file_size) + "MB" + headers = { + 'Content-Encoding':'url'} + print "Test put " + file_name + sys.stdout.flush() + + conf = cos_client.CosConfig( + appid="1252448703", + region="cn-north", + access_id=access_id, + access_key=access_key, + ) + client = cos_client.CosS3Client(conf) + obj_int = client.obj_int() + rt = obj_int.put_object( + Bucket='lewzylu06', + Body='123'*1232, + Key=file_name, + CacheControl='string', + ContentDisposition='string', + ContentEncoding='string', + ContentLanguage='string', + ContentType='string') + assert rt.status_code==200 + + print "Test get " + file_name + rt = obj_int.get_object(Bucket='lewzylu06', + Key=file_name) + assert rt.status_code==200 + + print "Test delete " + file_name + rt = obj_int.delete_object( + Bucket='lewzylu06', + Key=file_name, + ) + assert rt.status_code==204 + + print "Test create bucket" + rt = buc_int.create_bucket( + Bucket='lewzylu999' + ) + + print "Test delete bucket" + rt = buc_int.delete_bucket( + Bucket='lewzylu999', + MaxKeys = '1' + ) + assert rt.status_code==204 + rt = buc_int.list_objects(Bucket='lewzylu06') + print rt.content + print rt.status_code + +if __name__ == "__main__": + setUp() + Test() From e6775719d0cc784b058537bed658d0195d9eb694 Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Tue, 25 Jul 2017 22:36:26 +0800 Subject: [PATCH 13/71] Combine two interface --- qcloud_cos/test.py | 50 ++++++++++++++++++---------------------------- tox.ini | 15 -------------- 2 files changed, 19 insertions(+), 46 deletions(-) delete mode 100644 tox.ini diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 3e868735..da115022 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -9,8 +9,6 @@ sys.setdefaultencoding('utf-8') logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(asctime)s - %(message)s") -access_id = "AKID15IsskiBQKTZbAo6WhgcBqVls9SmuG00" -access_key = "ciivKvnnrMvSvQpMAWuIz12pThGGlWRW" file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_list = [] test_num = 20 @@ -24,26 +22,7 @@ def gen_file(path, size): def setUp(): - print "config" - conf = cos_client.CosConfig( - appid="1252448703", - region="cn-north", - access_id=access_id, - access_key=access_key, - ) - client = cos_client.CosS3Client(conf) - global obj_int - obj_int = client.obj_int() - - conf = cos_client.CosConfig( - appid="1252448703", - region="cn-north", - access_id=access_id, - access_key=access_key, - ) - client = cos_client.CosS3Client(conf) - global buc_int - buc_int = client.buc_int() + print "start test" def tearDown(): print "function teardown" @@ -60,12 +39,11 @@ def Test(): conf = cos_client.CosConfig( appid="1252448703", region="cn-north", - access_id=access_id, - access_key=access_key, + access_id=ACCESS_ID, + access_key=ACCESS_KEY, ) client = cos_client.CosS3Client(conf) - obj_int = client.obj_int() - rt = obj_int.put_object( + rt = client.put_object( Bucket='lewzylu06', Body='123'*1232, Key=file_name, @@ -77,32 +55,42 @@ def Test(): assert rt.status_code==200 print "Test get " + file_name - rt = obj_int.get_object(Bucket='lewzylu06', + rt = client.get_object(Bucket='lewzylu06', Key=file_name) assert rt.status_code==200 print "Test delete " + file_name - rt = obj_int.delete_object( + rt = client.delete_object( Bucket='lewzylu06', Key=file_name, ) assert rt.status_code==204 + + + conf = cos_client.CosConfig( + appid="1252448703", + region="cn-north", + access_id=ACCESS_ID, + access_key=ACCESS_KEY, + ) + client = cos_client.CosS3Client(conf) print "Test create bucket" - rt = buc_int.create_bucket( + rt = client.create_bucket( Bucket='lewzylu999' ) print "Test delete bucket" - rt = buc_int.delete_bucket( + rt = client.delete_bucket( Bucket='lewzylu999', MaxKeys = '1' ) assert rt.status_code==204 - rt = buc_int.list_objects(Bucket='lewzylu06') + rt = client.list_objects(Bucket='lewzylu06') print rt.content print rt.status_code if __name__ == "__main__": setUp() Test() + diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 611174cd..00000000 --- a/tox.ini +++ /dev/null @@ -1,15 +0,0 @@ -[tox] -envlist = py26,py27 -[testenv] -deps= - requests - lxml - -commands= - coscmd -h - coscmd config -h - coscmd upload -h - coscmd config -a AKID52nXBd1vnTxHPOuwSmtobGixzpSstB1f -s ay9MVSGsIagct1SmygHgtuiLm14vc9Uh -u 1252448703 -b sdktestgz -r cn-south - # dd if=/dev/urandom of=10m.txt bs=1M count=10 - # coscmd -v upload 10m.txt upload/10m.txt - From 8f3d80d8a5d41e58f11c95418d2f5620781d1a00 Mon Sep 17 00:00:00 2001 From: lewzylu <327874225@qq.com> Date: Tue, 25 Jul 2017 22:36:43 +0800 Subject: [PATCH 14/71] Update test file --- qcloud_cos/cos_auth.py | 4 +- qcloud_cos/cos_client.py | 140 ++++++++++++++++----------------------- qcloud_cos/test.py | 91 +++++++++++++------------ 3 files changed, 102 insertions(+), 133 deletions(-) diff --git a/qcloud_cos/cos_auth.py b/qcloud_cos/cos_auth.py index 6635cbb3..549cfe2d 100644 --- a/qcloud_cos/cos_auth.py +++ b/qcloud_cos/cos_auth.py @@ -4,13 +4,12 @@ import urllib import hashlib import logging -import requests from urllib import quote from urlparse import urlparse from requests.auth import AuthBase logger = logging.getLogger(__name__) -#fix a bug which can't send header + class CosS3Auth(AuthBase): def __init__(self, access_id, secret_key, expire=10000): @@ -72,4 +71,3 @@ def __call__(self, r): if __name__ == "__main__": url = 'http://lewzylu01-1252448703.cn-south.myqcloud.com/a.txt' - \ No newline at end of file diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 745bd2ad..7ccb6749 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -1,42 +1,37 @@ # -*- coding=utf-8 from cos_auth import CosS3Auth -from cos_threadpool import SimpleThreadPool -import time import requests -from os import path -from contextlib import closing -from xml.dom import minidom import logging import sys -import os import copy logger = logging.getLogger(__name__) fs_coding = sys.getfilesystemencoding() maplist = { - 'ContentLength':'Content-Length', - 'ContentType':'Content-Type', - 'ContentMD5':'Content-MD5', - 'CacheControl':'Cache-Control', - 'ContentDisposition':'Content-Disposition', - 'ContentEncoding':'Content-Encoding', - 'Expires':'Expires', - 'Metadata':'x-cos-meta- *', - 'ACL':'x-cos-acl', - 'GrantFullControl':'x-cos-grant-full-control', - 'GrantWrite':'x-cos-grant-write', - 'GrantRead':'x-cos-grant-read', - 'StorageClass':'x-cos-storage-class', - 'PartNumber':'partNumber', - 'UploadId':'uploadId', - 'Delimiter':'delimiter', - 'Marker':'marker', - 'MaxKeys':'max-keys', - 'Prefix':'prefix', - 'EncodingType':'encoding-type' + 'ContentLength': 'Content-Length', + 'ContentType': 'Content-Type', + 'ContentMD5': 'Content-MD5', + 'CacheControl': 'Cache-Control', + 'ContentDisposition': 'Content-Disposition', + 'ContentEncoding': 'Content-Encoding', + 'Expires': 'Expires', + 'Metadata': 'x-cos-meta- *', + 'ACL': 'x-cos-acl', + 'GrantFullControl': 'x-cos-grant-full-control', + 'GrantWrite': 'x-cos-grant-write', + 'GrantRead': 'x-cos-grant-read', + 'StorageClass': 'x-cos-storage-class', + 'PartNumber': 'partNumber', + 'UploadId': 'uploadId', + 'Delimiter': 'delimiter', + 'Marker': 'marker', + 'MaxKeys': 'max-keys', + 'Prefix': 'prefix', + 'EncodingType': 'encoding-type' } + def to_unicode(s): if isinstance(s, unicode): return s @@ -66,28 +61,26 @@ def getTagText(root, tag): if node.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE): rc = rc + node.data + def mapped(headers): - _headers = copy.copy(headers) + _headers = copy.copy(headers) for i in headers.keys(): if i in maplist: del _headers[i] _headers[maplist[i]] = headers[i] return _headers + class CosConfig(object): - def __init__(self, appid, region, access_id, access_key, part_size=1, max_thread=5, *args, **kwargs): - self._appid = appid - self._region = region - self._access_id = access_id - self._access_key = access_key - self._part_size = min(10, part_size) - self._max_thread = min(10, max_thread) - logger.info("config parameter-> appid: {appid}, region: {region}, part_size: {part_size}, max_thread: {max_thread}".format( - appid=appid, - region=region, - part_size=part_size, - max_thread=max_thread)) + def __init__(self, Appid, Region, Access_id, Access_key, *args, **kwargs): + self._appid = Appid + self._region = Region + self._access_id = Access_id + self._access_key = Access_key + logger.info("config parameter-> appid: {appid}, region: {region}".format( + appid=Appid, + region=Region)) def uri(self, bucket, path=None): if path: @@ -106,7 +99,7 @@ def uri(self, bucket, path=None): return url -class ObjectInterface(object): +class CosS3Client(object): def __init__(self, conf, session=None): self._conf = conf @@ -123,13 +116,11 @@ def __init__(self, conf, session=None): else: self._session = session - def put_object(self, Bucket, Body, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) for j in range(self._retry): - rt = self._session.put(url=url, - auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, headers=headers) + rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, headers=headers) if rt.status_code == 200: break return rt @@ -138,7 +129,7 @@ def get_object(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) for j in range(self._retry): - rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) + rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break return rt @@ -147,12 +138,12 @@ def delete_object(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) for j in range(self._retry): - rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) + rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 204: break return rt - - def create_multipart_upload(self, Bucket, Key, **kwargs): + + def create_multipart_upload(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploads") for j in range(self._retry): @@ -160,44 +151,30 @@ def create_multipart_upload(self, Bucket, Key, **kwargs): if rt.status_code == 200: break return rt - - def upload_part(self, Bucket, Key, PartNumber="", UploadId="", **kwargs): - headers,params = mapped(kwargs) + + def upload_part(self, Bucket, Key, Body, PartNumber="", UploadId="", **kwargs): + headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?partNumber={PartNumber}&uploadId={UploadId}".format(PartNumber=PartNumber, UploadId=UploadId)) for j in range(self._retry): rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body) if rt.status_code == 200: break return rt - + def complete_multipart_upload(self, Bucket, Key, UploadId="", **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) for j in range(self._retry): - rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=data) + rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break return rt -class BucketInterface(object): - - def __init__(self, conf, session=None): - self._conf = conf - self._upload_id = None - self._md5 = [] - self._have_finished = 0 - self._retry = 2 - if session is None: - self._session = requests.session() - else: - self._session = session - def create_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) for j in range(self._retry): - rt = self._session.put(url=url, - auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break return rt @@ -206,33 +183,28 @@ def delete_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) for j in range(self._retry): - rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) + rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 204: break return rt - def list_objects(self, Bucket ,**kwargs): + def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys="", Prefix="", **kwargs): headers = mapped(kwargs) - url = self._conf.uri(bucket=Bucket, path="?max-keys=1") + url = self._conf.uri(bucket=Bucket, + path='''?prefix={Prefix}&delimiter={Delimiter}&encoding-type={EncodingType}&marker={Marker}&max-keys={MaxKeys}'''.format( + Delimiter=Delimiter, + EncodingType=EncodingType, + Prefix=Prefix, + MaxKeys=MaxKeys, + Marker=Marker + ), + ) for j in range(self._retry): - rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key),headers=headers) + rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) if rt.status_code == 200: break return rt -class CosS3Client(object): - - def __init__(self, conf): - self._conf = conf - self._session = requests.session() - - def obj_int(self, local_path='', cos_path=''): - return ObjectInterface(conf=self._conf, session=self._session) - - def buc_int(self): - return BucketInterface(conf=self._conf, session=self._session) - - if __name__ == "__main__": pass diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index da115022..ca43ce35 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -1,29 +1,30 @@ # -*- coding=utf-8 -from qcloud_cos import cos_client +import cos_client import logging import random import sys import os -import datetime -reload(sys) -sys.setdefaultencoding('utf-8') + logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(asctime)s - %(message)s") file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_list = [] test_num = 20 +ACCESS_ID = os.environ["ACCESS_ID"] +ACCESS_KEY = os.environ["ACCESS_KEY"] def gen_file(path, size): - file = open(path, 'w') - file.seek(1024*1024*size) - file.write('\x00') - file.close() + _file = open(path, 'w') + _file.seek(1024*1024*size) + _file.write('\x00') + _file.close() def setUp(): print "start test" + def tearDown(): print "function teardown" @@ -31,66 +32,64 @@ def tearDown(): def Test(): file_size = 3.1 + 0.1 file_name = "tmp" + file_id + "_" + str(file_size) + "MB" - headers = { - 'Content-Encoding':'url'} + headers = {'Content-Encoding': 'url'} print "Test put " + file_name sys.stdout.flush() - conf = cos_client.CosConfig( - appid="1252448703", - region="cn-north", - access_id=ACCESS_ID, - access_key=ACCESS_KEY, + Appid="1252448703", + Region="cn-north", + Access_id=ACCESS_ID, + Access_key=ACCESS_KEY, ) client = cos_client.CosS3Client(conf) rt = client.put_object( Bucket='lewzylu06', - Body='123'*1232, + Body='123'*1232, Key=file_name, CacheControl='string', ContentDisposition='string', ContentEncoding='string', ContentLanguage='string', - ContentType='string') - assert rt.status_code==200 - + ContentType='string' + ) + assert rt.status_code == 200 + print "Test get " + file_name rt = client.get_object(Bucket='lewzylu06', - Key=file_name) - assert rt.status_code==200 - + Key=file_name + ) + assert rt.status_code == 200 + print "Test delete " + file_name - rt = client.delete_object( - Bucket='lewzylu06', - Key=file_name, - ) - assert rt.status_code==204 - - - + rt = client.delete_object(Bucket='lewzylu06', + Key=file_name, + ) + assert rt.status_code == 204 + conf = cos_client.CosConfig( - appid="1252448703", - region="cn-north", - access_id=ACCESS_ID, - access_key=ACCESS_KEY, + Appid="1252448703", + Region="cn-north", + Access_id=ACCESS_ID, + Access_key=ACCESS_KEY, ) client = cos_client.CosS3Client(conf) print "Test create bucket" - rt = client.create_bucket( - Bucket='lewzylu999' - ) - + rt = client.create_bucket(Bucket='lewzylu999' + ) + assert rt.status_code == 200 print "Test delete bucket" - rt = client.delete_bucket( - Bucket='lewzylu999', - MaxKeys = '1' - ) - assert rt.status_code==204 - rt = client.list_objects(Bucket='lewzylu06') - print rt.content + rt = client.delete_bucket(Bucket='lewzylu999' + ) + assert rt.status_code == 204 + + print "Test list objects" + rt = client.list_objects(Bucket='lewzylu06', + MaxKeys='1', + ) print rt.status_code + assert rt.status_code == 200 + if __name__ == "__main__": setUp() Test() - From ac094def358bc3a8713063aae2a07cd69ccb0f73 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 27 Jul 2017 21:18:46 +0800 Subject: [PATCH 15/71] Add log and uttest --- qcloud_cos/cos_auth.py | 2 +- qcloud_cos/cos_client.py | 150 ++++++++++++++++++------ qcloud_cos/test.py | 241 ++++++++++++++++++++++++--------------- 3 files changed, 263 insertions(+), 130 deletions(-) diff --git a/qcloud_cos/cos_auth.py b/qcloud_cos/cos_auth.py index 549cfe2d..0f49b635 100644 --- a/qcloud_cos/cos_auth.py +++ b/qcloud_cos/cos_auth.py @@ -70,4 +70,4 @@ def __call__(self, r): if __name__ == "__main__": - url = 'http://lewzylu01-1252448703.cn-south.myqcloud.com/a.txt' + pass diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 7ccb6749..2211bdb8 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -4,6 +4,14 @@ import logging import sys import copy +import xml.dom.minidom + + +logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', + datefmt='%a, %d %b %Y %H:%M:%S', + filename='cos_s3.log', + filemode='w') logger = logging.getLogger(__name__) fs_coding = sys.getfilesystemencoding() @@ -38,42 +46,48 @@ def to_unicode(s): else: return s.decode(fs_coding) +def dict_to_xml(data): + doc = xml.dom.minidom.Document() + root = doc.createElement('CompleteMultipartUpload') + doc.appendChild(root) -def to_printable_str(s): - if isinstance(s, unicode): - return s.encode(fs_coding) - else: - return s + if 'Parts' not in data.keys(): + logger.error("Invalid Parameter, Parts Is Required!") + return '' + + for i in data['Parts']: + nodePart = doc.createElement('Part') + if 'PartNumber' not in i.keys(): + logger.error("Invalid Parameter, PartNumber Is Required!") + return '' -def view_bar(num, total): - ret = 1.0*num / total - ag = ret * 100 - ab = "\r [%-50s]%.2f%%" % ('='*int(ret*50), ag, ) - sys.stdout.write(ab) - sys.stdout.flush() + nodeNumber = doc.createElement('PartNumber') + nodeNumber.appendChild(doc.createTextNode(str(i['PartNumber']))) + if 'ETag' not in i.keys(): + logger.error("Invalid Parameter, ETag Is Required!") + return '' -def getTagText(root, tag): - node = root.getElementsByTagName(tag)[0] - rc = "" - for node in node.childNodes: - if node.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE): - rc = rc + node.data + nodeETag = doc.createElement('ETag') + nodeETag.appendChild(doc.createTextNode(str(i['ETag']))) + + nodePart.appendChild(nodeNumber) + nodePart.appendChild(nodeETag) + root.appendChild(nodePart) + return doc.toxml('utf-8') def mapped(headers): - _headers = copy.copy(headers) + _headers = dict() for i in headers.keys(): if i in maplist: - del _headers[i] _headers[maplist[i]] = headers[i] return _headers - class CosConfig(object): - def __init__(self, Appid, Region, Access_id, Access_key, *args, **kwargs): + def __init__(self, Appid, Region, Access_id, Access_key): self._appid = Appid self._region = Region self._access_id = Access_id @@ -107,7 +121,7 @@ def __init__(self, conf, session=None): self._headers = [] self._params = [] self._md5 = [] - self._retry = 2 + self._retry = 1 self._file_num = 0 self._folder_num = 0 self._have_finished = 0 @@ -119,90 +133,158 @@ def __init__(self, conf, session=None): def put_object(self, Bucket, Body, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("put object, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, headers=headers) if rt.status_code == 200: break + logger.error(rt.headers) + return rt def get_object(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("get object, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break + logger.error(rt.headers) return rt def delete_object(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("delete object, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 204: break + logger.error(rt.headers) return rt def create_multipart_upload(self, Bucket, Key, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploads") + logger.info("create multipart upload, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.post(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) if rt.status_code == 200: break + logger.error(rt.headers) return rt - def upload_part(self, Bucket, Key, Body, PartNumber="", UploadId="", **kwargs): + def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?partNumber={PartNumber}&uploadId={UploadId}".format(PartNumber=PartNumber, UploadId=UploadId)) + logger.info("put object, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body) if rt.status_code == 200: break + logger.error(rt.headers) return rt - def complete_multipart_upload(self, Bucket, Key, UploadId="", **kwargs): + def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload = {}, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) + logger.info("complete multipart upload, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): - rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=dict_to_xml(MultipartUpload), headers=headers) if rt.status_code == 200: break + logger.error(rt.headers) return rt + def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) + logger.info("abort multipart upload, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) + for j in range(self._retry): + rt = self._session.delete(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + if rt.status_code == 200: + break + logger.error(rt.headers) + return rt + + def list_parts(self, Bucket, Key, UploadId, **kwargs): + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) + logger.info("list multipart upload, url=:{url} ,headers=:{headers}".format( + url = url, + headers = headers)) + for j in range(self._retry): + rt = self._session.get(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + if rt.status_code == 200: + break + logger.error(rt.headers) + return rt + def create_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) + logger.info("create bucket, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 200: break + logger.error(rt.headers) return rt def delete_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) + logger.info("delete bucket, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) if rt.status_code == 204: break + logger.error(rt.headers) return rt def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys="", Prefix="", **kwargs): headers = mapped(kwargs) - url = self._conf.uri(bucket=Bucket, - path='''?prefix={Prefix}&delimiter={Delimiter}&encoding-type={EncodingType}&marker={Marker}&max-keys={MaxKeys}'''.format( - Delimiter=Delimiter, - EncodingType=EncodingType, - Prefix=Prefix, - MaxKeys=MaxKeys, - Marker=Marker - ), - ) + url = self._conf.uri(bucket=Bucket) + logger.info("list objects, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) for j in range(self._retry): rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) if rt.status_code == 200: break + logger.error(rt.headers) + return rt + + def head_object(self, Bucket, Key): + headers = '' + url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("put object, url=:{url} ,headers=:{headers}".format( + url=url, + headers = headers)) + for j in range(self._retry): + rt = self._session.head(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) + if rt.status_code == 200: + break + logger.error(rt.headers) return rt diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index ca43ce35..d555900b 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -1,95 +1,146 @@ -# -*- coding=utf-8 -import cos_client -import logging -import random -import sys -import os - -logger = logging.getLogger(__name__) -logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(asctime)s - %(message)s") -file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) -file_list = [] -test_num = 20 -ACCESS_ID = os.environ["ACCESS_ID"] -ACCESS_KEY = os.environ["ACCESS_KEY"] - - -def gen_file(path, size): - _file = open(path, 'w') - _file.seek(1024*1024*size) - _file.write('\x00') - _file.close() - - -def setUp(): - print "start test" - - -def tearDown(): - print "function teardown" - - -def Test(): - file_size = 3.1 + 0.1 - file_name = "tmp" + file_id + "_" + str(file_size) + "MB" - headers = {'Content-Encoding': 'url'} - print "Test put " + file_name - sys.stdout.flush() - conf = cos_client.CosConfig( - Appid="1252448703", - Region="cn-north", - Access_id=ACCESS_ID, - Access_key=ACCESS_KEY, - ) - client = cos_client.CosS3Client(conf) - rt = client.put_object( - Bucket='lewzylu06', - Body='123'*1232, - Key=file_name, - CacheControl='string', - ContentDisposition='string', - ContentEncoding='string', - ContentLanguage='string', - ContentType='string' - ) - assert rt.status_code == 200 - - print "Test get " + file_name - rt = client.get_object(Bucket='lewzylu06', - Key=file_name - ) - assert rt.status_code == 200 - - print "Test delete " + file_name - rt = client.delete_object(Bucket='lewzylu06', - Key=file_name, - ) - assert rt.status_code == 204 - - conf = cos_client.CosConfig( - Appid="1252448703", - Region="cn-north", - Access_id=ACCESS_ID, - Access_key=ACCESS_KEY, - ) - client = cos_client.CosS3Client(conf) - print "Test create bucket" - rt = client.create_bucket(Bucket='lewzylu999' - ) - assert rt.status_code == 200 - print "Test delete bucket" - rt = client.delete_bucket(Bucket='lewzylu999' - ) - assert rt.status_code == 204 - - print "Test list objects" - rt = client.list_objects(Bucket='lewzylu06', - MaxKeys='1', - ) - print rt.status_code - assert rt.status_code == 200 - - -if __name__ == "__main__": - setUp() - Test() +# -*- coding=utf-8 +import cos_client +import random +import sys +import os +import xml.dom.minidom +from xml.dom.minidom import parse +from cos_client import CosS3Client +from cos_client import CosConfig + +ACCESS_ID = os.environ["ACCESS_ID"] +ACCESS_KEY = os.environ["ACCESS_KEY"] + +def gen_file(path, size): + _file = open(path, 'w') + _file.seek(1024*1024*size) + _file.write('cos') + _file.close() + +def get_id_from_xml(data): + tree = xml.dom.minidom.parseString(data) + root = tree.documentElement + result = root.getElementsByTagName('UploadId') + # use childNodes to get a list, if has no child get itself + return result[0].childNodes[0].nodeValue + +def setUp(): + print "start test" + +def tearDown(): + print "function teardown" + + +def Test(): + conf = CosConfig( + Appid="1252448703", + Region="cn-north", + Access_id=ACCESS_ID, + Access_key=ACCESS_KEY + ) + client = cos_client.CosS3Client(conf) + + file_size = 2 + file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) + file_name = "tmp" + file_id + "_" + str(file_size) + "MB" + + print "Test Put Object " + file_name + response = client.put_object( + Bucket='test01', + Body='TY'*1024*512*file_size, + Key=file_name, + CacheControl = 'no-cache', + ContentDisposition = 'download.txt', + ACL = 'public-read' + ) + assert response.status_code == 200 + + print "Test Get Object " + file_name + response = client.get_object( + Bucket='test01', + Key=file_name, + ) + assert response.status_code == 200 + + print "Test Head Object " + file_name + response = client.head_object( + Bucket='test01', + Key=file_name + ) + assert response.status_code == 200 + + print "Test Delete Object " + file_name + response = client.delete_object( + Bucket='test01', + Key=file_name + ) + assert response.status_code == 204 + + print "Test List Objects" + response = client.list_objects( + Bucket='test01' + ) + assert response.status_code == 200 + + print "Test Create Bucket" + response = client.create_bucket( + Bucket='test02', + ACL = 'public-read' + ) + assert response.status_code == 200 + + print "Test Delete Bucket" + response = client.delete_bucket( + Bucket='test02' + ) + assert response.status_code == 204 + + print "Test Create MultipartUpload" + response = client.create_multipart_upload( + Bucket='test01', + Key = 'multipartfile.txt', + ) + assert response.status_code == 200 + uploadid = get_id_from_xml(response.text) + + + print "Test Abort MultipartUpload" + response = client.abort_multipart_upload( + Bucket='test01', + Key = 'multipartfile.txt', + UploadId = uploadid + ) + assert response.status_code == 200 + + print "Test Create MultipartUpload" + response = client.create_multipart_upload( + Bucket='test01', + Key = 'multipartfile.txt', + ) + uploadid = get_id_from_xml(response.text) + assert response.status_code == 200 + + print "Test Upload Part" + response = client.upload_part( + Bucket='test01', + Key = 'multipartfile.txt', + UploadId = uploadid, + PartNumber = 1, + Body = 'A'*1024*1024*4 + ) + etag = response.headers['ETag'] + assert response.status_code == 200 + + print "Test Complete MultipartUpload" + response = client.complete_multipart_upload( + Bucket='test01', + Key = 'multipartfile.txt', + UploadId = uploadid, + MultipartUpload = {'Parts':[{'PartNumber':1, 'ETag':etag}]} + ) + assert response.status_code == 200 + +if __name__ == "__main__": + setUp() + Test() + From 13df8aaca2a0adbca2bd4faf6af04162edf6400e Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 28 Jul 2017 14:58:17 +0800 Subject: [PATCH 16/71] fix up the coding convention --- qcloud_cos/cos_client.py | 144 ++++++++++++++++++++++++++------------- qcloud_cos/test.py | 49 +++++++------ 2 files changed, 126 insertions(+), 67 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 2211bdb8..8916bf56 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -7,12 +7,12 @@ import xml.dom.minidom -logging.basicConfig(level=logging.DEBUG, +logging.basicConfig( + level=logging.INFO, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='cos_s3.log', filemode='w') - logger = logging.getLogger(__name__) fs_coding = sys.getfilesystemencoding() @@ -46,6 +46,7 @@ def to_unicode(s): else: return s.decode(fs_coding) + def dict_to_xml(data): doc = xml.dom.minidom.Document() root = doc.createElement('CompleteMultipartUpload') @@ -54,7 +55,7 @@ def dict_to_xml(data): if 'Parts' not in data.keys(): logger.error("Invalid Parameter, Parts Is Required!") return '' - + for i in data['Parts']: nodePart = doc.createElement('Part') @@ -85,6 +86,7 @@ def mapped(headers): _headers[maplist[i]] = headers[i] return _headers + class CosConfig(object): def __init__(self, Appid, Region, Access_id, Access_key): @@ -135,13 +137,16 @@ def put_object(self, Bucket, Body, Key, **kwargs): url = self._conf.uri(bucket=Bucket, path=Key) logger.info("put object, url=:{url} ,headers=:{headers}".format( url=url, - headers = headers)) + headers=headers)) for j in range(self._retry): - rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, headers=headers) + rt = self._session.put( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + data=Body, + headers=headers) if rt.status_code == 200: break logger.error(rt.headers) - return rt def get_object(self, Bucket, Key, **kwargs): @@ -149,9 +154,12 @@ def get_object(self, Bucket, Key, **kwargs): url = self._conf.uri(bucket=Bucket, path=Key) logger.info("get object, url=:{url} ,headers=:{headers}".format( url=url, - headers = headers)) + headers=headers)) for j in range(self._retry): - rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + rt = self._session.get( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) if rt.status_code == 200: break logger.error(rt.headers) @@ -162,9 +170,12 @@ def delete_object(self, Bucket, Key, **kwargs): url = self._conf.uri(bucket=Bucket, path=Key) logger.info("delete object, url=:{url} ,headers=:{headers}".format( url=url, - headers = headers)) + headers=headers)) for j in range(self._retry): - rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + rt = self._session.delete( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) if rt.status_code == 204: break logger.error(rt.headers) @@ -175,9 +186,12 @@ def create_multipart_upload(self, Bucket, Key, **kwargs): url = self._conf.uri(bucket=Bucket, path=Key+"?uploads") logger.info("create multipart upload, url=:{url} ,headers=:{headers}".format( url=url, - headers = headers)) + headers=headers)) for j in range(self._retry): - rt = self._session.post(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) + rt = self._session.post( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) if rt.status_code == 200: break logger.error(rt.headers) @@ -185,67 +199,85 @@ def create_multipart_upload(self, Bucket, Key, **kwargs): def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): headers = mapped(kwargs) - url = self._conf.uri(bucket=Bucket, path=Key+"?partNumber={PartNumber}&uploadId={UploadId}".format(PartNumber=PartNumber, UploadId=UploadId)) + url = self._conf.uri(bucket=Bucket, path=Key+"?partNumber={PartNumber}&uploadId={UploadId}".format( + PartNumber=PartNumber, + UploadId=UploadId)) logger.info("put object, url=:{url} ,headers=:{headers}".format( url=url, - headers = headers)) + headers=headers)) for j in range(self._retry): - rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body) + rt = self._session.put( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + data=Body) if rt.status_code == 200: break logger.error(rt.headers) return rt - def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload = {}, **kwargs): + def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) logger.info("complete multipart upload, url=:{url} ,headers=:{headers}".format( url=url, - headers = headers)) + headers=headers)) for j in range(self._retry): - rt = self._session.post(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=dict_to_xml(MultipartUpload), headers=headers) + rt = self._session.post( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + data=dict_to_xml(MultipartUpload), + headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.headers) return rt def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): - headers = mapped(kwargs) - url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) - logger.info("abort multipart upload, url=:{url} ,headers=:{headers}".format( - url=url, - headers = headers)) - for j in range(self._retry): - rt = self._session.delete(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - if rt.status_code == 200: - break - logger.error(rt.headers) - return rt + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) + logger.info("abort multipart upload, url=:{url} ,headers=:{headers}".format( + url=url, + headers=headers)) + for j in range(self._retry): + rt = self._session.delete( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) + if rt.status_code == 200: + break + logger.error(rt.headers) + return rt def list_parts(self, Bucket, Key, UploadId, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) logger.info("list multipart upload, url=:{url} ,headers=:{headers}".format( - url = url, - headers = headers)) + url=url, + headers=headers)) for j in range(self._retry): - rt = self._session.get(url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + rt = self._session.get( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) if rt.status_code == 200: - break + break logger.error(rt.headers) - return rt + return rt def create_bucket(self, Bucket, **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) logger.info("create bucket, url=:{url} ,headers=:{headers}".format( url=url, - headers = headers)) + headers=headers)) for j in range(self._retry): - rt = self._session.put(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + rt = self._session.put( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.headers) return rt def delete_bucket(self, Bucket, **kwargs): @@ -253,38 +285,54 @@ def delete_bucket(self, Bucket, **kwargs): url = self._conf.uri(bucket=Bucket) logger.info("delete bucket, url=:{url} ,headers=:{headers}".format( url=url, - headers = headers)) + headers=headers)) for j in range(self._retry): - rt = self._session.delete(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + rt = self._session.delete( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) if rt.status_code == 204: break logger.error(rt.headers) return rt - def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys="", Prefix="", **kwargs): + def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys=100, Prefix="", **kwargs): headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) logger.info("list objects, url=:{url} ,headers=:{headers}".format( url=url, - headers = headers)) + headers=headers)) + params = { + 'delimiter': Delimiter, + 'encoding-type': EncodingType, + 'marker': Marker, + 'max-keys': MaxKeys, + 'prefix': Prefix} for j in range(self._retry): - rt = self._session.get(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) + rt = self._session.get( + url=url, + params=params, + headers=headers, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) if rt.status_code == 200: break logger.error(rt.headers) return rt - def head_object(self, Bucket, Key): - headers = '' + def head_object(self, Bucket, Key, **kwargs): + headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) logger.info("put object, url=:{url} ,headers=:{headers}".format( url=url, - headers = headers)) + headers=headers)) for j in range(self._retry): - rt = self._session.head(url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) + rt = self._session.head( + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.headers) return rt diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 1920a3be..4728a5b3 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -11,12 +11,14 @@ ACCESS_ID = os.environ["ACCESS_ID"] ACCESS_KEY = os.environ["ACCESS_KEY"] + def gen_file(path, size): _file = open(path, 'w') _file.seek(1024*1024*size) _file.write('cos') _file.close() + def get_id_from_xml(data): tree = xml.dom.minidom.parseString(data) root = tree.documentElement @@ -24,9 +26,11 @@ def get_id_from_xml(data): # use childNodes to get a list, if has no child get itself return result[0].childNodes[0].nodeValue + def setUp(): print "start test" + def tearDown(): print "function teardown" @@ -49,9 +53,9 @@ def Test(): Bucket='test01', Body='TY'*1024*512*file_size, Key=file_name, - CacheControl = 'no-cache', - ContentDisposition = 'download.txt', - ACL = 'public-read' + CacheControl='no-cache', + ContentDisposition='download.txt', + ACL='public-read' ) assert response.status_code == 200 @@ -85,7 +89,7 @@ def Test(): print "Test Create Bucket" response = client.create_bucket( Bucket='test02', - ACL = 'public-read' + ACL='public-read' ) assert response.status_code == 200 @@ -98,45 +102,52 @@ def Test(): print "Test Create MultipartUpload" response = client.create_multipart_upload( Bucket='test01', - Key = 'multipartfile.txt', + Key='multipartfile.txt', ) assert response.status_code == 200 uploadid = get_id_from_xml(response.text) - print "Test Abort MultipartUpload" response = client.abort_multipart_upload( Bucket='test01', - Key = 'multipartfile.txt', - UploadId = uploadid + Key='multipartfile.txt', + UploadId=uploadid ) assert response.status_code == 200 - + print "Test Create MultipartUpload" response = client.create_multipart_upload( Bucket='test01', - Key = 'multipartfile.txt', + Key='multipartfile.txt', ) uploadid = get_id_from_xml(response.text) assert response.status_code == 200 - + print "Test Upload Part" response = client.upload_part( Bucket='test01', - Key = 'multipartfile.txt', - UploadId = uploadid, - PartNumber = 1, - Body = 'A'*1024*1024*4 + Key='multipartfile.txt', + UploadId=uploadid, + PartNumber=1, + Body='A'*1024*1024*4 ) etag = response.headers['ETag'] assert response.status_code == 200 - + + print "List Upload Parts" + response = client.list_parts( + Bucket='test01', + Key='multipartfile.txt', + UploadId=uploadid + ) + assert response.status_code == 200 + print "Test Complete MultipartUpload" response = client.complete_multipart_upload( Bucket='test01', - Key = 'multipartfile.txt', - UploadId = uploadid, - MultipartUpload = {'Parts':[{'PartNumber':1, 'ETag':etag}]} + Key='multipartfile.txt', + UploadId=uploadid, + MultipartUpload={'Parts': [{'PartNumber': 1, 'ETag': etag}]} ) assert response.status_code == 200 From 4309a8655ba751c3bf8a39b6f55a5acb68ae040d Mon Sep 17 00:00:00 2001 From: tiedu Date: Fri, 28 Jul 2017 16:13:05 +0800 Subject: [PATCH 17/71] Update cos_client.py --- qcloud_cos/cos_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 5736fd25..8916bf56 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -55,7 +55,7 @@ def dict_to_xml(data): if 'Parts' not in data.keys(): logger.error("Invalid Parameter, Parts Is Required!") return '' - + for i in data['Parts']: nodePart = doc.createElement('Part') From a0ca1907fe9af7bd798693db21b9568c56cc36e4 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 28 Jul 2017 20:29:45 +0800 Subject: [PATCH 18/71] Add Code Comments and ReadMe File --- qcloud_cos/cos_client.py | 32 ++++++++++++++++++++------------ qcloud_cos/test.py | 1 + 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 8916bf56..ce1db48b 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -48,6 +48,7 @@ def to_unicode(s): def dict_to_xml(data): + """V5使用xml格式,将输入的dict转换为xml""" doc = xml.dom.minidom.Document() root = doc.createElement('CompleteMultipartUpload') doc.appendChild(root) @@ -80,6 +81,7 @@ def dict_to_xml(data): def mapped(headers): + """S3到COS参数的一个映射""" _headers = dict() for i in headers.keys(): if i in maplist: @@ -88,7 +90,7 @@ def mapped(headers): class CosConfig(object): - + """config类,保存用户相关信息""" def __init__(self, Appid, Region, Access_id, Access_key): self._appid = Appid self._region = Region @@ -99,6 +101,7 @@ def __init__(self, Appid, Region, Access_id, Access_key): region=Region)) def uri(self, bucket, path=None): + """拼接url""" if path: url = u"http://{bucket}-{uid}.{region}.myqcloud.com/{path}".format( bucket=to_unicode(bucket), @@ -116,23 +119,17 @@ def uri(self, bucket, path=None): class CosS3Client(object): - - def __init__(self, conf, session=None): + """cos客户端类,封装相应请求""" + def __init__(self, conf, retry=1, session=None): self._conf = conf - self._upload_id = None - self._headers = [] - self._params = [] - self._md5 = [] - self._retry = 1 - self._file_num = 0 - self._folder_num = 0 - self._have_finished = 0 + self._retry = retry # 重试的次数,分片上传时可适当增大 if session is None: self._session = requests.session() else: self._session = session def put_object(self, Bucket, Body, Key, **kwargs): + """单文件上传接口,适用于小文件,最大不得超过5GB""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) logger.info("put object, url=:{url} ,headers=:{headers}".format( @@ -148,8 +145,9 @@ def put_object(self, Bucket, Body, Key, **kwargs): break logger.error(rt.headers) return rt - + def get_object(self, Bucket, Key, **kwargs): + """单文件下载接口""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) logger.info("get object, url=:{url} ,headers=:{headers}".format( @@ -166,6 +164,7 @@ def get_object(self, Bucket, Key, **kwargs): return rt def delete_object(self, Bucket, Key, **kwargs): + """单文件删除接口""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) logger.info("delete object, url=:{url} ,headers=:{headers}".format( @@ -182,6 +181,7 @@ def delete_object(self, Bucket, Key, **kwargs): return rt def create_multipart_upload(self, Bucket, Key, **kwargs): + """创建分片上传,适用于大文件上传""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploads") logger.info("create multipart upload, url=:{url} ,headers=:{headers}".format( @@ -198,6 +198,7 @@ def create_multipart_upload(self, Bucket, Key, **kwargs): return rt def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): + """上传分片,单个大小不得超过5GB""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?partNumber={PartNumber}&uploadId={UploadId}".format( PartNumber=PartNumber, @@ -216,6 +217,7 @@ def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): return rt def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, **kwargs): + """完成分片上传,组装后的文件不得小于1MB,否则会返回错误""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) logger.info("complete multipart upload, url=:{url} ,headers=:{headers}".format( @@ -233,6 +235,7 @@ def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, * return rt def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): + """放弃一个已经存在的分片上传任务,删除所有已经存在的分片""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) logger.info("abort multipart upload, url=:{url} ,headers=:{headers}".format( @@ -249,6 +252,7 @@ def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): return rt def list_parts(self, Bucket, Key, UploadId, **kwargs): + """列出已上传的分片""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId)) logger.info("list multipart upload, url=:{url} ,headers=:{headers}".format( @@ -265,6 +269,7 @@ def list_parts(self, Bucket, Key, UploadId, **kwargs): return rt def create_bucket(self, Bucket, **kwargs): + """创建一个bucket""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) logger.info("create bucket, url=:{url} ,headers=:{headers}".format( @@ -281,6 +286,7 @@ def create_bucket(self, Bucket, **kwargs): return rt def delete_bucket(self, Bucket, **kwargs): + """删除一个bucket,bucket必须为空""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) logger.info("delete bucket, url=:{url} ,headers=:{headers}".format( @@ -297,6 +303,7 @@ def delete_bucket(self, Bucket, **kwargs): return rt def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys=100, Prefix="", **kwargs): + """获取文件列表""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) logger.info("list objects, url=:{url} ,headers=:{headers}".format( @@ -320,6 +327,7 @@ def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxK return rt def head_object(self, Bucket, Key, **kwargs): + """获取文件信息""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) logger.info("put object, url=:{url} ,headers=:{headers}".format( diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 4728a5b3..cde5b664 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -20,6 +20,7 @@ def gen_file(path, size): def get_id_from_xml(data): + """解析xml中的uploadid""" tree = xml.dom.minidom.parseString(data) root = tree.documentElement result = root.getElementsByTagName('UploadId') From 21fc039c23e8f2aa1c6f888214bb3dd50da86a37 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 28 Jul 2017 20:41:01 +0800 Subject: [PATCH 19/71] Add README.rst --- README.md | 0 requirements.txt | 2 -- setup.py | 34 ---------------------------------- 3 files changed, 36 deletions(-) delete mode 100644 README.md delete mode 100644 requirements.txt delete mode 100644 setup.py diff --git a/README.md b/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index bc29d3d8..00000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -requests==2.12.4 -argparse==1.4.0 diff --git a/setup.py b/setup.py deleted file mode 100644 index a7bbc943..00000000 --- a/setup.py +++ /dev/null @@ -1,34 +0,0 @@ -from setuptools import setup, find_packages -from platform import python_version_tuple - - -def requirements(): - - with open('requirements.txt', 'r') as fileobj: - requirements = [line.strip() for line in fileobj] - - version = python_version_tuple() - - if version[0] == 2 and version[1] == 6: - requirements.append("argparse==1.4.0") - return requirements - - -def long_description(): - with open('README.rst', 'r') as fileobj: - return fileobj.read() - - -setup( - name='cos-python-sdk-v5', - version='0.0.1', - url='https://www.qcloud.com/', - license='MIT', - author='lewzylu', - author_email='327874225@qq.com', - description='cos-python-sdk-v5', - long_description=long_description(), - packages=find_packages(), - install_requires=requirements() - } -) From 914e758f30d599963bf87fd14e0eb327b4d7aa3b Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 28 Jul 2017 20:47:18 +0800 Subject: [PATCH 20/71] Add README.rst File --- README.rst | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 README.rst diff --git a/README.rst b/README.rst new file mode 100644 index 00000000..acde4cb2 --- /dev/null +++ b/README.rst @@ -0,0 +1,133 @@ +Qcloud COSv5 SDK +####################### + +介绍 +_______ + +腾讯云COSV5Python SDK, 目前可以支持Python2.6与Python2.7。 + +安装指南 +__________ + +使用pip安装 :: + + pip install -U qcloud_cos_v5 + + +手动安装:: + + python setup.py install + +使用方法 +__________ + +使用python sdk,参照https://github.com/tencentyun/cos-python-sdk-v5/blob/master/qcloud_cos/test.py + +.. code:: python + + # 设置用户属性, 包括appid, secret_id和secret_key + appid = 100000 # 替换为用户的appid + secret_id = u'xxxxxxxx' # 替换为用户的secret_id + secret_key = u'xxxxxxx' # 替换为用户的secret_key +   region = "cn-north"       # 替换为用户的region,目前可以为 cn-east/cn-south/cn-north/cn-southwest,分别对应于上海,广州,天津,西南园区 + config = CosConfig(Appid=appid, Region=region, Access_id=secret_id, Access_key=secret_key) #获取配置对象 + client = CosS3Client(config) #获取客户端对象 + + ############################################################################ + # 文件操作 # + ############################################################################ + # 1. 上传单个文件 + response = client.put_object( + Bucket='test01', + Body='TY'*1024*512*file_size, + Key=file_name, + CacheControl='no-cache', + ContentDisposition='download.txt', + ACL='public-read' + ) + + # 2. 下载单个文件 + response = client.get_object( + Bucket='test01', + Key=file_name, + ) + + # 3. 获取文件属性 + response = client.head_object( + Bucket='test01', + Key=file_name + ) + + # 4. 删除单个文件 + response = client.delete_object( + Bucket='test01', + Key=file_name + ) + + # 5. 创建分片上传 + response = client.create_multipart_upload( + Bucket='test01', + Key='multipartfile.txt', + ) + uploadid = get_id_from_xml(response.text) + + # 6. 删除分片上传 + response = client.abort_multipart_upload( + Bucket='test01', + Key='multipartfile.txt', + UploadId=uploadid + ) + + # 7. 再次创建分片上传 + response = client.create_multipart_upload( + Bucket='test01', + Key='multipartfile.txt', + ) + uploadid = get_id_from_xml(response.text) + + # 8. 上传分片 + response = client.upload_part( + Bucket='test01', + Key='multipartfile.txt', + UploadId=uploadid, + PartNumber=1, + Body='A'*1024*1024*4 + ) + etag = response.headers['ETag'] + + # 8. 上传分片 + response = client.list_parts( + Bucket='test01', + Key='multipartfile.txt', + UploadId=uploadid + ) + + + # 9. 完成分片上传 + response = client.complete_multipart_upload( + Bucket='test01', + Key='multipartfile.txt', + UploadId=uploadid, + MultipartUpload={'Parts': [{'PartNumber': 1, 'ETag': etag}]} + ) + + + ############################################################################ + # Bucket操作 # + ############################################################################ + # 1. 创建Bucket + response = client.create_bucket( + Bucket='test02', + ACL='public-read' + ) + + # 2. 删除Bucket + print "Test Delete Bucket" + response = client.delete_bucket( + Bucket='test02' + ) + + # 3. 获取文件列表 + response = client.list_objects( + Bucket='test01' + ) From 202d32357a69744094971d8c8baa0bec57b3d19f Mon Sep 17 00:00:00 2001 From: tiedu Date: Fri, 28 Jul 2017 20:51:45 +0800 Subject: [PATCH 21/71] Update README.rst --- README.rst | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index acde4cb2..e5399eba 100644 --- a/README.rst +++ b/README.rst @@ -26,10 +26,10 @@ __________ .. code:: python # 设置用户属性, 包括appid, secret_id和secret_key - appid = 100000 # 替换为用户的appid - secret_id = u'xxxxxxxx' # 替换为用户的secret_id - secret_key = u'xxxxxxx' # 替换为用户的secret_key -   region = "cn-north"       # 替换为用户的region,目前可以为 cn-east/cn-south/cn-north/cn-southwest,分别对应于上海,广州,天津,西南园区 + appid = 100000 # 替换为用户的appid + secret_id = u'xxxxxxxx' # 替换为用户的secret_id + secret_key = u'xxxxxxx' # 替换为用户的secret_key +   region = "cn-north"       # 替换为用户的region,目前可以为 cn-east/cn-south/cn-north/cn-southwest,分别对应于上海,广州,天津,西南园区 config = CosConfig(Appid=appid, Region=region, Access_id=secret_id, Access_key=secret_key) #获取配置对象 client = CosS3Client(config) #获取客户端对象 @@ -95,14 +95,6 @@ __________ ) etag = response.headers['ETag'] - # 8. 上传分片 - response = client.list_parts( - Bucket='test01', - Key='multipartfile.txt', - UploadId=uploadid - ) - - # 9. 完成分片上传 response = client.complete_multipart_upload( Bucket='test01', @@ -122,7 +114,6 @@ __________ ) # 2. 删除Bucket - print "Test Delete Bucket" response = client.delete_bucket( Bucket='test02' ) From 8c1f89a4bf8fae077550f8097ad95acf911312bd Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 28 Jul 2017 21:02:09 +0800 Subject: [PATCH 22/71] fix up code style --- qcloud_cos/cos_client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index a434bed7..318ac62a 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -56,7 +56,7 @@ def dict_to_xml(data): if 'Parts' not in data.keys(): logger.error("Invalid Parameter, Parts Is Required!") return '' - + for i in data['Parts']: nodePart = doc.createElement('Part') @@ -122,7 +122,7 @@ class CosS3Client(object): """cos客户端类,封装相应请求""" def __init__(self, conf, retry=1, session=None): self._conf = conf - self._retry = retry # 重试的次数,分片上传时可适当增大 + self._retry = retry # 重试的次数,分片上传时可适当增大 if session is None: self._session = requests.session() else: @@ -145,7 +145,7 @@ def put_object(self, Bucket, Body, Key, **kwargs): break logger.error(rt.headers) return rt - + def get_object(self, Bucket, Key, **kwargs): """单文件下载接口""" headers = mapped(kwargs) From 94a06cd7c8a9ee4652bebdef44c7b8185a72bffb Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 28 Jul 2017 21:45:10 +0800 Subject: [PATCH 23/71] Add setup --- qcloud_cos/requirements.txt | 2 ++ qcloud_cos/setup.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 qcloud_cos/requirements.txt create mode 100644 qcloud_cos/setup.py diff --git a/qcloud_cos/requirements.txt b/qcloud_cos/requirements.txt new file mode 100644 index 00000000..bc29d3d8 --- /dev/null +++ b/qcloud_cos/requirements.txt @@ -0,0 +1,2 @@ +requests==2.12.4 +argparse==1.4.0 diff --git a/qcloud_cos/setup.py b/qcloud_cos/setup.py new file mode 100644 index 00000000..2362fb62 --- /dev/null +++ b/qcloud_cos/setup.py @@ -0,0 +1,34 @@ +from setuptools import setup, find_packages +from platform import python_version_tuple + + +def requirements(): + + with open('requirements.txt', 'r') as fileobj: + requirements = [line.strip() for line in fileobj] + + version = python_version_tuple() + + if version[0] == 2 and version[1] == 6: + requirements.append("argparse==1.4.0") + return requirements + + +def long_description(): + with open('README.rst', 'r') as fileobj: + return fileobj.read() + + +setup( + name='cos-python-sdk-v5', + version='1.0.0', + url='https://www.qcloud.com/', + license='MIT', + author='tiedu, lewzylu, channingliu', + author_email='dutie123@qq.com', + description='cos-python-sdk-v5', + long_description=long_description(), + packages=find_packages(), + install_requires=requirements() + } +) From c3af1e9e80cbbdcd1a838ae607c8ce3cbce12534 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 28 Jul 2017 21:51:48 +0800 Subject: [PATCH 24/71] add requiremensts.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..bc29d3d8 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests==2.12.4 +argparse==1.4.0 From 588a49a119555fdf0765e00f144d206a73137521 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 28 Jul 2017 21:52:12 +0800 Subject: [PATCH 25/71] add setup.py --- setup.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 setup.py diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..2362fb62 --- /dev/null +++ b/setup.py @@ -0,0 +1,34 @@ +from setuptools import setup, find_packages +from platform import python_version_tuple + + +def requirements(): + + with open('requirements.txt', 'r') as fileobj: + requirements = [line.strip() for line in fileobj] + + version = python_version_tuple() + + if version[0] == 2 and version[1] == 6: + requirements.append("argparse==1.4.0") + return requirements + + +def long_description(): + with open('README.rst', 'r') as fileobj: + return fileobj.read() + + +setup( + name='cos-python-sdk-v5', + version='1.0.0', + url='https://www.qcloud.com/', + license='MIT', + author='tiedu, lewzylu, channingliu', + author_email='dutie123@qq.com', + description='cos-python-sdk-v5', + long_description=long_description(), + packages=find_packages(), + install_requires=requirements() + } +) From dcd3296242489422ae87ce52b309e7bad13481cf Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 28 Jul 2017 21:54:10 +0800 Subject: [PATCH 26/71] mv setup to write place --- qcloud_cos/requirements.txt | 2 -- qcloud_cos/setup.py | 34 ---------------------------------- 2 files changed, 36 deletions(-) delete mode 100644 qcloud_cos/requirements.txt delete mode 100644 qcloud_cos/setup.py diff --git a/qcloud_cos/requirements.txt b/qcloud_cos/requirements.txt deleted file mode 100644 index bc29d3d8..00000000 --- a/qcloud_cos/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -requests==2.12.4 -argparse==1.4.0 diff --git a/qcloud_cos/setup.py b/qcloud_cos/setup.py deleted file mode 100644 index 2362fb62..00000000 --- a/qcloud_cos/setup.py +++ /dev/null @@ -1,34 +0,0 @@ -from setuptools import setup, find_packages -from platform import python_version_tuple - - -def requirements(): - - with open('requirements.txt', 'r') as fileobj: - requirements = [line.strip() for line in fileobj] - - version = python_version_tuple() - - if version[0] == 2 and version[1] == 6: - requirements.append("argparse==1.4.0") - return requirements - - -def long_description(): - with open('README.rst', 'r') as fileobj: - return fileobj.read() - - -setup( - name='cos-python-sdk-v5', - version='1.0.0', - url='https://www.qcloud.com/', - license='MIT', - author='tiedu, lewzylu, channingliu', - author_email='dutie123@qq.com', - description='cos-python-sdk-v5', - long_description=long_description(), - packages=find_packages(), - install_requires=requirements() - } -) From 236f3120ae0c08b69dd91dfc474b10db6df8bc2f Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Sat, 29 Jul 2017 12:09:17 +0800 Subject: [PATCH 27/71] Add the list_parts sample to ReadMe --- README.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e5399eba..9543b0ba 100644 --- a/README.rst +++ b/README.rst @@ -95,7 +95,14 @@ __________ ) etag = response.headers['ETag'] - # 9. 完成分片上传 + # 9. 列出分片 + response = clieent.list_parts( + Bucket='test01', + Key='mutilpartfile.txt', + UploadId=uploadid + ) + + # 10. 完成分片上传 response = client.complete_multipart_upload( Bucket='test01', Key='multipartfile.txt', From 5dd9ce79865de72adf3b081652fc0672e4ffd38d Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Sat, 29 Jul 2017 17:18:36 +0800 Subject: [PATCH 28/71] Fix up some logical errors --- qcloud_cos/cos_client.py | 32 +++++++++++++------------------- qcloud_cos/test.py | 2 +- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 318ac62a..3c09469f 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -30,12 +30,6 @@ 'GrantWrite': 'x-cos-grant-write', 'GrantRead': 'x-cos-grant-read', 'StorageClass': 'x-cos-storage-class', - 'PartNumber': 'partNumber', - 'UploadId': 'uploadId', - 'Delimiter': 'delimiter', - 'Marker': 'marker', - 'MaxKeys': 'max-keys', - 'Prefix': 'prefix', 'EncodingType': 'encoding-type' } @@ -143,7 +137,7 @@ def put_object(self, Bucket, Body, Key, **kwargs): headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.text) return rt def get_object(self, Bucket, Key, **kwargs): @@ -160,7 +154,7 @@ def get_object(self, Bucket, Key, **kwargs): headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.text) return rt def delete_object(self, Bucket, Key, **kwargs): @@ -177,7 +171,7 @@ def delete_object(self, Bucket, Key, **kwargs): headers=headers) if rt.status_code == 204: break - logger.error(rt.headers) + logger.error(rt.text) return rt def create_multipart_upload(self, Bucket, Key, **kwargs): @@ -194,7 +188,7 @@ def create_multipart_upload(self, Bucket, Key, **kwargs): headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.text) return rt def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): @@ -213,7 +207,7 @@ def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): data=Body) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.text) return rt def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, **kwargs): @@ -231,7 +225,7 @@ def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, * headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.text) return rt def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): @@ -248,7 +242,7 @@ def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.text) return rt def list_parts(self, Bucket, Key, UploadId, **kwargs): @@ -265,7 +259,7 @@ def list_parts(self, Bucket, Key, UploadId, **kwargs): headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.text) return rt def create_bucket(self, Bucket, **kwargs): @@ -282,7 +276,7 @@ def create_bucket(self, Bucket, **kwargs): headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.text) return rt def delete_bucket(self, Bucket, **kwargs): @@ -299,7 +293,7 @@ def delete_bucket(self, Bucket, **kwargs): headers=headers) if rt.status_code == 204: break - logger.error(rt.headers) + logger.error(rt.text) return rt def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys=100, Prefix="", **kwargs): @@ -323,14 +317,14 @@ def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxK auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.text) return rt def head_object(self, Bucket, Key, **kwargs): """获取文件信息""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket, path=Key) - logger.info("put object, url=:{url} ,headers=:{headers}".format( + logger.info("head object, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) for j in range(self._retry): @@ -340,7 +334,7 @@ def head_object(self, Bucket, Key, **kwargs): headers=headers) if rt.status_code == 200: break - logger.error(rt.headers) + logger.error(rt.text) return rt diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index cde5b664..804b8397 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -43,7 +43,7 @@ def Test(): Access_id=ACCESS_ID, Access_key=ACCESS_KEY ) - client = cos_client.CosS3Client(conf) + client = CosS3Client(conf) file_size = 2 file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) From 07895f7bcdfcf62066adb87002eb50b04962284c Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 31 Jul 2017 14:29:07 +0800 Subject: [PATCH 29/71] Add the Excepoiton log and set the requests timeout --- qcloud_cos/cos_client.py | 104 +++++++++++++++++++++++++++++++-------- qcloud_cos/test.py | 2 +- 2 files changed, 84 insertions(+), 22 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 3c09469f..ea6ec8cf 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -122,6 +122,22 @@ def __init__(self, conf, retry=1, session=None): else: self._session = session + def send_request(self, method, url, **kwargs): + try: + if method == 'POST': + res = self._session.post(url, **kwargs) + elif method == 'GET': + res = self._session.get(url, **kwargs) + elif method == 'PUT': + res = self._session.put(url, **kwargs) + elif method == 'DELETE': + res = self._session.delete(url, **kwargs) + elif method == 'HEAD': + res = self._session.head(url, **kwargs) + return res + except Exception as e: + logger.exception('url:%s, exception:%s' % (url, str(e))) + def put_object(self, Bucket, Body, Key, **kwargs): """单文件上传接口,适用于小文件,最大不得超过5GB""" headers = mapped(kwargs) @@ -130,11 +146,15 @@ def put_object(self, Bucket, Body, Key, **kwargs): url=url, headers=headers)) for j in range(self._retry): - rt = self._session.put( + rt = self.send_request( + method='PUT', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, - headers=headers) + headers=headers, + timeout=10) + if rt is None: + continue if rt.status_code == 200: break logger.error(rt.text) @@ -148,10 +168,13 @@ def get_object(self, Bucket, Key, **kwargs): url=url, headers=headers)) for j in range(self._retry): - rt = self._session.get( + rt = self.send_request( + method='GET', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + if rt is None: + continue if rt.status_code == 200: break logger.error(rt.text) @@ -165,10 +188,13 @@ def delete_object(self, Bucket, Key, **kwargs): url=url, headers=headers)) for j in range(self._retry): - rt = self._session.delete( + rt = self.send_request( + method='DELETE', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + if rt is None: + continue if rt.status_code == 204: break logger.error(rt.text) @@ -182,10 +208,14 @@ def create_multipart_upload(self, Bucket, Key, **kwargs): url=url, headers=headers)) for j in range(self._retry): - rt = self._session.post( + rt = self.send_request( + method='POST', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers) + headers=headers, + timeout=10) + if rt is None: + continue if rt.status_code == 200: break logger.error(rt.text) @@ -201,10 +231,14 @@ def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): url=url, headers=headers)) for j in range(self._retry): - rt = self._session.put( + rt = self.send_request( + method='PUT', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - data=Body) + data=Body, + timeout=10) + if rt is None: + continue if rt.status_code == 200: break logger.error(rt.text) @@ -218,11 +252,15 @@ def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, * url=url, headers=headers)) for j in range(self._retry): - rt = self._session.post( + rt = self.send_request( + method='POST', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=dict_to_xml(MultipartUpload), - headers=headers) + headers=headers, + timeout=600) # 完成分片上传的超时时间设置为10分钟 + if rt is None: + continue if rt.status_code == 200: break logger.error(rt.text) @@ -236,10 +274,14 @@ def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): url=url, headers=headers)) for j in range(self._retry): - rt = self._session.delete( + rt = self.send_request( + method='DELETE', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers) + headers=headers, + timeout=10) + if rt is None: + continue if rt.status_code == 200: break logger.error(rt.text) @@ -253,10 +295,14 @@ def list_parts(self, Bucket, Key, UploadId, **kwargs): url=url, headers=headers)) for j in range(self._retry): - rt = self._session.get( + rt = self.send_request( + method='GET', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers) + headers=headers, + timeout=10) + if rt is None: + continue if rt.status_code == 200: break logger.error(rt.text) @@ -270,10 +316,14 @@ def create_bucket(self, Bucket, **kwargs): url=url, headers=headers)) for j in range(self._retry): - rt = self._session.put( + rt = self.send_request( + method='PUT', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers) + headers=headers, + timeout=10) + if rt is None: + continue if rt.status_code == 200: break logger.error(rt.text) @@ -287,10 +337,14 @@ def delete_bucket(self, Bucket, **kwargs): url=url, headers=headers)) for j in range(self._retry): - rt = self._session.delete( + rt = self.send_request( + method='DELETE', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers) + headers=headers, + timeout=10) + if rt is None: + continue if rt.status_code == 204: break logger.error(rt.text) @@ -310,11 +364,15 @@ def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxK 'max-keys': MaxKeys, 'prefix': Prefix} for j in range(self._retry): - rt = self._session.get( + rt = self.send_request( + method='GET', url=url, params=params, headers=headers, + timeout=10, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) + if rt is None: + continue if rt.status_code == 200: break logger.error(rt.text) @@ -328,10 +386,14 @@ def head_object(self, Bucket, Key, **kwargs): url=url, headers=headers)) for j in range(self._retry): - rt = self._session.head( + rt = self.send_request( + method='HEAD', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers) + headers=headers, + timeout=10) + if rt is None: + continue if rt.status_code == 200: break logger.error(rt.text) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 804b8397..05fd7863 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -52,7 +52,7 @@ def Test(): print "Test Put Object " + file_name response = client.put_object( Bucket='test01', - Body='TY'*1024*512*file_size, + Body='T'*1024*1024*file_size, Key=file_name, CacheControl='no-cache', ContentDisposition='download.txt', From c44da00c1f61a0c0c235881c92bd671edb61da07 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 31 Jul 2017 15:18:56 +0800 Subject: [PATCH 30/71] fix up encoding error --- qcloud_cos/cos_client.py | 6 +++--- qcloud_cos/test.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index ea6ec8cf..1764e98f 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -14,8 +14,8 @@ filename='cos_s3.log', filemode='w') logger = logging.getLogger(__name__) -fs_coding = sys.getfilesystemencoding() - +reload(sys) +sys.setdefaultencoding('utf-8') maplist = { 'ContentLength': 'Content-Length', 'ContentType': 'Content-Type', @@ -38,7 +38,7 @@ def to_unicode(s): if isinstance(s, unicode): return s else: - return s.decode(fs_coding) + return s.decode('utf-8') def dict_to_xml(data): diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 05fd7863..bdb69fbd 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -8,7 +8,7 @@ from cos_client import CosS3Client from cos_client import CosConfig -ACCESS_ID = os.environ["ACCESS_ID"] +ACCESS_ID = os.environ["ACCESS_ID"] ACCESS_KEY = os.environ["ACCESS_KEY"] From 18f5220d5e691626b4919d771176c3ed579432ec Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 31 Jul 2017 15:21:12 +0800 Subject: [PATCH 31/71] fix up logical errors --- qcloud_cos/test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index bdb69fbd..ef87d6f5 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -8,10 +8,9 @@ from cos_client import CosS3Client from cos_client import CosConfig -ACCESS_ID = os.environ["ACCESS_ID"] +ACCESS_ID = os.environ["ACCESS_ID"] ACCESS_KEY = os.environ["ACCESS_KEY"] - def gen_file(path, size): _file = open(path, 'w') _file.seek(1024*1024*size) From 26c23e9135588bb2f86f0ef706da65866cc97b24 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 31 Jul 2017 15:26:05 +0800 Subject: [PATCH 32/71] fix up pep8 --- qcloud_cos/test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index ef87d6f5..05fd7863 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -11,6 +11,7 @@ ACCESS_ID = os.environ["ACCESS_ID"] ACCESS_KEY = os.environ["ACCESS_KEY"] + def gen_file(path, size): _file = open(path, 'w') _file.seek(1024*1024*size) From 46ff4e461cc60aa1438d2e0bf230558d4edce121 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 31 Jul 2017 21:31:21 +0800 Subject: [PATCH 33/71] fix up the timeout setup --- qcloud_cos/cos_client.py | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 1764e98f..2a76ee0d 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -122,18 +122,18 @@ def __init__(self, conf, retry=1, session=None): else: self._session = session - def send_request(self, method, url, **kwargs): + def send_request(self, method, url, timeout=20, **kwargs): try: if method == 'POST': - res = self._session.post(url, **kwargs) + res = self._session.post(url, timeout=timeout, **kwargs) elif method == 'GET': - res = self._session.get(url, **kwargs) + res = self._session.get(url, timeout=timeout, **kwargs) elif method == 'PUT': - res = self._session.put(url, **kwargs) + res = self._session.put(url, timeout=timeout, **kwargs) elif method == 'DELETE': - res = self._session.delete(url, **kwargs) + res = self._session.delete(url, timeout=timeout, **kwargs) elif method == 'HEAD': - res = self._session.head(url, **kwargs) + res = self._session.head(url, timeout=timeout, **kwargs) return res except Exception as e: logger.exception('url:%s, exception:%s' % (url, str(e))) @@ -151,8 +151,7 @@ def put_object(self, Bucket, Body, Key, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body, - headers=headers, - timeout=10) + headers=headers) if rt is None: continue if rt.status_code == 200: @@ -212,8 +211,7 @@ def create_multipart_upload(self, Bucket, Key, **kwargs): method='POST', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers, - timeout=10) + headers=headers) if rt is None: continue if rt.status_code == 200: @@ -255,10 +253,10 @@ def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, * rt = self.send_request( method='POST', url=url, + timeout=600, # 完成分片上传的超时时间设置为10分钟 auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=dict_to_xml(MultipartUpload), - headers=headers, - timeout=600) # 完成分片上传的超时时间设置为10分钟 + headers=headers) if rt is None: continue if rt.status_code == 200: @@ -278,8 +276,7 @@ def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): method='DELETE', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers, - timeout=10) + headers=headers) if rt is None: continue if rt.status_code == 200: @@ -299,8 +296,7 @@ def list_parts(self, Bucket, Key, UploadId, **kwargs): method='GET', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers, - timeout=10) + headers=headers) if rt is None: continue if rt.status_code == 200: @@ -320,8 +316,7 @@ def create_bucket(self, Bucket, **kwargs): method='PUT', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers, - timeout=10) + headers=headers) if rt is None: continue if rt.status_code == 200: @@ -341,8 +336,7 @@ def delete_bucket(self, Bucket, **kwargs): method='DELETE', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers, - timeout=10) + headers=headers) if rt is None: continue if rt.status_code == 204: @@ -369,7 +363,6 @@ def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxK url=url, params=params, headers=headers, - timeout=10, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) if rt is None: continue @@ -390,8 +383,7 @@ def head_object(self, Bucket, Key, **kwargs): method='HEAD', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers, - timeout=10) + headers=headers) if rt is None: continue if rt.status_code == 200: From e9a362cca4def74c5da966c4217e24529f76f74b Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 31 Jul 2017 21:42:32 +0800 Subject: [PATCH 34/71] set the timeout=60 to make sure the ut pass --- qcloud_cos/cos_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 2a76ee0d..3607a33f 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -114,7 +114,7 @@ def uri(self, bucket, path=None): class CosS3Client(object): """cos客户端类,封装相应请求""" - def __init__(self, conf, retry=1, session=None): + def __init__(self, conf, retry=2, session=None): self._conf = conf self._retry = retry # 重试的次数,分片上传时可适当增大 if session is None: @@ -122,7 +122,7 @@ def __init__(self, conf, retry=1, session=None): else: self._session = session - def send_request(self, method, url, timeout=20, **kwargs): + def send_request(self, method, url, timeout=60, **kwargs): try: if method == 'POST': res = self._session.post(url, timeout=timeout, **kwargs) From 16e64f58c124a8c0ab83a19363e88e16b53e784b Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 31 Jul 2017 21:52:57 +0800 Subject: [PATCH 35/71] set the retry=2 --- qcloud_cos/cos_client.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 3607a33f..350b31ac 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -233,8 +233,7 @@ def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): method='PUT', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - data=Body, - timeout=10) + data=Body) if rt is None: continue if rt.status_code == 200: From df80f7d4f81b2ee029c66a971c0167b3f69e7f94 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Tue, 1 Aug 2017 11:46:49 +0800 Subject: [PATCH 36/71] Add the Exception Module --- qcloud_cos/cos_auth.pyc | Bin 0 -> 3544 bytes qcloud_cos/cos_client.py | 119 +++++++++-------------------------- qcloud_cos/cos_client.pyc | Bin 0 -> 12837 bytes qcloud_cos/cos_exception.py | 14 +++++ qcloud_cos/cos_exception.pyc | Bin 0 -> 1380 bytes qcloud_cos/cos_s3.log | 36 +++++++++++ qcloud_cos/test.py | 8 +-- 7 files changed, 85 insertions(+), 92 deletions(-) create mode 100644 qcloud_cos/cos_auth.pyc create mode 100644 qcloud_cos/cos_client.pyc create mode 100644 qcloud_cos/cos_exception.py create mode 100644 qcloud_cos/cos_exception.pyc create mode 100644 qcloud_cos/cos_s3.log diff --git a/qcloud_cos/cos_auth.pyc b/qcloud_cos/cos_auth.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43b8f32722519ec4e5b584175609bf82ad793cfd GIT binary patch literal 3544 zcmcImOLH4V5bj;cYg?8hzhcLEI0_+&DpiU}Q9zYrCy-E(1Leb-OH{ztT053jT508- zQ65OD9GqXkfinmG2EQdgf(tkJx@RTlz|oPkt)A|letgq2JB7cOOK;!5ebJ=+Q^5b% zc=Vqj5q=IOM2#8mP{WzZU23>fzCew_lrK`FD7;IFOT9U2%#p*s3Y2)%^Qht3agmaF z>Mc-XfgDw&&LXK2ogu^$MRTMU=mfDmdPj6d^rBH_bu>?1m$E;oFUcL%7LaKCFFuDg z2dtR`IUS}(*&(ZkSuzMS{ek40p=m!2wK9uPKTGw|=Pa3_;6nNokG=t-Q2(^%cSsI3 zyPOjW_K#`|SiEwNs96NZ4^MuEN8bb)J2WN=z_`L-SP({#JCYm^#fd4wJP4ajrF9TT zW{HPdH8W*`u6kqUd8}R!;!M>zjA5cxaw0XH&to?qO!F|zXMv*{6a55aHwsO-3tY^@ z-FDhjyCzoAaJQN2`rwUer~SH)y7iY|?4CB0bQlFturde%)B{*But5;_V-o}wcFK{+ zS;V)=5Uk;0xj^w8Fae4VQODuMoVa9M>HrD|i@fF&@CEA3amQf@h__h;wMUa8#WFwe z2sprwC(IFYK+mA9fZceGg!f4iRJ` z=OE6`T#4gRzm}_VpYJI~hQ(a?W`o9y zd2ATiBF?BdDNXUZMB|c0%3LP1Nu5p36SfneR*}dnGzPy)S0V&j;)d;PVG6kuz;%T> z+p>tuG+w68Rd$EjPP8s_5g$oi7Tq=RjA@sq!8c{GfK0wv<~nt5NPr!lmpex%$ka)N zas%K6A2#$%yE65DK>dYWp1a+YDrG`iYpz z4w#|^yQA7|?5ab(sf4GTqoSLi{LZTaDSd4xx=gK+h7vZBN6 zraP*!!J*IFR#-Vqlk}C!gwum0HuhL$Z(0tMi#<{HldyLjg^&5*)p$sAwWFTGi4;vr zqjstd{!nSy(>zvTq%v@Zj~{C$CnFn*%$myanHvin1(@?Aa9jlgICz_47vN~dF^!)~ z*q56*DwHl06Q36fFBj4rsX)4nzmqiUg{G=awpW#v z938g;6Zh2Q(MUy>lX`P;ypKsD$h9&_x5I~}kxVO%cmNFLy#hz}-2$0j=GZ0+Od9C8 z)ki>izkubJ5{3+WuK5k@X`Ki4FlnV(Y}&m8_I&rW9(E5#VRr&f^c?nJ#H>vha=5Eo zF}Ru3E?GT^wKm+Tp^6ej~<6%o|(GmGQ zOJ#2)!zgYVQT4)ssA8jf+J_hG#`dh34notG)j&kmZ>EuLw@w=OC8ACaH!kJ-rt!z9u9DivG=&PdL6|r)GuM$y|5`x`s$U>d)JrlX2NjQ_0INNz<27cAL2($anvQ*81a z;)9*#-(}6GAm__!2Fb;?mbearW|$;Fz+It#1R3}+2R64Hrdy8Z@`caC_nvbNx<$w~+^degqAtLB5cI>I3Icn-4SH!b zOfdAhe*b%r^Ad%-h|8(Z4J}6(FSqBG=km&XVcZXb8ms(0CemGe!1`Z-NQ-gD$NiS{ zuH6T0o^LJvfbYLPpT^R|EoFX?9pXP{C-<3f@Q+ZGl(28{d&~*wO^`B{#C}&C{#FW` HkIK$}Ami$< literal 0 HcmV?d00001 diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 350b31ac..4de0ebd7 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -1,5 +1,7 @@ # -*- coding=utf-8 from cos_auth import CosS3Auth +from cos_exception import UserDefinedError +from cos_exception import ServerError import requests import logging import sys @@ -124,19 +126,26 @@ def __init__(self, conf, retry=2, session=None): def send_request(self, method, url, timeout=60, **kwargs): try: - if method == 'POST': - res = self._session.post(url, timeout=timeout, **kwargs) - elif method == 'GET': - res = self._session.get(url, timeout=timeout, **kwargs) - elif method == 'PUT': - res = self._session.put(url, timeout=timeout, **kwargs) - elif method == 'DELETE': - res = self._session.delete(url, timeout=timeout, **kwargs) - elif method == 'HEAD': - res = self._session.head(url, timeout=timeout, **kwargs) - return res + for j in range(self._retry): + if method == 'POST': + res = self._session.post(url, timeout=timeout, **kwargs) + elif method == 'GET': + res = self._session.get(url, timeout=timeout, **kwargs) + elif method == 'PUT': + res = self._session.put(url, timeout=timeout, **kwargs) + elif method == 'DELETE': + res = self._session.delete(url, timeout=timeout, **kwargs) + elif method == 'HEAD': + res = self._session.head(url, timeout=timeout, **kwargs) + if res.status_code == 200 or res.status_code == 204: + return res + if res.status_code < 500: + raise UserDefinedError(res.text) + elif res.status_code >= 500: + raise ServerError(res.text) except Exception as e: logger.exception('url:%s, exception:%s' % (url, str(e))) + raise e def put_object(self, Bucket, Body, Key, **kwargs): """单文件上传接口,适用于小文件,最大不得超过5GB""" @@ -166,17 +175,11 @@ def get_object(self, Bucket, Key, **kwargs): logger.info("get object, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='GET', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - if rt is None: - continue - if rt.status_code == 200: - break - logger.error(rt.text) return rt def delete_object(self, Bucket, Key, **kwargs): @@ -186,17 +189,11 @@ def delete_object(self, Bucket, Key, **kwargs): logger.info("delete object, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='DELETE', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - if rt is None: - continue - if rt.status_code == 204: - break - logger.error(rt.text) return rt def create_multipart_upload(self, Bucket, Key, **kwargs): @@ -206,17 +203,11 @@ def create_multipart_upload(self, Bucket, Key, **kwargs): logger.info("create multipart upload, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='POST', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - if rt is None: - continue - if rt.status_code == 200: - break - logger.error(rt.text) return rt def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): @@ -228,17 +219,11 @@ def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): logger.info("put object, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='PUT', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body) - if rt is None: - continue - if rt.status_code == 200: - break - logger.error(rt.text) return rt def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, **kwargs): @@ -248,19 +233,13 @@ def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, * logger.info("complete multipart upload, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='POST', url=url, timeout=600, # 完成分片上传的超时时间设置为10分钟 auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=dict_to_xml(MultipartUpload), headers=headers) - if rt is None: - continue - if rt.status_code == 200: - break - logger.error(rt.text) return rt def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): @@ -270,17 +249,11 @@ def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): logger.info("abort multipart upload, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='DELETE', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - if rt is None: - continue - if rt.status_code == 200: - break - logger.error(rt.text) return rt def list_parts(self, Bucket, Key, UploadId, **kwargs): @@ -290,17 +263,11 @@ def list_parts(self, Bucket, Key, UploadId, **kwargs): logger.info("list multipart upload, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='GET', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - if rt is None: - continue - if rt.status_code == 200: - break - logger.error(rt.text) return rt def create_bucket(self, Bucket, **kwargs): @@ -310,17 +277,11 @@ def create_bucket(self, Bucket, **kwargs): logger.info("create bucket, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='PUT', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - if rt is None: - continue - if rt.status_code == 200: - break - logger.error(rt.text) return rt def delete_bucket(self, Bucket, **kwargs): @@ -330,17 +291,11 @@ def delete_bucket(self, Bucket, **kwargs): logger.info("delete bucket, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='DELETE', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - if rt is None: - continue - if rt.status_code == 204: - break - logger.error(rt.text) return rt def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys=100, Prefix="", **kwargs): @@ -356,18 +311,12 @@ def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxK 'marker': Marker, 'max-keys': MaxKeys, 'prefix': Prefix} - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='GET', url=url, params=params, headers=headers, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) - if rt is None: - continue - if rt.status_code == 200: - break - logger.error(rt.text) return rt def head_object(self, Bucket, Key, **kwargs): @@ -377,17 +326,11 @@ def head_object(self, Bucket, Key, **kwargs): logger.info("head object, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( + rt = self.send_request( method='HEAD', url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - if rt is None: - continue - if rt.status_code == 200: - break - logger.error(rt.text) return rt diff --git a/qcloud_cos/cos_client.pyc b/qcloud_cos/cos_client.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f395466b87f36789b344ec472810e46c841c8b34 GIT binary patch literal 12837 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 literal 0 HcmV?d00001 diff --git a/qcloud_cos/cos_s3.log b/qcloud_cos/cos_s3.log new file mode 100644 index 00000000..40dba25b --- /dev/null +++ b/qcloud_cos/cos_s3.log @@ -0,0 +1,36 @@ +Tue, 01 Aug 2017 11:43:18 cos_client.py[line:97] INFO config parameter-> appid: 1252448703, region: cn-north +Tue, 01 Aug 2017 11:43:18 cos_client.py[line:156] INFO put object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp440144_2MB ,headers=:{'x-cos-acl': 'public-read', 'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} +Tue, 01 Aug 2017 11:43:18 cos_client.py[line:177] INFO get object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp440144_2MB ,headers=:{} +Tue, 01 Aug 2017 11:43:19 cos_client.py[line:328] INFO head object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp440144_2MB ,headers=:{} +Tue, 01 Aug 2017 11:43:19 cos_client.py[line:191] INFO delete object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp440144_2MB ,headers=:{} +Tue, 01 Aug 2017 11:43:19 cos_client.py[line:307] INFO list objects, url=:http://test01-1252448703.cn-north.myqcloud.com ,headers=:{} +Tue, 01 Aug 2017 11:43:19 cos_client.py[line:279] INFO create bucket, url=:http://test02-1252448703.cn-north.myqcloud.com ,headers=:{'x-cos-acl': 'public-read'} +Tue, 01 Aug 2017 11:43:21 cos_client.py[line:147] ERROR url:http://test02-1252448703.cn-north.myqcloud.com, exception: + + BucketAlreadyExists + The requested bucket name is not available. + test02-1252448703.cn-north.myqcloud.com + NTk3ZmY4ZDhfMmZiNTM1MGFfNzk4Ml9mZThhZg== + OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTBjYzE2MjAxN2M1MzJiOTdkZjMxMDVlYTZjN2FiMmI0YjVlZTZkNWJhZWY0YzhmMTJiMzlmOTFmNWFmOTI0MDk= + + +Traceback (most recent call last): + File "/data/part1/home/tiedu/cos-python-sdk-v5/qcloud_cos/cos_client.py", line 143, in send_request + raise UserDefinedError(res.text) +UserDefinedError: + + BucketAlreadyExists + The requested bucket name is not available. + test02-1252448703.cn-north.myqcloud.com + NTk3ZmY4ZDhfMmZiNTM1MGFfNzk4Ml9mZThhZg== + OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTBjYzE2MjAxN2M1MzJiOTdkZjMxMDVlYTZjN2FiMmI0YjVlZTZkNWJhZWY0YzhmMTJiMzlmOTFmNWFmOTI0MDk= + + + +Tue, 01 Aug 2017 11:43:21 cos_client.py[line:293] INFO delete bucket, url=:http://test02-1252448703.cn-north.myqcloud.com ,headers=:{} +Tue, 01 Aug 2017 11:43:22 cos_client.py[line:205] INFO create multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} +Tue, 01 Aug 2017 11:43:22 cos_client.py[line:251] INFO abort multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=150155900239f9b832787e69ae5d294f4ca43f739962502b4d033234e08f35fa98c8988abd ,headers=:{} +Tue, 01 Aug 2017 11:43:22 cos_client.py[line:205] INFO create multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} +Tue, 01 Aug 2017 11:43:22 cos_client.py[line:221] INFO put object, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?partNumber=1&uploadId=15015590026d355bbfd6a9076b62b77d4db1db00c4bf3dd169d36b070e7ddbc1e562b1110a ,headers=:{} +Tue, 01 Aug 2017 11:43:23 cos_client.py[line:265] INFO list multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=15015590026d355bbfd6a9076b62b77d4db1db00c4bf3dd169d36b070e7ddbc1e562b1110a ,headers=:{} +Tue, 01 Aug 2017 11:43:23 cos_client.py[line:235] INFO complete multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=15015590026d355bbfd6a9076b62b77d4db1db00c4bf3dd169d36b070e7ddbc1e562b1110a ,headers=:{} diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 05fd7863..19c2bb7b 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -89,14 +89,14 @@ def Test(): print "Test Create Bucket" response = client.create_bucket( - Bucket='test02', - ACL='public-read' - ) + Bucket='test'+file_id, + ACL='public-read' + ) assert response.status_code == 200 print "Test Delete Bucket" response = client.delete_bucket( - Bucket='test02' + Bucket='test'+file_id ) assert response.status_code == 204 From a4339230e889dca029f0d2fc9de43961978edb43 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Tue, 1 Aug 2017 11:55:37 +0800 Subject: [PATCH 37/71] Add Exception Moudle --- qcloud_cos/cos_auth.pyc | Bin 3544 -> 0 bytes qcloud_cos/cos_client.pyc | Bin 12837 -> 0 bytes qcloud_cos/cos_exception.pyc | Bin 1380 -> 0 bytes qcloud_cos/cos_s3.log | 36 ----------------------------------- 4 files changed, 36 deletions(-) delete mode 100644 qcloud_cos/cos_auth.pyc delete mode 100644 qcloud_cos/cos_client.pyc delete mode 100644 qcloud_cos/cos_exception.pyc delete mode 100644 qcloud_cos/cos_s3.log diff --git a/qcloud_cos/cos_auth.pyc b/qcloud_cos/cos_auth.pyc deleted file mode 100644 index 43b8f32722519ec4e5b584175609bf82ad793cfd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3544 zcmcImOLH4V5bj;cYg?8hzhcLEI0_+&DpiU}Q9zYrCy-E(1Leb-OH{ztT053jT508- zQ65OD9GqXkfinmG2EQdgf(tkJx@RTlz|oPkt)A|letgq2JB7cOOK;!5ebJ=+Q^5b% zc=Vqj5q=IOM2#8mP{WzZU23>fzCew_lrK`FD7;IFOT9U2%#p*s3Y2)%^Qht3agmaF z>Mc-XfgDw&&LXK2ogu^$MRTMU=mfDmdPj6d^rBH_bu>?1m$E;oFUcL%7LaKCFFuDg z2dtR`IUS}(*&(ZkSuzMS{ek40p=m!2wK9uPKTGw|=Pa3_;6nNokG=t-Q2(^%cSsI3 zyPOjW_K#`|SiEwNs96NZ4^MuEN8bb)J2WN=z_`L-SP({#JCYm^#fd4wJP4ajrF9TT zW{HPdH8W*`u6kqUd8}R!;!M>zjA5cxaw0XH&to?qO!F|zXMv*{6a55aHwsO-3tY^@ z-FDhjyCzoAaJQN2`rwUer~SH)y7iY|?4CB0bQlFturde%)B{*But5;_V-o}wcFK{+ zS;V)=5Uk;0xj^w8Fae4VQODuMoVa9M>HrD|i@fF&@CEA3amQf@h__h;wMUa8#WFwe z2sprwC(IFYK+mA9fZceGg!f4iRJ` z=OE6`T#4gRzm}_VpYJI~hQ(a?W`o9y zd2ATiBF?BdDNXUZMB|c0%3LP1Nu5p36SfneR*}dnGzPy)S0V&j;)d;PVG6kuz;%T> z+p>tuG+w68Rd$EjPP8s_5g$oi7Tq=RjA@sq!8c{GfK0wv<~nt5NPr!lmpex%$ka)N zas%K6A2#$%yE65DK>dYWp1a+YDrG`iYpz z4w#|^yQA7|?5ab(sf4GTqoSLi{LZTaDSd4xx=gK+h7vZBN6 zraP*!!J*IFR#-Vqlk}C!gwum0HuhL$Z(0tMi#<{HldyLjg^&5*)p$sAwWFTGi4;vr zqjstd{!nSy(>zvTq%v@Zj~{C$CnFn*%$myanHvin1(@?Aa9jlgICz_47vN~dF^!)~ z*q56*DwHl06Q36fFBj4rsX)4nzmqiUg{G=awpW#v z938g;6Zh2Q(MUy>lX`P;ypKsD$h9&_x5I~}kxVO%cmNFLy#hz}-2$0j=GZ0+Od9C8 z)ki>izkubJ5{3+WuK5k@X`Ki4FlnV(Y}&m8_I&rW9(E5#VRr&f^c?nJ#H>vha=5Eo zF}Ru3E?GT^wKm+Tp^6ej~<6%o|(GmGQ zOJ#2)!zgYVQT4)ssA8jf+J_hG#`dh34notG)j&kmZ>EuLw@w=OC8ACaH!kJ-rt!z9u9DivG=&PdL6|r)GuM$y|5`x`s$U>d)JrlX2NjQ_0INNz<27cAL2($anvQ*81a z;)9*#-(}6GAm__!2Fb;?mbearW|$;Fz+It#1R3}+2R64Hrdy8Z@`caC_nvbNx<$w~+^degqAtLB5cI>I3Icn-4SH!b zOfdAhe*b%r^Ad%-h|8(Z4J}6(FSqBG=km&XVcZXb8ms(0CemGe!1`Z-NQ-gD$NiS{ zuH6T0o^LJvfbYLPpT^R|EoFX?9pXP{C-<3f@Q+ZGl(28{d&~*wO^`B{#C}&C{#FW` HkIK$}Ami$< diff --git a/qcloud_cos/cos_client.pyc b/qcloud_cos/cos_client.pyc deleted file mode 100644 index f395466b87f36789b344ec472810e46c841c8b34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12837 zcmdT~TW}OtdOkfGjWj|+TxD3tc)V*Z1J)pWU62j&WkJ#!YC*6)!WZq5$uQlLTAGXK z?!jU~Yu1Pb-@vJ5?e*G8*}Hb^WG}Eu)tUe{$y4%>*Hq;p4|&iCxss|pB&kZ}CHcPp zbkB?~;0p?|5p(+7`<(y({@Xd-@b7Ic8~^K>r*bOzw+zp3;O9MKC}rWlq4G)<3^iyd zgXM_IM^vFf4L0aP_Q`6e~k6y}@NU~`y{tHBm!$JFRD zWi?8sRaqE?&gc_YR*SOGgvvH`QZ*Xv+NSK~>LixcuIv@cZerfRV|1mmq``2OE2~{u zE7Ud%b*u1Lt*kY8tW{PA9(O2f9UkkI^(8#+RQSKm`W?8K>T}(at6Rv(wCx_TU8(H%8&Q$BkJx!XhTKreEo6PK2ieYK*30=$!QSL0I+H_A z-Y#ZY_)Z>EZtqO;Q7mn;4x&{i(9I|nY|qOMqpRP9d918&4;6fGE$7U3B|5D{=b=RB zQ;E)9+dKDe?@as6d~qv@58n3lhlNvZWZu=xbFp6cbuAJK2yVd6kf_4-=nK7Fiu~V#cOL<>r zWKB@vt*(to^*Y{o$#Z-MombWB>#99+CwM`sub3-Y4wl|ttE|?Me0>w+jthcv851c` zCRMQgY$~x?NV6At5IE}*1iCq!%li!|?daL#t*h1!yIBxvsGQGZ4!sR7<1to$6Sd)1 zR?ZvowCnh`kVLvZ!J=$Hzf4c-+F46rD1A(nge1C)=a*cdA(hK#Jx^$t)-^q>kbT(! z5mG++L-K|sAcJybJAd32k?Gxw#8>J#QbV1DY^-KJjo)a5stH1$hEhr=Bk0&)15A=L z$YvbRDSCdkn6m|=<)Q;N*dhX!&8(IdzST=2QIdE&kn1MByT`Mx|3LRhsbF{ej%}5@ z$(iw^{z$2q@~pAck*(c_bNN!)%AkRbnOxohPPd>B0p^!7!Am!y4b&HthB}U7G}!E9M2d~-ctjK)v@vNBW7n}J<$haXm!nXc7)*T) zB{K1^?1GN#dk_AznrsN?Yh;f}OdM0k8|tPwA5NiFDyIlmfVW@--rcB1kz!eK(io#L z$9lBs{|1!yoEc}r8ROMO1v56wj935^`n(yN>t{S3m3CRO5fo%K2I#<%QJMMhchwV| z8MdN@73m};-n$>k<6EacxOV;gdlQBH%$rv$SI_<1)fX!le>nT$k1D6$x&G5B%gOn( zAN+FWrJqe-x{OZ#9b`(WFrK%4dv7`KJH)|(@q7saK)tjdMbGO*Zg=rWHt$#o)Ie?e zw%f(5?1NMa9Ps!suJzsb7OISscG9dF%-hwsdq{1zge6a0a&2f` zY2-qsM&$HxhCU>~1jH5+KCxA#7y<;+AKa)Yy6OYfwdZPhI8m3|ET77 z;^%z@i4Cs{t`$;Kr z5W@!z0)~JOde`9 z%5J_)zkS5_$G3NPA3IdejoJQW>R8#aCbxwA+)_BIy@oBhQlb0Uc-9}86hiCnq6IO) zd>AtcPuQb;-=~{b&@a3-@5D&+5hjl!(G5K;?q>2WB>I(Ze#zNL7L{EmhlkgJL`7oY zV5@L(RfEp8M*5S)u~s`71{j%)hHwS}K{?N&pgUuga+!>|i=D~%{!-C4_aakUx8#<_ zgEN00Ge3!+_-!#DE*=lU3WQ-j;^=W>@{b!3<@7Ex^OO?;PpYK|!(^(cXrQ71z$xf0 zXpNX;5b`!j20mP~WDx$wCDWoDpt3~>m{TE)TrL^Jz7qa2MF5O+ zm6}3mzCs}oX3v#WkPOxW1?g3O{WEIBUtG{?vU2eUvp+vY1$p`W?1lGde)FtD{hK4% z`D1|?@(9vJwWI~Fv{||L6I}3NPof({x=|J5p$?UE0&TRT1YQ z)CsY;K7xZ{=KT?TfujS)#4ZrXqh z&gr1k6UA*RiimQoMY%76NKMLs_c{t`K!gHks$CtIfMzJ7I%twn;>?D65+K!qLcbtp z|GxBqs2ZM#l*+#7#mD*v2)RSiJU#oLjshNjKsyVA{rmI%>fk6Cs;>$!fAqj+pw*l<9Iu9W7&*Cqz^qZQ9y`k z{W4-rc)=#UOKJ7tWSbOAG1PtGo3*j$!9jH~CSBMhfoW2N@4)Xa zL&S|6&5^Y~|uP-2s&|Z=9&S{qFRomnt8=I{VvGv)4{BEjYW-D$0~4 z3b^wqB9wxv@s}LLEtnR>%V^@gf|6KQ6=^l@1Vm#-3!oauGlsHugkq?V8f&yOODBh$ z67a%c3V0jHcAV7&SOSEq;FTByxSkJQKo~Hi&6Nm*BgM%GV2WnIRKpih3xKF$iX$2g zP>zg3C?ExCp|Tw7*5T}h*$+O@IGYC@Xs^!*o$q41<~WihsrWHiSp*^CiVGUd!<@il zGLQGr1xxM$h@*;a2TcD3UJ-b@HKvCwkAI=qTsiaRN3XrTfXylFP#dMs$mu^IXTFG> zZmaG*VD?{qT4tZd02-v5$~2779W+W+xz^_kVmM%H7Ra@}Dbvk3l)aH$2P3O;O)>Mx z%*vV9D_1U8&iwHDbEmZlnPWWOez)Gb)X6&?h)2tED(ZQ^i-JDvOBBKr(}ZsPv_^#C z{udG-JT}%e$W&>N(KPs5G*#8Y-GMErQw#L;$PoTS`@e<^k)qGtt2~{n{ecvoW56~b zunZiFh+qf$U84q`GFQgq^cm_8@8`PIF1ZPbl&TuURoMEIKVi2}-a0c`NYPvbR(7&Ok zYLlBKaoUMo&K1+{ayq#jEA{BeRet^A%$b+xX|3y5rf_OedHF0(z(cJ?PnU4KeD;C8 zJG&|`|7qpSYtvVMI(zMW<@G=L==^K57cSH(wKbSJP-=5ANPc?1hXiMKaxt_tdXBM{ z^CbMyIy{o2^Btg%$D_Fw!)iWp9VoeUxp|&OR?t`l>wR;8N*9^u zgw;cos$={kZU|Zmce;*C+*|WSUX;r2gKU~IvzC(9Tp(&KhaV(#B&jM=NAuc>#&>3nO7^P zF9SE)7FR*`i9tiX!F#}4#>~w_xX(LgXwFFnv7%lBkMam3n$bmY!V?5KZB?x_i2}8f zTqp5*NXOKn35CH#3?BsQ^4$V76x}vBZ`4rrfjZ)IXdc}R0}J({=b9I&2P32UtBkZr zoX3xmv_r4;kG@h8EQqro_~^R&(|YDS-nk{uoD{2z(Qk))L?0(`%JrsK)^m349GfE= z;PcAajlx-m{Ts!sATUYP_%k@9ITw`|-sDCzg-`oalA}@C`5y@W6L;ina zx88I{Z~E?=v)kOj9nhh4EF?J|!L{O7b&Y?C0_9rHed&cRlxqat@HQaJRk?<*3+coc zPFk)V#AZ+gjcOZY9kRWRg5QLPoWyN|hYRm`+oV1(7N>)syg~tB9)wtCX-}*C^h_gR<4au zq4dXxsHt6Af@(_cH_Zd=KxXojLw;4=fV>BZrXk9e@a=6oGW=c--!yIszHKzWj5@hJ zJ(TsFT#tMbCL?zDe{-Lx4V>cdk&hTP@oC^hceu8E`AN2Twr|-(S)6c&Uo)FL`P84- z(20E~?eE>^B!Kd>@&ACLpAaN~0+=z7488!i0Fx;WEKn@B+O^dJ z*{G~eZM8u*VeFpZR^}X`pXlL7pi&biaUGGN;}Jz)B49X*0JO!_0zP)h9asn?#IBE` zuMiBtD}xQdhQZbXhO3I{BbVlyQ-nI4Y2iqSFb<6ng};Fotrjyw{34~b|Ds$}AqPD` z&6B?Iz0}XljW_ o!SuwGg&w(dnm9ck#aW{!aGG?iR_8bRuDHYZ`2`~eU8n2(0BevPLI3~& diff --git a/qcloud_cos/cos_s3.log b/qcloud_cos/cos_s3.log deleted file mode 100644 index 40dba25b..00000000 --- a/qcloud_cos/cos_s3.log +++ /dev/null @@ -1,36 +0,0 @@ -Tue, 01 Aug 2017 11:43:18 cos_client.py[line:97] INFO config parameter-> appid: 1252448703, region: cn-north -Tue, 01 Aug 2017 11:43:18 cos_client.py[line:156] INFO put object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp440144_2MB ,headers=:{'x-cos-acl': 'public-read', 'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} -Tue, 01 Aug 2017 11:43:18 cos_client.py[line:177] INFO get object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp440144_2MB ,headers=:{} -Tue, 01 Aug 2017 11:43:19 cos_client.py[line:328] INFO head object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp440144_2MB ,headers=:{} -Tue, 01 Aug 2017 11:43:19 cos_client.py[line:191] INFO delete object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp440144_2MB ,headers=:{} -Tue, 01 Aug 2017 11:43:19 cos_client.py[line:307] INFO list objects, url=:http://test01-1252448703.cn-north.myqcloud.com ,headers=:{} -Tue, 01 Aug 2017 11:43:19 cos_client.py[line:279] INFO create bucket, url=:http://test02-1252448703.cn-north.myqcloud.com ,headers=:{'x-cos-acl': 'public-read'} -Tue, 01 Aug 2017 11:43:21 cos_client.py[line:147] ERROR url:http://test02-1252448703.cn-north.myqcloud.com, exception: - - BucketAlreadyExists - The requested bucket name is not available. - test02-1252448703.cn-north.myqcloud.com - NTk3ZmY4ZDhfMmZiNTM1MGFfNzk4Ml9mZThhZg== - OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTBjYzE2MjAxN2M1MzJiOTdkZjMxMDVlYTZjN2FiMmI0YjVlZTZkNWJhZWY0YzhmMTJiMzlmOTFmNWFmOTI0MDk= - - -Traceback (most recent call last): - File "/data/part1/home/tiedu/cos-python-sdk-v5/qcloud_cos/cos_client.py", line 143, in send_request - raise UserDefinedError(res.text) -UserDefinedError: - - BucketAlreadyExists - The requested bucket name is not available. - test02-1252448703.cn-north.myqcloud.com - NTk3ZmY4ZDhfMmZiNTM1MGFfNzk4Ml9mZThhZg== - OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTBjYzE2MjAxN2M1MzJiOTdkZjMxMDVlYTZjN2FiMmI0YjVlZTZkNWJhZWY0YzhmMTJiMzlmOTFmNWFmOTI0MDk= - - - -Tue, 01 Aug 2017 11:43:21 cos_client.py[line:293] INFO delete bucket, url=:http://test02-1252448703.cn-north.myqcloud.com ,headers=:{} -Tue, 01 Aug 2017 11:43:22 cos_client.py[line:205] INFO create multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} -Tue, 01 Aug 2017 11:43:22 cos_client.py[line:251] INFO abort multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=150155900239f9b832787e69ae5d294f4ca43f739962502b4d033234e08f35fa98c8988abd ,headers=:{} -Tue, 01 Aug 2017 11:43:22 cos_client.py[line:205] INFO create multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} -Tue, 01 Aug 2017 11:43:22 cos_client.py[line:221] INFO put object, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?partNumber=1&uploadId=15015590026d355bbfd6a9076b62b77d4db1db00c4bf3dd169d36b070e7ddbc1e562b1110a ,headers=:{} -Tue, 01 Aug 2017 11:43:23 cos_client.py[line:265] INFO list multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=15015590026d355bbfd6a9076b62b77d4db1db00c4bf3dd169d36b070e7ddbc1e562b1110a ,headers=:{} -Tue, 01 Aug 2017 11:43:23 cos_client.py[line:235] INFO complete multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=15015590026d355bbfd6a9076b62b77d4db1db00c4bf3dd169d36b070e7ddbc1e562b1110a ,headers=:{} From 1858f346d1c1144ec239a9a6eddecf5b88b49cc4 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Tue, 1 Aug 2017 20:23:05 +0800 Subject: [PATCH 38/71] Modify the UT to test Exception and Special Characters --- qcloud_cos/test.py | 62 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 19c2bb7b..b0534b25 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -7,6 +7,7 @@ from xml.dom.minidom import parse from cos_client import CosS3Client from cos_client import CosConfig +from cos_exception import COSServiceError ACCESS_ID = os.environ["ACCESS_ID"] ACCESS_KEY = os.environ["ACCESS_KEY"] @@ -49,22 +50,63 @@ def Test(): file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_name = "tmp" + file_id + "_" + str(file_size) + "MB" - print "Test Put Object " + file_name + print "Test Put Object That Bucket Not Exist" + file_name + try: + response = client.put_object( + Bucket='test0xx', + Body='T'*1024*1024*file_size, + Key=file_name, + CacheControl='no-cache', + ContentDisposition='download.txt' + ) + except COSServiceError as e: + print e.get_full_msg() + print e.get_error_code() + print e.get_error_msg() + print e.get_resource_location() + print e.get_trace_id() + print e.get_request_id() + + special_file_name = '对@@@/象*存储 @>?<=;:""%\###$[].^-_~{}|' + print "Test Put Object Contains Special Characters " + special_file_name response = client.put_object( - Bucket='test01', - Body='T'*1024*1024*file_size, - Key=file_name, - CacheControl='no-cache', - ContentDisposition='download.txt', - ACL='public-read' - ) + Bucket='test01', + Body='S'*1024*1024*file_size, + Key=special_file_name, + CacheControl='no-cache', + ContentDisposition='download.txt' + ) + print response.headers assert response.status_code == 200 - print "Test Get Object " + file_name + print "Test Get Object Contains Special Characters " + special_file_name response = client.get_object( + Bucket='test01', + Key=special_file_name, + ) + assert response.status_code == 200 + + print "Test Delete Object Contains Special Characters " + special_file_name + response = client.delete_object( Bucket='test01', - Key=file_name, + Key=special_file_name ) + assert response.status_code == 204 + + print "Test Put Object " + file_name + response = client.put_object( + Bucket='test01', + Body='T'*1024*1024*file_size, + Key=file_name, + CacheControl='no-cache', + ContentDisposition='download.txt' + ) + + print "Test Get Object " + file_name + response = client.get_object( + Bucket='test01', + Key=file_name, + ) assert response.status_code == 200 print "Test Head Object " + file_name From 94ffe2bbe7a376874b54b00ae454d4d83a7ddb82 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Tue, 1 Aug 2017 20:23:38 +0800 Subject: [PATCH 39/71] Modify the Exception Module --- qcloud_cos/cos_client.py | 24 +++++++-------- qcloud_cos/cos_exception.py | 61 ++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 4de0ebd7..0fcedecd 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -1,13 +1,12 @@ # -*- coding=utf-8 -from cos_auth import CosS3Auth -from cos_exception import UserDefinedError -from cos_exception import ServerError import requests import logging import sys import copy import xml.dom.minidom - +from cos_auth import CosS3Auth +from cos_exception import ClientError +from cos_exception import COSServiceError logging.basicConfig( level=logging.INFO, @@ -124,7 +123,7 @@ def __init__(self, conf, retry=2, session=None): else: self._session = session - def send_request(self, method, url, timeout=60, **kwargs): + def send_request(self, method, url, timeout=30, **kwargs): try: for j in range(self._retry): if method == 'POST': @@ -137,15 +136,16 @@ def send_request(self, method, url, timeout=60, **kwargs): res = self._session.delete(url, timeout=timeout, **kwargs) elif method == 'HEAD': res = self._session.head(url, timeout=timeout, **kwargs) - if res.status_code == 200 or res.status_code == 204: + if res.status_code < 300: return res - if res.status_code < 500: - raise UserDefinedError(res.text) - elif res.status_code >= 500: - raise ServerError(res.text) - except Exception as e: + except Exception as e: # 捕获requests抛出的如timeout等客户端错误,转化为客户端错误 logger.exception('url:%s, exception:%s' % (url, str(e))) - raise e + raise ClientError(str(e)) + + if res.status_code >= 300: # 所有的3XX,4XX,5XX都认为是COSServiceError + msg = res.text + logger.error(msg) + raise COSServiceError(msg) def put_object(self, Bucket, Body, Key, **kwargs): """单文件上传接口,适用于小文件,最大不得超过5GB""" diff --git a/qcloud_cos/cos_exception.py b/qcloud_cos/cos_exception.py index 29beacfd..e926ec30 100644 --- a/qcloud_cos/cos_exception.py +++ b/qcloud_cos/cos_exception.py @@ -1,14 +1,65 @@ +import xml.dom.minidom -class CosException(Exception): + +class COSException(Exception): + def __init__(self, message): + Exception.__init__(self, message) + + +class COSBadResponseError(COSException): def __init__(self, message): Exception.__init__(self, message) -class UserDefinedError(CosException): +def digest_xml(data): + msg = dict() + try: + tree = xml.dom.minidom.parseString(data) + root = tree.documentElement + + result = root.getElementsByTagName('Code') + msg['code'] = result[0].childNodes[0].nodeValue + + result = root.getElementsByTagName('Message') + msg['message'] = result[0].childNodes[0].nodeValue + + result = root.getElementsByTagName('Resource') + msg['resource'] = result[0].childNodes[0].nodeValue + + result = root.getElementsByTagName('RequestId') + msg['requestid'] = result[0].childNodes[0].nodeValue + + result = root.getElementsByTagName('TraceId') + msg['traceid'] = result[0].childNodes[0].nodeValue + return msg + except Exception as e: + raise COSBadResponseError("Response Error Msg Is INVALID") + + +class ClientError(COSException): def __init__(self, message): - CosException.__init__(self, message) + COSException.__init__(self, message) -class ServerError(CosException): +class COSServiceError(COSException): def __init__(self, message): - CosException.__init__(self, message) + COSException.__init__(self, message) + self._msg = digest_xml(message) + + def get_full_msg(self): + return self._msg + + def get_error_code(self): + return self._msg['code'] + + def get_error_msg(self): + return self._msg['message'] + + def get_resource_location(self): + return self._msg['resource'] + + def get_trace_id(self): + return self._msg['requestid'] + + def get_request_id(self): + return self._msg['traceid'] From aa0e3b90a9e92adaed13f123e48a743c1d7e88b1 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Tue, 1 Aug 2017 20:25:53 +0800 Subject: [PATCH 40/71] Modify the put_object Sample to remove acl set while uploading --- README.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 9543b0ba..38b10da7 100644 --- a/README.rst +++ b/README.rst @@ -42,8 +42,7 @@ __________ Body='TY'*1024*512*file_size, Key=file_name, CacheControl='no-cache', - ContentDisposition='download.txt', - ACL='public-read' + ContentDisposition='download.txt' ) # 2. 下载单个文件 From fca5e8a2f782feb86d8bd6a2ccd4bdbb9321ca8f Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 7 Aug 2017 10:26:22 +0800 Subject: [PATCH 41/71] Fix up syntax error --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 2362fb62..042d9e74 100644 --- a/setup.py +++ b/setup.py @@ -30,5 +30,4 @@ def long_description(): long_description=long_description(), packages=find_packages(), install_requires=requirements() - } ) From cb69db23d4d79fed03a8ff2d4a78285da73e1392 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 7 Aug 2017 13:16:06 +0800 Subject: [PATCH 42/71] Modify the Exception Moudle --- qcloud_cos/cos_auth.py | 1 + qcloud_cos/cos_auth.pyc | Bin 0 -> 3544 bytes qcloud_cos/cos_client.py | 3 ++- qcloud_cos/cos_client.pyc | Bin 0 -> 12828 bytes qcloud_cos/cos_exception.py | 51 ++++++++++++++++++++++++----------- qcloud_cos/cos_exception.pyc | Bin 0 -> 4403 bytes qcloud_cos/cos_s3.log | 28 +++++++++++++++++++ qcloud_cos/test.py | 9 ++++--- 8 files changed, 72 insertions(+), 20 deletions(-) create mode 100644 qcloud_cos/cos_auth.pyc create mode 100644 qcloud_cos/cos_client.pyc create mode 100644 qcloud_cos/cos_exception.pyc create mode 100644 qcloud_cos/cos_s3.log diff --git a/qcloud_cos/cos_auth.py b/qcloud_cos/cos_auth.py index 0f49b635..6cadc4e2 100644 --- a/qcloud_cos/cos_auth.py +++ b/qcloud_cos/cos_auth.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- + import hmac import time import urllib diff --git a/qcloud_cos/cos_auth.pyc b/qcloud_cos/cos_auth.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c236f7cc0aa9e1ce679412a0382a43e1a9b300bc GIT binary patch literal 3544 zcmcImOLH4V5bj+`Yg?8rzhcLEDul$UR4FD!0acEjKte$dln-kzQ2|?P?OIxCS1a#~ zk{C%Rr-~|$95{2}Z}40A5pduJU-zu!95_0XX4KQ&(~oa@9)-V_%0K`8)5{j+p920r zM^nF}3-GfjCTh-Ti<;JyZ&TBr(gkW3rgV{-MWJnqZAwbiERn^w3KTn(IMj5^xJdCF zCG*srCo3#ccY(q(ox{Z<1tkjS=>)zUdP{Up^s-rDaWF?co3h`iFTowv=MiZ1FFuEL z3#2ZgI~}GvG(#2-vv}ZV>K)D(L*04it57dM{5(}hA2Vl$f(`C7G<6eQi2SEHzeRA! z+2)v#uzOTzz@n8MqE-xE}}j>qAfL6n7ccB8pdVSFMvT+CxL?@V(r%x8h3I(OLBK-K2T%{8!N7W6)Q`01t*}w{ zMAibnErwtXt%@d4yZ}sqqD$1Zcrhn7X`8x$0?Z<>`2=)rvmkb8Qlv=c zdkz5y=<$RSAqLb8$_m(xOU&Ftvp{xHK}G5nDEos;$#8lOsb9IEWjCS7;1+m97SGw8#b9-NF>ICxGiJ zb+=^^muS31-D_+Pv#nrV=E6UMx+1dcVj0txr_MKJv4BjzSo#KaZ;FFkJTEtnN|33O zD&-2m3pR}FnRI1pbxW*PFRYr%xGL`!#J+i(jaBc{q zx1=nvlr>323IdTc>Qgla+el5}-lj1ek~78`SfhRXp@_L~O-OhCH&RpQ(BEbtbJY(- zRd&D>E$AK9?_yUSYCi0qqUf;m_^7}cSCd0-ucnzP^83;sv{;uL@5>`JwT_Onmy;D0 zW;WeXofQsU-nK%@VH&5e!%QeOh$C%|Rko(&FuB|lWk2?l|1A^PCXU1 z`*0}t3rN0{Fl5+s$uA&J8$4+EaXZZ--ANAE^8M3>-#Zxjy$L9hv)h9alO|m7VXk4= zpk`dNWQ{md`e3%$&_=m8WMy+vUJ$u`Uk|g~{zTTu@5wDWb11jh)Q>FO^X(sm$HTVhq9XEl zR+ybhghABOB1-&$h$0;(%7qnU#?-8+4t(8_)quya-%0~hZrwEMi$|4aIt;`ZI4(cI zT&^;+g?-gQ^e&$dCYu4?G3FiD3Eu=!8~KZyPU5%3NI!h-^4@i&y18Sx>ij-&`B5dy zp9x5!KSbg3iQ3V6;29*PhB7TrG>AP@ZSLLa>{kMsh)tp%BgDt3(s*FW){&BSYv7sS z*~L3M%e~K%57AvLs~*IcTUuh;^ICo!d)^fe;9GQLRjoB^U7l_gYs+d_JK(I_j`bCI z6|}1Lz+Sc2th*R3*|(r`$Krm=a%_I^Ir#2a*CAT~Z^OQ3nJ4NzjC)?+PeRW#?^`cP zgJF!J%lW%sqq|5^sLObqx?Ir9Xo{EHu`8uK^Tdz(o>%9s= 300: # 所有的3XX,4XX,5XX都认为是COSServiceError msg = res.text logger.error(msg) - raise COSServiceError(msg) + raise COSServiceError(msg, res.status_code) def put_object(self, Bucket, Body, Key, **kwargs): """单文件上传接口,适用于小文件,最大不得超过5GB""" diff --git a/qcloud_cos/cos_client.pyc b/qcloud_cos/cos_client.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9db5bb15c044c0583b846808b7c586872556fe33 GIT binary patch literal 12828 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 literal 0 HcmV?d00001 diff --git a/qcloud_cos/cos_exception.py b/qcloud_cos/cos_exception.py index e926ec30..72eb94ef 100644 --- a/qcloud_cos/cos_exception.py +++ b/qcloud_cos/cos_exception.py @@ -1,3 +1,5 @@ +# -*- coding=utf-8 + import xml.dom.minidom @@ -6,11 +8,6 @@ def __init__(self, message): Exception.__init__(self, message) -class COSBadResponseError(COSException): - def __init__(self, message): - Exception.__init__(self, message) - - def digest_xml(data): msg = dict() try: @@ -33,33 +30,57 @@ def digest_xml(data): msg['traceid'] = result[0].childNodes[0].nodeValue return msg except Exception as e: - raise COSBadResponseError("Response Error Msg Is INVALID") + return "Response Error Msg Is INVALID" class ClientError(COSException): + """Client端错误,如timeout""" def __init__(self, message): COSException.__init__(self, message) class COSServiceError(COSException): - def __init__(self, message): + """COS Server端错误,可以获取特定的错误信息""" + def __init__(self, message, status_code): COSException.__init__(self, message) - self._msg = digest_xml(message) + self._origin_msg = message + self._digest_msg = digest_xml(message) + self._status_code = status_code + + def get_origin_msg(self): + """获取原始的XML格式错误信息""" + return self._origin_msg + + def get_digest_msg(self): + """获取经过处理的dict格式的错误信息""" + return self._digest_msg - def get_full_msg(self): - return self._msg + def get_status_code(self): + """获取http error code""" + return self._status_code def get_error_code(self): - return self._msg['code'] + """获取COS定义的错误码描述,服务器返回错误信息格式出错时,返回空 """ + if isinstance(self._digest_msg, dict): + return self._digest_msg['code'] + return "" def get_error_msg(self): - return self._msg['message'] + if isinstance(self._digest_msg, dict): + return self._digest_msg['message'] + return "" def get_resource_location(self): - return self._msg['resource'] + if isinstance(self._digest_msg, dict): + return self._digest_msg['resource'] + return "" def get_trace_id(self): - return self._msg['requestid'] + if isinstance(self._digest_msg, dict): + return self._digest_msg['requestid'] + return "" def get_request_id(self): - return self._msg['traceid'] + if isinstance(self._digest_msg, dict): + return self._digest_msg['traceid'] + return "" diff --git a/qcloud_cos/cos_exception.pyc b/qcloud_cos/cos_exception.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4084fa4d8d326365fbe114ea312592393d98bc6e GIT binary patch literal 4403 zcmc&%-EUMy6rZ{K(cKm-8bC=Tu8O)U?Wzfy7($f7Llan&y98l5KL+f#+Lj`aN_3{-vl1QI;ZbgmT0w3=(2qh&drnmJ=dK(xjXeK}x6u zFQ>c9DG>~GsF^M`O?#H|S?nMFjbG7h!Eo%I(&2NynlfS3=n5mTa1c#DicVQE1b@&G zZYfX8zJrb$2|k9Vx1%#cOiD2$#EcYkj*w8qvKRBjYv|+M&zTHno)0#JhCZQbAY`7DXp7UR)RpI%K~Oxe9tF)Bru;%rkWH3`WJsg2 zG->IReQBOTW7BR01*V-7VpfXjJHkjY>4?dMm`swf=cJf*#0)4YF`E!GptG}y4hDe4 z5xXV_>?1?I0hac+*^>PFJ=juRw)94916{VvMr_$G+u%lQLtq0^-)(FcNg(F*polY4 z&ZYpTEuwUSF|`$@DH?*ySQMxbPr)-EGX~F53m%tP*t4$EQ8V@xPvXvm0O_hTO{L9v z!0?RiEDU&?V{ye-SRt?&8i#@2&F|=`sG(Kva2!W*?x?Qj#&vGIc>L`npx85Y~WYtx6^i8&xxmc@X){x@wriHAN3YfmKzVsXjP;tWqrk zrHoO3BCG{PXsucL21ds#wWe|jM0rAy6$C-U0@QVt2_{yG2XPb`LwvAFvt|G-gnSR` zn-+5{Z4g!=s0VA1;`$kMLS|(`?vPn$SU$17$&4J9Y^1STNG2g``}7w5NYsO9`f+sK zG*xye(aj@kB`8@@gzG2K*&SAXUc7Vp%If0cAGbbkegD1*>nduR`^si6HWfBA&_`VI zGvlof*5l7Sj}LS*7U9~Z1mUue37?(^zAu5SLZDjZZCbae16d<2X@*RZMF~H`jUp!gp}(! z0^vke&Q6g(k%2*n{Jok-uIZtKaqLBLSPdH<;?RAHwx>Yw+Hpa_Nk!Syh}Nb??Ftmv zrXIGKf9*2Z`%xYDVq2Y|&E+;k=&-Fy6mitpI)pi>JlWA#?*YNuw{_|3)(;=Sz9)_z zS-y6wb!%a*q4@yeJ_~L;BAfRiX3Qhl7m0I?$zKD-Mv%i*c4K`;!QIBo&4tya3$1VG zS3dm!T2WfJYORBi)raixU^MID=Jo%i*^aJe6UI#C6c;f@8(GACuI~y^og>$*LGqg* zt@jNfgR%BB28cw0n-s>O!)3g?Jw>+PRYD#qaj58%V6|RD9zc}ezJ9UmrIl;vmlxp5 zU-vG5`AO@;Z(3J=TwS`{`r@m#@U)(7UAO__^5?&yP*|RopKjz_3JC}T2a{}E)IuFL zphv@3E_vSFMyqVcegm8R##!P3zNsnQ21>Mr@_el! appid: 1252448703, region: cn-north +Mon, 07 Aug 2017 13:14:00 cos_client.py[line:157] INFO put object, url=:http://test0xx-1252448703.cn-north.myqcloud.com/tmp998379_2MB ,headers=:{'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} +Mon, 07 Aug 2017 13:14:02 cos_client.py[line:148] ERROR + + NoSuchBucket + The specified bucket does not exist. + test0xx-1252448703.cn-north.myqcloud.com/tmp998379_2MB + NTk4N2Y3MTlfNTViMjM1MGFfNmEyNV82Zjc3NQ== + OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTczMmZiNDZmZjBmNTVjMGU4NTViNDhhYWVjNzNkNzI4MGU2OTkyMWM5NTE5MGVmOTg1MDViMmE0MzdjMTc4MzY= + + + +Mon, 07 Aug 2017 13:14:02 cos_client.py[line:157] INFO put object, url=:http://test01-1252448703.cn-north.myqcloud.com/对象!"存储#$%&()*+,- ./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ,headers=:{'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} +Mon, 07 Aug 2017 13:14:02 cos_client.py[line:178] INFO get object, url=:http://test01-1252448703.cn-north.myqcloud.com/对象!"存储#$%&()*+,- ./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ,headers=:{} +Mon, 07 Aug 2017 13:14:03 cos_client.py[line:192] INFO delete object, url=:http://test01-1252448703.cn-north.myqcloud.com/对象!"存储#$%&()*+,- ./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ,headers=:{} +Mon, 07 Aug 2017 13:14:03 cos_client.py[line:157] INFO put object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp998379_2MB ,headers=:{'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} +Mon, 07 Aug 2017 13:14:03 cos_client.py[line:178] INFO get object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp998379_2MB ,headers=:{} +Mon, 07 Aug 2017 13:14:03 cos_client.py[line:329] INFO head object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp998379_2MB ,headers=:{} +Mon, 07 Aug 2017 13:14:03 cos_client.py[line:192] INFO delete object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp998379_2MB ,headers=:{} +Mon, 07 Aug 2017 13:14:03 cos_client.py[line:308] INFO list objects, url=:http://test01-1252448703.cn-north.myqcloud.com ,headers=:{} +Mon, 07 Aug 2017 13:14:03 cos_client.py[line:280] INFO create bucket, url=:http://test998379-1252448703.cn-north.myqcloud.com ,headers=:{'x-cos-acl': 'public-read'} +Mon, 07 Aug 2017 13:14:05 cos_client.py[line:294] INFO delete bucket, url=:http://test998379-1252448703.cn-north.myqcloud.com ,headers=:{} +Mon, 07 Aug 2017 13:14:10 cos_client.py[line:206] INFO create multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} +Mon, 07 Aug 2017 13:14:10 cos_client.py[line:252] INFO abort multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=1502082850f7b555cea45bee13fb0ac1a32e5486e8921021845293323a0cf8256fdcc63a3a ,headers=:{} +Mon, 07 Aug 2017 13:14:10 cos_client.py[line:206] INFO create multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} +Mon, 07 Aug 2017 13:14:10 cos_client.py[line:222] INFO put object, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?partNumber=1&uploadId=15020828507e7caa9a7121be68312ed8af4c81e80e3184918ffe0fb50d37c1ab04677b7152 ,headers=:{} +Mon, 07 Aug 2017 13:14:11 cos_client.py[line:266] INFO list multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=15020828507e7caa9a7121be68312ed8af4c81e80e3184918ffe0fb50d37c1ab04677b7152 ,headers=:{} +Mon, 07 Aug 2017 13:14:11 cos_client.py[line:236] INFO complete multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=15020828507e7caa9a7121be68312ed8af4c81e80e3184918ffe0fb50d37c1ab04677b7152 ,headers=:{} diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index b0534b25..4057cc0f 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -50,7 +50,7 @@ def Test(): file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_name = "tmp" + file_id + "_" + str(file_size) + "MB" - print "Test Put Object That Bucket Not Exist" + file_name + print "Test Put Object That Bucket Not Exist " + file_name try: response = client.put_object( Bucket='test0xx', @@ -60,14 +60,16 @@ def Test(): ContentDisposition='download.txt' ) except COSServiceError as e: - print e.get_full_msg() + print e.get_origin_msg() + print e.get_digest_msg() + print e.get_status_code() print e.get_error_code() print e.get_error_msg() print e.get_resource_location() print e.get_trace_id() print e.get_request_id() - special_file_name = '对@@@/象*存储 @>?<=;:""%\###$[].^-_~{}|' + special_file_name = '对象!"存储#$%&()*+,- ./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~' print "Test Put Object Contains Special Characters " + special_file_name response = client.put_object( Bucket='test01', @@ -76,7 +78,6 @@ def Test(): CacheControl='no-cache', ContentDisposition='download.txt' ) - print response.headers assert response.status_code == 200 print "Test Get Object Contains Special Characters " + special_file_name From 4dc6348a8dc30b32b685095613987db04cfccaec Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 7 Aug 2017 13:19:10 +0800 Subject: [PATCH 43/71] delete pyc --- qcloud_cos/cos_auth.pyc | Bin 3544 -> 0 bytes qcloud_cos/cos_client.pyc | Bin 12828 -> 0 bytes qcloud_cos/cos_exception.pyc | Bin 4403 -> 0 bytes qcloud_cos/cos_s3.log | 28 ---------------------------- 4 files changed, 28 deletions(-) delete mode 100644 qcloud_cos/cos_auth.pyc delete mode 100644 qcloud_cos/cos_client.pyc delete mode 100644 qcloud_cos/cos_exception.pyc delete mode 100644 qcloud_cos/cos_s3.log diff --git a/qcloud_cos/cos_auth.pyc b/qcloud_cos/cos_auth.pyc deleted file mode 100644 index c236f7cc0aa9e1ce679412a0382a43e1a9b300bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3544 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 diff --git a/qcloud_cos/cos_exception.pyc b/qcloud_cos/cos_exception.pyc deleted file mode 100644 index 4084fa4d8d326365fbe114ea312592393d98bc6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4403 zcmc&%-EUMy6rZ{K(cKm-8bC=Tu8O)U?Wzfy7($f7Llan&y98l5KL+f#+Lj`aN_3{-vl1QI;ZbgmT0w3=(2qh&drnmJ=dK(xjXeK}x6u zFQ>c9DG>~GsF^M`O?#H|S?nMFjbG7h!Eo%I(&2NynlfS3=n5mTa1c#DicVQE1b@&G zZYfX8zJrb$2|k9Vx1%#cOiD2$#EcYkj*w8qvKRBjYv|+M&zTHno)0#JhCZQbAY`7DXp7UR)RpI%K~Oxe9tF)Bru;%rkWH3`WJsg2 zG->IReQBOTW7BR01*V-7VpfXjJHkjY>4?dMm`swf=cJf*#0)4YF`E!GptG}y4hDe4 z5xXV_>?1?I0hac+*^>PFJ=juRw)94916{VvMr_$G+u%lQLtq0^-)(FcNg(F*polY4 z&ZYpTEuwUSF|`$@DH?*ySQMxbPr)-EGX~F53m%tP*t4$EQ8V@xPvXvm0O_hTO{L9v z!0?RiEDU&?V{ye-SRt?&8i#@2&F|=`sG(Kva2!W*?x?Qj#&vGIc>L`npx85Y~WYtx6^i8&xxmc@X){x@wriHAN3YfmKzVsXjP;tWqrk zrHoO3BCG{PXsucL21ds#wWe|jM0rAy6$C-U0@QVt2_{yG2XPb`LwvAFvt|G-gnSR` zn-+5{Z4g!=s0VA1;`$kMLS|(`?vPn$SU$17$&4J9Y^1STNG2g``}7w5NYsO9`f+sK zG*xye(aj@kB`8@@gzG2K*&SAXUc7Vp%If0cAGbbkegD1*>nduR`^si6HWfBA&_`VI zGvlof*5l7Sj}LS*7U9~Z1mUue37?(^zAu5SLZDjZZCbae16d<2X@*RZMF~H`jUp!gp}(! z0^vke&Q6g(k%2*n{Jok-uIZtKaqLBLSPdH<;?RAHwx>Yw+Hpa_Nk!Syh}Nb??Ftmv zrXIGKf9*2Z`%xYDVq2Y|&E+;k=&-Fy6mitpI)pi>JlWA#?*YNuw{_|3)(;=Sz9)_z zS-y6wb!%a*q4@yeJ_~L;BAfRiX3Qhl7m0I?$zKD-Mv%i*c4K`;!QIBo&4tya3$1VG zS3dm!T2WfJYORBi)raixU^MID=Jo%i*^aJe6UI#C6c;f@8(GACuI~y^og>$*LGqg* zt@jNfgR%BB28cw0n-s>O!)3g?Jw>+PRYD#qaj58%V6|RD9zc}ezJ9UmrIl;vmlxp5 zU-vG5`AO@;Z(3J=TwS`{`r@m#@U)(7UAO__^5?&yP*|RopKjz_3JC}T2a{}E)IuFL zphv@3E_vSFMyqVcegm8R##!P3zNsnQ21>Mr@_el! appid: 1252448703, region: cn-north -Mon, 07 Aug 2017 13:14:00 cos_client.py[line:157] INFO put object, url=:http://test0xx-1252448703.cn-north.myqcloud.com/tmp998379_2MB ,headers=:{'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} -Mon, 07 Aug 2017 13:14:02 cos_client.py[line:148] ERROR - - NoSuchBucket - The specified bucket does not exist. - test0xx-1252448703.cn-north.myqcloud.com/tmp998379_2MB - NTk4N2Y3MTlfNTViMjM1MGFfNmEyNV82Zjc3NQ== - OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTczMmZiNDZmZjBmNTVjMGU4NTViNDhhYWVjNzNkNzI4MGU2OTkyMWM5NTE5MGVmOTg1MDViMmE0MzdjMTc4MzY= - - - -Mon, 07 Aug 2017 13:14:02 cos_client.py[line:157] INFO put object, url=:http://test01-1252448703.cn-north.myqcloud.com/对象!"存储#$%&()*+,- ./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ,headers=:{'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} -Mon, 07 Aug 2017 13:14:02 cos_client.py[line:178] INFO get object, url=:http://test01-1252448703.cn-north.myqcloud.com/对象!"存储#$%&()*+,- ./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ,headers=:{} -Mon, 07 Aug 2017 13:14:03 cos_client.py[line:192] INFO delete object, url=:http://test01-1252448703.cn-north.myqcloud.com/对象!"存储#$%&()*+,- ./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ,headers=:{} -Mon, 07 Aug 2017 13:14:03 cos_client.py[line:157] INFO put object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp998379_2MB ,headers=:{'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} -Mon, 07 Aug 2017 13:14:03 cos_client.py[line:178] INFO get object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp998379_2MB ,headers=:{} -Mon, 07 Aug 2017 13:14:03 cos_client.py[line:329] INFO head object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp998379_2MB ,headers=:{} -Mon, 07 Aug 2017 13:14:03 cos_client.py[line:192] INFO delete object, url=:http://test01-1252448703.cn-north.myqcloud.com/tmp998379_2MB ,headers=:{} -Mon, 07 Aug 2017 13:14:03 cos_client.py[line:308] INFO list objects, url=:http://test01-1252448703.cn-north.myqcloud.com ,headers=:{} -Mon, 07 Aug 2017 13:14:03 cos_client.py[line:280] INFO create bucket, url=:http://test998379-1252448703.cn-north.myqcloud.com ,headers=:{'x-cos-acl': 'public-read'} -Mon, 07 Aug 2017 13:14:05 cos_client.py[line:294] INFO delete bucket, url=:http://test998379-1252448703.cn-north.myqcloud.com ,headers=:{} -Mon, 07 Aug 2017 13:14:10 cos_client.py[line:206] INFO create multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} -Mon, 07 Aug 2017 13:14:10 cos_client.py[line:252] INFO abort multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=1502082850f7b555cea45bee13fb0ac1a32e5486e8921021845293323a0cf8256fdcc63a3a ,headers=:{} -Mon, 07 Aug 2017 13:14:10 cos_client.py[line:206] INFO create multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} -Mon, 07 Aug 2017 13:14:10 cos_client.py[line:222] INFO put object, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?partNumber=1&uploadId=15020828507e7caa9a7121be68312ed8af4c81e80e3184918ffe0fb50d37c1ab04677b7152 ,headers=:{} -Mon, 07 Aug 2017 13:14:11 cos_client.py[line:266] INFO list multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=15020828507e7caa9a7121be68312ed8af4c81e80e3184918ffe0fb50d37c1ab04677b7152 ,headers=:{} -Mon, 07 Aug 2017 13:14:11 cos_client.py[line:236] INFO complete multipart upload, url=:http://test01-1252448703.cn-north.myqcloud.com/multipartfile.txt?uploadId=15020828507e7caa9a7121be68312ed8af4c81e80e3184918ffe0fb50d37c1ab04677b7152 ,headers=:{} From 64864a2938731b4c889985bcd01ad0ce2dfcbbbf Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 7 Aug 2017 14:49:41 +0800 Subject: [PATCH 44/71] Modify Timeout Description --- qcloud_cos/cos_client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 4198acb4..7dc68078 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -237,7 +237,6 @@ def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, * rt = self.send_request( method='POST', url=url, - timeout=600, # 完成分片上传的超时时间设置为10分钟 auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=dict_to_xml(MultipartUpload), headers=headers) From 786df5b5b2fd5dc1f0e986362ba014a9f59680ad Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 7 Aug 2017 14:56:28 +0800 Subject: [PATCH 45/71] Modify the return --- qcloud_cos/cos_exception.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qcloud_cos/cos_exception.py b/qcloud_cos/cos_exception.py index 72eb94ef..77643457 100644 --- a/qcloud_cos/cos_exception.py +++ b/qcloud_cos/cos_exception.py @@ -63,24 +63,24 @@ def get_error_code(self): """获取COS定义的错误码描述,服务器返回错误信息格式出错时,返回空 """ if isinstance(self._digest_msg, dict): return self._digest_msg['code'] - return "" + return "Unknown" def get_error_msg(self): if isinstance(self._digest_msg, dict): return self._digest_msg['message'] - return "" + return "Unknown" def get_resource_location(self): if isinstance(self._digest_msg, dict): return self._digest_msg['resource'] - return "" + return "Unknown" def get_trace_id(self): if isinstance(self._digest_msg, dict): return self._digest_msg['requestid'] - return "" + return "Unknown" def get_request_id(self): if isinstance(self._digest_msg, dict): return self._digest_msg['traceid'] - return "" + return "Unknown" From ef4dfe7a64348aa49347aa87b621b393aab3eb6e Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 7 Aug 2017 15:26:57 +0800 Subject: [PATCH 46/71] Modify the CompleteMultiple Timeout --- qcloud_cos/cos_client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 7dc68078..ac87859c 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -239,6 +239,7 @@ def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, * url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=dict_to_xml(MultipartUpload), + timeout=1200, # 分片上传大文件的时间比较长,设置为20min headers=headers) return rt From b7161b8139d5f74d18cd9006b138fbc4595614da Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Tue, 8 Aug 2017 10:41:42 +0800 Subject: [PATCH 47/71] Add the xml2dict to handle the response --- qcloud_cos/cos_client.py | 74 ++++++++++++++++++++++++++++++++-------- qcloud_cos/test.py | 51 +++++++++++---------------- qcloud_cos/xml2dict.py | 46 +++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 47 deletions(-) create mode 100644 qcloud_cos/xml2dict.py diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index ac87859c..aeda089f 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -5,6 +5,8 @@ import sys import copy import xml.dom.minidom +import xml.etree.ElementTree +from xml2dict import Xml2Dict from cos_auth import CosS3Auth from cos_exception import ClientError from cos_exception import COSServiceError @@ -49,11 +51,11 @@ def dict_to_xml(data): root = doc.createElement('CompleteMultipartUpload') doc.appendChild(root) - if 'Parts' not in data.keys(): - logger.error("Invalid Parameter, Parts Is Required!") + if 'Part' not in data.keys(): + logger.error("Invalid Parameter, Part Is Required!") return '' - for i in data['Parts']: + for i in data['Part']: nodePart = doc.createElement('Part') if 'PartNumber' not in i.keys(): @@ -76,6 +78,22 @@ def dict_to_xml(data): return doc.toxml('utf-8') +def xml_to_dict(data): + """V5使用xml格式,将response中的xml转换为dict""" + root = xml.etree.ElementTree.fromstring(data) + xmldict = Xml2Dict(root) + return xmldict + + +def get_id_from_xml(data, name): + """解析xml中的特定字段""" + tree = xml.dom.minidom.parseString(data) + root = tree.documentElement + result = root.getElementsByTagName(name) + # use childNodes to get a list, if has no child get itself + return result[0].childNodes[0].nodeValue + + def mapped(headers): """S3到COS参数的一个映射""" _headers = dict() @@ -167,7 +185,10 @@ def put_object(self, Bucket, Body, Key, **kwargs): if rt.status_code == 200: break logger.error(rt.text) - return rt + + response = dict() + response['ETag'] = rt.headers['ETag'] + return response def get_object(self, Bucket, Key, **kwargs): """单文件下载接口""" @@ -181,7 +202,13 @@ def get_object(self, Bucket, Key, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - return rt + + response = dict() + response['Body'] = rt.text + + for k in rt.headers.keys(): + response[k] = rt.headers[k] + return response def delete_object(self, Bucket, Key, **kwargs): """单文件删除接口""" @@ -195,7 +222,7 @@ def delete_object(self, Bucket, Key, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - return rt + return None def create_multipart_upload(self, Bucket, Key, **kwargs): """创建分片上传,适用于大文件上传""" @@ -209,7 +236,9 @@ def create_multipart_upload(self, Bucket, Key, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - return rt + + data = xml_to_dict(rt.text) + return data def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): """上传分片,单个大小不得超过5GB""" @@ -225,7 +254,9 @@ def upload_part(self, Bucket, Key, Body, PartNumber, UploadId, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), data=Body) - return rt + response = dict() + response['ETag'] = rt.headers['ETag'] + return response def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, **kwargs): """完成分片上传,组装后的文件不得小于1MB,否则会返回错误""" @@ -241,7 +272,11 @@ def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, * data=dict_to_xml(MultipartUpload), timeout=1200, # 分片上传大文件的时间比较长,设置为20min headers=headers) - return rt + response = dict() + data = xml_to_dict(rt.text) + for key in data.keys(): + response[key[key.find('}')+1:]] = data[key] + return response def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): """放弃一个已经存在的分片上传任务,删除所有已经存在的分片""" @@ -255,7 +290,7 @@ def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - return rt + return None def list_parts(self, Bucket, Key, UploadId, **kwargs): """列出已上传的分片""" @@ -269,7 +304,15 @@ def list_parts(self, Bucket, Key, UploadId, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - return rt + + data = xml_to_dict(rt.text) + if isinstance(data['Part'], list): + return data + else: # 只有一个part,将dict转为list,保持一致 + lst = [] + lst.append(data['Part']) + data['Part'] = lst + return data def create_bucket(self, Bucket, **kwargs): """创建一个bucket""" @@ -283,7 +326,7 @@ def create_bucket(self, Bucket, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - return rt + return None def delete_bucket(self, Bucket, **kwargs): """删除一个bucket,bucket必须为空""" @@ -297,7 +340,7 @@ def delete_bucket(self, Bucket, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - return rt + return None def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys=100, Prefix="", **kwargs): """获取文件列表""" @@ -318,7 +361,8 @@ def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxK params=params, headers=headers, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) - return rt + data = xml_to_dict(rt.text) + return data def head_object(self, Bucket, Key, **kwargs): """获取文件信息""" @@ -332,7 +376,7 @@ def head_object(self, Bucket, Key, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) - return rt + return rt.headers if __name__ == "__main__": diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 4057cc0f..12bbbfc8 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -3,8 +3,6 @@ import random import sys import os -import xml.dom.minidom -from xml.dom.minidom import parse from cos_client import CosS3Client from cos_client import CosConfig from cos_exception import COSServiceError @@ -20,15 +18,6 @@ def gen_file(path, size): _file.close() -def get_id_from_xml(data): - """解析xml中的uploadid""" - tree = xml.dom.minidom.parseString(data) - root = tree.documentElement - result = root.getElementsByTagName('UploadId') - # use childNodes to get a list, if has no child get itself - return result[0].childNodes[0].nodeValue - - def setUp(): print "start test" @@ -78,21 +67,18 @@ def Test(): CacheControl='no-cache', ContentDisposition='download.txt' ) - assert response.status_code == 200 print "Test Get Object Contains Special Characters " + special_file_name response = client.get_object( Bucket='test01', Key=special_file_name, ) - assert response.status_code == 200 print "Test Delete Object Contains Special Characters " + special_file_name response = client.delete_object( Bucket='test01', Key=special_file_name ) - assert response.status_code == 204 print "Test Put Object " + file_name response = client.put_object( @@ -108,48 +94,45 @@ def Test(): Bucket='test01', Key=file_name, ) - assert response.status_code == 200 + print response print "Test Head Object " + file_name response = client.head_object( Bucket='test01', Key=file_name ) - assert response.status_code == 200 + print response print "Test Delete Object " + file_name response = client.delete_object( Bucket='test01', Key=file_name ) - assert response.status_code == 204 print "Test List Objects" response = client.list_objects( Bucket='test01' ) - assert response.status_code == 200 + print response print "Test Create Bucket" response = client.create_bucket( Bucket='test'+file_id, ACL='public-read' ) - assert response.status_code == 200 print "Test Delete Bucket" response = client.delete_bucket( Bucket='test'+file_id ) - assert response.status_code == 204 print "Test Create MultipartUpload" response = client.create_multipart_upload( Bucket='test01', Key='multipartfile.txt', ) - assert response.status_code == 200 - uploadid = get_id_from_xml(response.text) + uploadid = response['UploadId'] + print response print "Test Abort MultipartUpload" response = client.abort_multipart_upload( @@ -157,26 +140,31 @@ def Test(): Key='multipartfile.txt', UploadId=uploadid ) - assert response.status_code == 200 print "Test Create MultipartUpload" response = client.create_multipart_upload( Bucket='test01', Key='multipartfile.txt', ) - uploadid = get_id_from_xml(response.text) - assert response.status_code == 200 + uploadid = response['UploadId'] - print "Test Upload Part" + print "Test Upload Part1" response = client.upload_part( Bucket='test01', Key='multipartfile.txt', UploadId=uploadid, PartNumber=1, - Body='A'*1024*1024*4 + Body='A'*1024*1024*10 + ) + + print "Test Upload Part2" + response = client.upload_part( + Bucket='test01', + Key='multipartfile.txt', + UploadId=uploadid, + PartNumber=2, + Body='B'*1024*1024*10 ) - etag = response.headers['ETag'] - assert response.status_code == 200 print "List Upload Parts" response = client.list_parts( @@ -184,16 +172,15 @@ def Test(): Key='multipartfile.txt', UploadId=uploadid ) - assert response.status_code == 200 + lst = response['Part'] print "Test Complete MultipartUpload" response = client.complete_multipart_upload( Bucket='test01', Key='multipartfile.txt', UploadId=uploadid, - MultipartUpload={'Parts': [{'PartNumber': 1, 'ETag': etag}]} + MultipartUpload={'Part': lst} ) - assert response.status_code == 200 if __name__ == "__main__": setUp() diff --git a/qcloud_cos/xml2dict.py b/qcloud_cos/xml2dict.py new file mode 100644 index 00000000..cfa23414 --- /dev/null +++ b/qcloud_cos/xml2dict.py @@ -0,0 +1,46 @@ +# -*- coding=utf-8 +import xml.etree.ElementTree + + +class Xml2Dict(dict): + def __init__(self, parent_node): + if parent_node.items(): + self.updateDict(dict(parent_node.items())) + for element in parent_node: + if len(element): + aDict = Xml2Dict(element) + self.updateDict({element.tag: aDict}) + elif element.items(): + elementattrib = element.items() + if element.text: + elementattrib.append((element.tag, element.text)) + self.updateDict({element.tag: dict(elementattrib)}) + else: + self.updateDict({element.tag: element.text}) + + def updateDict(self, aDict): + for key in aDict.keys(): + if key in self: + value = self.pop(key) + if type(value) is not list: + lst = list() + lst.append(value) + lst.append(aDict[key]) + self.update({key: lst}) + else: + value.append(aDict[key]) + self.update({key: value}) + else: + self.update({key: aDict[key]}) + +if __name__ == "__main__": + s = """ + + 10 + 1test1 + 2test2 + 3test3 + """ + root = xml.etree.ElementTree.fromstring(s) + xmldict = XmlDictConfig(root) + print xmldict From 29c7c3878f1f9322b34e5720e8ae86486707e30b Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Tue, 8 Aug 2017 11:17:19 +0800 Subject: [PATCH 48/71] Modify the test.py --- qcloud_cos/__init__.py | 8 +++++--- qcloud_cos/cos_client.py | 8 ++++---- qcloud_cos/cos_exception.py | 10 +++++----- qcloud_cos/test.py | 9 ++------- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/qcloud_cos/__init__.py b/qcloud_cos/__init__.py index b193bef6..8472f4a1 100644 --- a/qcloud_cos/__init__.py +++ b/qcloud_cos/__init__.py @@ -1,3 +1,5 @@ -import cos_auth -import cos_threadpool -import cos_client +from .cos_client import CosS3Client +from .cos_client import CosConfig +from .cos_exception import CosServiceError +from .cos_exception import CosClientError +from .cos_auth import CosS3Auth diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index aeda089f..74205803 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -8,8 +8,8 @@ import xml.etree.ElementTree from xml2dict import Xml2Dict from cos_auth import CosS3Auth -from cos_exception import ClientError -from cos_exception import COSServiceError +from cos_exception import CosClientError +from cos_exception import CosServiceError logging.basicConfig( level=logging.INFO, @@ -159,12 +159,12 @@ def send_request(self, method, url, timeout=30, **kwargs): return res except Exception as e: # 捕获requests抛出的如timeout等客户端错误,转化为客户端错误 logger.exception('url:%s, exception:%s' % (url, str(e))) - raise ClientError(str(e)) + raise CosClientError(str(e)) if res.status_code >= 300: # 所有的3XX,4XX,5XX都认为是COSServiceError msg = res.text logger.error(msg) - raise COSServiceError(msg, res.status_code) + raise CosServiceError(msg, res.status_code) def put_object(self, Bucket, Body, Key, **kwargs): """单文件上传接口,适用于小文件,最大不得超过5GB""" diff --git a/qcloud_cos/cos_exception.py b/qcloud_cos/cos_exception.py index 77643457..8610e3b3 100644 --- a/qcloud_cos/cos_exception.py +++ b/qcloud_cos/cos_exception.py @@ -3,7 +3,7 @@ import xml.dom.minidom -class COSException(Exception): +class CosException(Exception): def __init__(self, message): Exception.__init__(self, message) @@ -33,16 +33,16 @@ def digest_xml(data): return "Response Error Msg Is INVALID" -class ClientError(COSException): +class CosClientError(CosException): """Client端错误,如timeout""" def __init__(self, message): - COSException.__init__(self, message) + CosException.__init__(self, message) -class COSServiceError(COSException): +class CosServiceError(CosException): """COS Server端错误,可以获取特定的错误信息""" def __init__(self, message, status_code): - COSException.__init__(self, message) + CosException.__init__(self, message) self._origin_msg = message self._digest_msg = digest_xml(message) self._status_code = status_code diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 12bbbfc8..87999f17 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -1,11 +1,10 @@ # -*- coding=utf-8 -import cos_client import random import sys import os from cos_client import CosS3Client from cos_client import CosConfig -from cos_exception import COSServiceError +from cos_exception import CosServiceError ACCESS_ID = os.environ["ACCESS_ID"] ACCESS_KEY = os.environ["ACCESS_KEY"] @@ -48,7 +47,7 @@ def Test(): CacheControl='no-cache', ContentDisposition='download.txt' ) - except COSServiceError as e: + except CosServiceError as e: print e.get_origin_msg() print e.get_digest_msg() print e.get_status_code() @@ -94,14 +93,12 @@ def Test(): Bucket='test01', Key=file_name, ) - print response print "Test Head Object " + file_name response = client.head_object( Bucket='test01', Key=file_name ) - print response print "Test Delete Object " + file_name response = client.delete_object( @@ -113,7 +110,6 @@ def Test(): response = client.list_objects( Bucket='test01' ) - print response print "Test Create Bucket" response = client.create_bucket( @@ -132,7 +128,6 @@ def Test(): Key='multipartfile.txt', ) uploadid = response['UploadId'] - print response print "Test Abort MultipartUpload" response = client.abort_multipart_upload( From 046447c1bcbb8db23f9c4cb046e94f22a4487fc6 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Tue, 8 Aug 2017 21:09:43 +0800 Subject: [PATCH 49/71] Fix up the bugs in response --- qcloud_cos/cos_client.py | 12 +++++++++--- qcloud_cos/test.py | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 74205803..e0af5645 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -342,7 +342,7 @@ def delete_bucket(self, Bucket, **kwargs): headers=headers) return None - def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxKeys=100, Prefix="", **kwargs): + def list_objects(self, Bucket, Delimiter="", Marker="", MaxKeys=1000, Prefix="", **kwargs): """获取文件列表""" headers = mapped(kwargs) url = self._conf.uri(bucket=Bucket) @@ -351,7 +351,6 @@ def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxK headers=headers)) params = { 'delimiter': Delimiter, - 'encoding-type': EncodingType, 'marker': Marker, 'max-keys': MaxKeys, 'prefix': Prefix} @@ -361,8 +360,15 @@ def list_objects(self, Bucket, Delimiter="", EncodingType="url", Marker="", MaxK params=params, headers=headers, auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) + data = xml_to_dict(rt.text) - return data + if isinstance(data['Contents'], list): + return data + else: # 只有一个Contents,将dict转为list,保持一致 + lst = [] + lst.append(data['Contents']) + data['Contents'] = lst + return data def head_object(self, Bucket, Key, **kwargs): """获取文件信息""" diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 87999f17..e3289010 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -82,7 +82,7 @@ def Test(): print "Test Put Object " + file_name response = client.put_object( Bucket='test01', - Body='T'*1024*1024*file_size, + Body='T', Key=file_name, CacheControl='no-cache', ContentDisposition='download.txt' From cdd4627fbccc2cab06367fb099be8b7c184353ee Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 10 Aug 2017 12:05:00 +0800 Subject: [PATCH 50/71] Add the streambody to get stream in get_object --- qcloud_cos/cos_client.py | 4 +++- qcloud_cos/streambody.py | 27 +++++++++++++++++++++++++++ qcloud_cos/test.py | 17 +++++++++++++---- 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 qcloud_cos/streambody.py diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index e0af5645..94447514 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -6,6 +6,7 @@ import copy import xml.dom.minidom import xml.etree.ElementTree +from streambody import StreamBody from xml2dict import Xml2Dict from cos_auth import CosS3Auth from cos_exception import CosClientError @@ -200,11 +201,12 @@ def get_object(self, Bucket, Key, **kwargs): rt = self.send_request( method='GET', url=url, + stream=True, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) response = dict() - response['Body'] = rt.text + response['Body'] = StreamBody(rt) for k in rt.headers.keys(): response[k] = rt.headers[k] diff --git a/qcloud_cos/streambody.py b/qcloud_cos/streambody.py new file mode 100644 index 00000000..08240a02 --- /dev/null +++ b/qcloud_cos/streambody.py @@ -0,0 +1,27 @@ +# -*- coding=utf-8 +import requests + + +class StreamBody(): + def __init__(self, rt): + self._rt = rt + + def get_stream(self, stream_size=1024): + return self._rt.iter_content(chunk_size=stream_size) + + def get_stream_to_file(self, file_name): + if 'Content-Length' in self._rt.headers: + content_len = int(self._rt.headers['Content-Length']) + else: + raise IOError("download failed without Content-Length header") + + file_len = 0 + with open(file_name, 'wb') as fp: + for chunk in self._rt.iter_content(chunk_size=1024): + if chunk: + file_len += len(chunk) + fp.write(chunk) + fp.flush() + fp.close() + if file_len != content_len: + raise IOError("download failed with incomplete file") diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index e3289010..f6799515 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -34,7 +34,7 @@ def Test(): ) client = CosS3Client(conf) - file_size = 2 + file_size = 100 file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_name = "tmp" + file_id + "_" + str(file_size) + "MB" @@ -42,7 +42,7 @@ def Test(): try: response = client.put_object( Bucket='test0xx', - Body='T'*1024*1024*file_size, + Body='T'*1024*1024, Key=file_name, CacheControl='no-cache', ContentDisposition='download.txt' @@ -61,7 +61,7 @@ def Test(): print "Test Put Object Contains Special Characters " + special_file_name response = client.put_object( Bucket='test01', - Body='S'*1024*1024*file_size, + Body='S'*1024*1024, Key=special_file_name, CacheControl='no-cache', ContentDisposition='download.txt' @@ -80,19 +80,28 @@ def Test(): ) print "Test Put Object " + file_name + gen_file(file_name, file_size) + fp = open(file_name, 'rb') response = client.put_object( Bucket='test01', - Body='T', + Body=fp, Key=file_name, CacheControl='no-cache', ContentDisposition='download.txt' ) + fp.close() + os.remove(file_name) print "Test Get Object " + file_name response = client.get_object( Bucket='test01', Key=file_name, ) + # 返回一个generator + # stream_generator = response['Body'].get_stream(stream_size=1024*512) + response['Body'].get_stream_to_file('cos.txt') + if os.path.exists('cos.txt'): + os.remove('cos.txt') print "Test Head Object " + file_name response = client.head_object( From fb5c23f9981fe85f06a23f8916cb6fd17d852e17 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 10 Aug 2017 13:18:13 +0800 Subject: [PATCH 51/71] Modify the test file size --- qcloud_cos/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index f6799515..b1ce9d5b 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -34,7 +34,7 @@ def Test(): ) client = CosS3Client(conf) - file_size = 100 + file_size = 10 file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_name = "tmp" + file_id + "_" + str(file_size) + "MB" From 72c708a80e194ea2a367b7ad0356efcf2d9a5663 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 10 Aug 2017 14:12:48 +0800 Subject: [PATCH 52/71] Modify the Key Start with / --- qcloud_cos/cos_client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 94447514..cdb25ffc 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -118,6 +118,8 @@ def __init__(self, Appid, Region, Access_id, Access_key): def uri(self, bucket, path=None): """拼接url""" if path: + if path[0] == '/': + path = path[1:] url = u"http://{bucket}-{uid}.{region}.myqcloud.com/{path}".format( bucket=to_unicode(bucket), uid=self._appid, From 0af74480ae2b64d49c8ff0a1e30783566b29a079 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 11 Aug 2017 21:53:19 +0800 Subject: [PATCH 53/71] Add the copy object and list buckets --- qcloud_cos/cos_client.py | 50 +++++++++++++++++++++++++++++++++++----- qcloud_cos/test.py | 47 +++++++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index cdb25ffc..33fe4aee 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -53,22 +53,19 @@ def dict_to_xml(data): doc.appendChild(root) if 'Part' not in data.keys(): - logger.error("Invalid Parameter, Part Is Required!") - return '' + raise CosClientError("Invalid Parameter, Part Is Required!") for i in data['Part']: nodePart = doc.createElement('Part') if 'PartNumber' not in i.keys(): - logger.error("Invalid Parameter, PartNumber Is Required!") - return '' + raise CosClientError("Invalid Parameter, PartNumber Is Required!") nodeNumber = doc.createElement('PartNumber') nodeNumber.appendChild(doc.createTextNode(str(i['PartNumber']))) if 'ETag' not in i.keys(): - logger.error("Invalid Parameter, ETag Is Required!") - return '' + raise CosClientError("Invalid Parameter, ETag Is Required!") nodeETag = doc.createElement('ETag') nodeETag.appendChild(doc.createTextNode(str(i['ETag']))) @@ -388,6 +385,47 @@ def head_object(self, Bucket, Key, **kwargs): headers=headers) return rt.headers + def gen_copy_source_url(self, CopySource): + """拼接拷贝源url""" + if 'Bucket' in CopySource.keys(): + bucket = CopySource['Bucket'] + else: + raise CosClientError('CopySource Need Parameter Bucket') + if 'Key' in CopySource.keys(): + key = CopySource['Key'] + else: + raise CosClientError('CopySource Need Parameter Key') + url = self._conf.uri(bucket=bucket, path=key).encode('utf8') + url = url[7:] # copysource不支持http://开头,去除 + return url + + def copy_object(self, Bucket, Key, CopySource, CopyStatus='Copy', **kwargs): + """文件拷贝,文件信息修改""" + headers = mapped(kwargs) + headers['x-cos-copy-source'] = self.gen_copy_source_url(CopySource) + headers['x-cos-metadata-directive'] = CopyStatus + url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("copy object, url=:{url} ,headers=:{headers}".format( + url=url, + headers=headers)) + rt = self.send_request( + method='PUT', + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) + data = xml_to_dict(rt.text) + return data + + def list_buckets(self): + """列出所有bucket""" + url = 'http://service.cos.myqcloud.com/' + rt = self.send_request( + method='GET', + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + ) + data = xml_to_dict(rt.text) + return data if __name__ == "__main__": pass diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index b1ce9d5b..39c74695 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -34,10 +34,23 @@ def Test(): ) client = CosS3Client(conf) - file_size = 10 + test_bucket = 'test01' + file_size = 2 # 方便CI通过 file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_name = "tmp" + file_id + "_" + str(file_size) + "MB" + print "Test Copy Object From Other Bucket " + response = client.list_buckets() + + copy_source = {'Bucket': 'test01', 'Key': '/test.txt'} + print "Test Copy Object From Other Bucket " + response = client.copy_object( + Bucket='test04', + Key='test.txt', + CopySource=copy_source + ) + print response + print "Test Put Object That Bucket Not Exist " + file_name try: response = client.put_object( @@ -57,10 +70,10 @@ def Test(): print e.get_trace_id() print e.get_request_id() - special_file_name = '对象!"存储#$%&()*+,- ./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~' + special_file_name = "对象()*'/. 存![]^&*~储{|}~()" print "Test Put Object Contains Special Characters " + special_file_name response = client.put_object( - Bucket='test01', + Bucket=test_bucket, Body='S'*1024*1024, Key=special_file_name, CacheControl='no-cache', @@ -69,13 +82,13 @@ def Test(): print "Test Get Object Contains Special Characters " + special_file_name response = client.get_object( - Bucket='test01', + Bucket=test_bucket, Key=special_file_name, ) print "Test Delete Object Contains Special Characters " + special_file_name response = client.delete_object( - Bucket='test01', + Bucket=test_bucket, Key=special_file_name ) @@ -83,7 +96,7 @@ def Test(): gen_file(file_name, file_size) fp = open(file_name, 'rb') response = client.put_object( - Bucket='test01', + Bucket=test_bucket, Body=fp, Key=file_name, CacheControl='no-cache', @@ -94,7 +107,7 @@ def Test(): print "Test Get Object " + file_name response = client.get_object( - Bucket='test01', + Bucket=test_bucket, Key=file_name, ) # 返回一个generator @@ -105,19 +118,19 @@ def Test(): print "Test Head Object " + file_name response = client.head_object( - Bucket='test01', + Bucket=test_bucket, Key=file_name ) print "Test Delete Object " + file_name response = client.delete_object( - Bucket='test01', + Bucket=test_bucket, Key=file_name ) print "Test List Objects" response = client.list_objects( - Bucket='test01' + Bucket=test_bucket ) print "Test Create Bucket" @@ -133,28 +146,28 @@ def Test(): print "Test Create MultipartUpload" response = client.create_multipart_upload( - Bucket='test01', + Bucket=test_bucket, Key='multipartfile.txt', ) uploadid = response['UploadId'] print "Test Abort MultipartUpload" response = client.abort_multipart_upload( - Bucket='test01', + Bucket=test_bucket, Key='multipartfile.txt', UploadId=uploadid ) print "Test Create MultipartUpload" response = client.create_multipart_upload( - Bucket='test01', + Bucket=test_bucket, Key='multipartfile.txt', ) uploadid = response['UploadId'] print "Test Upload Part1" response = client.upload_part( - Bucket='test01', + Bucket=test_bucket, Key='multipartfile.txt', UploadId=uploadid, PartNumber=1, @@ -163,7 +176,7 @@ def Test(): print "Test Upload Part2" response = client.upload_part( - Bucket='test01', + Bucket=test_bucket, Key='multipartfile.txt', UploadId=uploadid, PartNumber=2, @@ -172,7 +185,7 @@ def Test(): print "List Upload Parts" response = client.list_parts( - Bucket='test01', + Bucket=test_bucket, Key='multipartfile.txt', UploadId=uploadid ) @@ -180,7 +193,7 @@ def Test(): print "Test Complete MultipartUpload" response = client.complete_multipart_upload( - Bucket='test01', + Bucket=test_bucket, Key='multipartfile.txt', UploadId=uploadid, MultipartUpload={'Part': lst} From 0d4c8ec2ff751ac0db41786e587e240b343defc5 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 14 Aug 2017 11:34:45 +0800 Subject: [PATCH 54/71] Add get_raw_stream() --- qcloud_cos/streambody.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/qcloud_cos/streambody.py b/qcloud_cos/streambody.py index 08240a02..d28fbacc 100644 --- a/qcloud_cos/streambody.py +++ b/qcloud_cos/streambody.py @@ -6,8 +6,11 @@ class StreamBody(): def __init__(self, rt): self._rt = rt - def get_stream(self, stream_size=1024): - return self._rt.iter_content(chunk_size=stream_size) + def get_raw_stream(self): + return self._rt.raw + + def get_stream(self, chunk_size=1024): + return self._rt.iter_content(chunk_size=chunk_size) def get_stream_to_file(self, file_name): if 'Content-Length' in self._rt.headers: From b33dcd0d2184244633f589549026cc0bf75e862f Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 14 Aug 2017 11:36:02 +0800 Subject: [PATCH 55/71] Add get_presigned_download_url() --- qcloud_cos/cos_client.py | 19 +++++++++++++++++++ qcloud_cos/test.py | 17 +++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 33fe4aee..d6d0e3f9 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -1,11 +1,13 @@ # -*- coding=utf-8 import requests +import urllib import logging import sys import copy import xml.dom.minidom import xml.etree.ElementTree +from requests import Request, Session from streambody import StreamBody from xml2dict import Xml2Dict from cos_auth import CosS3Auth @@ -142,6 +144,15 @@ def __init__(self, conf, retry=2, session=None): else: self._session = session + def get_auth(self, Method, Bucket, Key=None, **kwargs): + """获取签名""" + headers = mapped(kwargs) + # TODO(tiedu) 检查header的参数合法性 + url = self._conf.uri(bucket=Bucket, path=Key) + r = Request(Method, url) + auth = CosS3Auth(self._conf._access_id, self._conf._access_key) + return auth(r).headers['Authorization'] + def send_request(self, method, url, timeout=30, **kwargs): try: for j in range(self._retry): @@ -211,6 +222,13 @@ def get_object(self, Bucket, Key, **kwargs): response[k] = rt.headers[k] return response + def get_presigned_download_url(self, Bucket, Key): + """生成预签名的下载url""" + url = self._conf.uri(bucket=Bucket, path=Key) + sign = self.get_auth(Method='GET', Bucket=Bucket, Key=Key) + url = url + '?sign=' + urllib.quote(sign) + return url + def delete_object(self, Bucket, Key, **kwargs): """单文件删除接口""" headers = mapped(kwargs) @@ -228,6 +246,7 @@ def delete_object(self, Bucket, Key, **kwargs): def create_multipart_upload(self, Bucket, Key, **kwargs): """创建分片上传,适用于大文件上传""" headers = mapped(kwargs) + # headers['Authorization'] = self.get_auth(Method='POST', Bucket=Bucket, Key=Key) url = self._conf.uri(bucket=Bucket, path=Key+"?uploads") logger.info("create multipart upload, url=:{url} ,headers=:{headers}".format( url=url, diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 39c74695..f9838b26 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -39,7 +39,14 @@ def Test(): file_id = str(random.randint(0, 1000)) + str(random.randint(0, 1000)) file_name = "tmp" + file_id + "_" + str(file_size) + "MB" - print "Test Copy Object From Other Bucket " + print "Test Get Presigned Download URL " + url = client.get_presigned_download_url( + Bucket=test_bucket, + Key='test.txt' + ) + print url + + print "Test List Buckets" response = client.list_buckets() copy_source = {'Bucket': 'test01', 'Key': '/test.txt'} @@ -49,7 +56,6 @@ def Test(): Key='test.txt', CopySource=copy_source ) - print response print "Test Put Object That Bucket Not Exist " + file_name try: @@ -110,6 +116,8 @@ def Test(): Bucket=test_bucket, Key=file_name, ) + # 返回一个raw stream + # fp = response['Body'].get_raw_stream() # 返回一个generator # stream_generator = response['Body'].get_stream(stream_size=1024*512) response['Body'].get_stream_to_file('cos.txt') @@ -121,6 +129,7 @@ def Test(): Bucket=test_bucket, Key=file_name ) + print response print "Test Delete Object " + file_name response = client.delete_object( @@ -171,7 +180,7 @@ def Test(): Key='multipartfile.txt', UploadId=uploadid, PartNumber=1, - Body='A'*1024*1024*10 + Body='A'*1024*1024*2 ) print "Test Upload Part2" @@ -180,7 +189,7 @@ def Test(): Key='multipartfile.txt', UploadId=uploadid, PartNumber=2, - Body='B'*1024*1024*10 + Body='B'*1024*1024*2 ) print "List Upload Parts" From c6106dbccd1f1beed2c0ce9a7730468c35af911e Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 14 Aug 2017 11:56:18 +0800 Subject: [PATCH 56/71] Modify the MultiPartUpload Example --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 38b10da7..ba522d77 100644 --- a/README.rst +++ b/README.rst @@ -82,7 +82,7 @@ __________ Bucket='test01', Key='multipartfile.txt', ) - uploadid = get_id_from_xml(response.text) + uploadid = response['UploadId'] # 8. 上传分片 response = client.upload_part( @@ -100,13 +100,14 @@ __________ Key='mutilpartfile.txt', UploadId=uploadid ) + lst = response['Part'] # 10. 完成分片上传 response = client.complete_multipart_upload( Bucket='test01', Key='multipartfile.txt', UploadId=uploadid, - MultipartUpload={'Parts': [{'PartNumber': 1, 'ETag': etag}]} + MultipartUpload={'Part': lst} ) From 4848016a5a6a5814bc03dbdf03363e16da551fc2 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 14 Aug 2017 16:39:14 +0800 Subject: [PATCH 57/71] Fix up the Metadata Set --- qcloud_cos/cos_client.py | 9 +++++++- qcloud_cos/test.py | 46 +++++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index d6d0e3f9..8f9b5583 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -31,7 +31,7 @@ 'ContentDisposition': 'Content-Disposition', 'ContentEncoding': 'Content-Encoding', 'Expires': 'Expires', - 'Metadata': 'x-cos-meta- *', + 'Metadata': 'Metadata', 'ACL': 'x-cos-acl', 'GrantFullControl': 'x-cos-grant-full-control', 'GrantWrite': 'x-cos-grant-write', @@ -100,6 +100,8 @@ def mapped(headers): for i in headers.keys(): if i in maplist: _headers[maplist[i]] = headers[i] + else: + raise CosClientError('No Parameter Named '+i+' Please Check It') return _headers @@ -180,6 +182,11 @@ def send_request(self, method, url, timeout=30, **kwargs): def put_object(self, Bucket, Body, Key, **kwargs): """单文件上传接口,适用于小文件,最大不得超过5GB""" headers = mapped(kwargs) + if 'Metadata' in headers.keys(): + for i in headers['Metadata'].keys(): + headers[i] = headers['Metadata'][i] + headers.pop('Metadata') + url = self._conf.uri(bucket=Bucket, path=Key) logger.info("put object, url=:{url} ,headers=:{headers}".format( url=url, diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index f9838b26..7a2fa57c 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -79,18 +79,18 @@ def Test(): special_file_name = "对象()*'/. 存![]^&*~储{|}~()" print "Test Put Object Contains Special Characters " + special_file_name response = client.put_object( - Bucket=test_bucket, - Body='S'*1024*1024, - Key=special_file_name, - CacheControl='no-cache', - ContentDisposition='download.txt' - ) + Bucket=test_bucket, + Body='S'*1024*1024, + Key=special_file_name, + CacheControl='no-cache', + ContentDisposition='download.txt' + ) print "Test Get Object Contains Special Characters " + special_file_name response = client.get_object( - Bucket=test_bucket, - Key=special_file_name, - ) + Bucket=test_bucket, + Key=special_file_name, + ) print "Test Delete Object Contains Special Characters " + special_file_name response = client.delete_object( @@ -102,19 +102,22 @@ def Test(): gen_file(file_name, file_size) fp = open(file_name, 'rb') response = client.put_object( - Bucket=test_bucket, - Body=fp, - Key=file_name, - CacheControl='no-cache', - ContentDisposition='download.txt' - ) + Bucket=test_bucket, + Body=fp, + Key=file_name, + CacheControl='no-cache', + ContentDisposition='download.txt', + Metadata={ + "x-cos-meta-tiedu": "value1" + } + ) fp.close() os.remove(file_name) print "Test Get Object " + file_name response = client.get_object( - Bucket=test_bucket, - Key=file_name, + Bucket=test_bucket, + Key=file_name, ) # 返回一个raw stream # fp = response['Body'].get_raw_stream() @@ -129,10 +132,9 @@ def Test(): Bucket=test_bucket, Key=file_name ) - print response print "Test Delete Object " + file_name - response = client.delete_object( + response = client.head_object( Bucket=test_bucket, Key=file_name ) @@ -144,9 +146,9 @@ def Test(): print "Test Create Bucket" response = client.create_bucket( - Bucket='test'+file_id, - ACL='public-read' - ) + Bucket='test'+file_id, + ACL='public-read' + ) print "Test Delete Bucket" response = client.delete_bucket( From bb880bf7bae01a49679c8e2dd14958bde3aa70d5 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 14 Aug 2017 16:56:05 +0800 Subject: [PATCH 58/71] Modify the example --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ba522d77..a2a143ea 100644 --- a/README.rst +++ b/README.rst @@ -92,7 +92,7 @@ __________ PartNumber=1, Body='A'*1024*1024*4 ) - etag = response.headers['ETag'] + etag = response['ETag'] # 9. 列出分片 response = clieent.list_parts( From 8d81b5446922b62d32572e5c6d22221778b0cb31 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 14 Aug 2017 21:10:38 +0800 Subject: [PATCH 59/71] Fix up None Return Bugs --- qcloud_cos/cos_client.py | 30 ++++++++++++++++++------------ qcloud_cos/test.py | 4 +++- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 8f9b5583..156f5526 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -333,12 +333,15 @@ def list_parts(self, Bucket, Key, UploadId, **kwargs): headers=headers) data = xml_to_dict(rt.text) - if isinstance(data['Part'], list): - return data - else: # 只有一个part,将dict转为list,保持一致 - lst = [] - lst.append(data['Part']) - data['Part'] = lst + if 'Part' is data.keys(): + if isinstance(data['Part'], list): + return data + else: # 只有一个part,将dict转为list,保持一致 + lst = [] + lst.append(data['Part']) + data['Part'] = lst + return data + else: return data def create_bucket(self, Bucket, **kwargs): @@ -389,12 +392,15 @@ def list_objects(self, Bucket, Delimiter="", Marker="", MaxKeys=1000, Prefix="", auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) data = xml_to_dict(rt.text) - if isinstance(data['Contents'], list): - return data - else: # 只有一个Contents,将dict转为list,保持一致 - lst = [] - lst.append(data['Contents']) - data['Contents'] = lst + if 'Contents' in data.keys(): + if isinstance(data['Contents'], list): + return data + else: # 只有一个Contents,将dict转为list,保持一致 + lst = [] + lst.append(data['Contents']) + data['Contents'] = lst + return data + else: return data def head_object(self, Bucket, Key, **kwargs): diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 7a2fa57c..8a1aa02c 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -141,8 +141,9 @@ def Test(): print "Test List Objects" response = client.list_objects( - Bucket=test_bucket + Bucket='test04' ) + print response print "Test Create Bucket" response = client.create_bucket( @@ -200,6 +201,7 @@ def Test(): Key='multipartfile.txt', UploadId=uploadid ) + print response lst = response['Part'] print "Test Complete MultipartUpload" From 69730bbdc292b09d6aa7fdf546d2d7e8ca28b933 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 14 Aug 2017 21:37:00 +0800 Subject: [PATCH 60/71] Remove Debug Code --- qcloud_cos/cos_client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 156f5526..3ed9b1eb 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -253,7 +253,6 @@ def delete_object(self, Bucket, Key, **kwargs): def create_multipart_upload(self, Bucket, Key, **kwargs): """创建分片上传,适用于大文件上传""" headers = mapped(kwargs) - # headers['Authorization'] = self.get_auth(Method='POST', Bucket=Bucket, Key=Key) url = self._conf.uri(bucket=Bucket, path=Key+"?uploads") logger.info("create multipart upload, url=:{url} ,headers=:{headers}".format( url=url, From 5f725c7790707084c992d445c07925797910fd96 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 17 Aug 2017 13:43:26 +0800 Subject: [PATCH 61/71] Fix Up is to in --- qcloud_cos/cos_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 3ed9b1eb..dd759b1f 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -332,7 +332,7 @@ def list_parts(self, Bucket, Key, UploadId, **kwargs): headers=headers) data = xml_to_dict(rt.text) - if 'Part' is data.keys(): + if 'Part' in data.keys(): if isinstance(data['Part'], list): return data else: # 只有一个part,将dict转为list,保持一致 From fd2ba780ff7890d1722b8c03b83f265f3d65ae2b Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Mon, 21 Aug 2017 16:30:54 +0800 Subject: [PATCH 62/71] Delete unuse retry in put object --- qcloud_cos/cos_client.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index dd759b1f..fa6f84bd 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -191,18 +191,12 @@ def put_object(self, Bucket, Body, Key, **kwargs): logger.info("put object, url=:{url} ,headers=:{headers}".format( url=url, headers=headers)) - for j in range(self._retry): - rt = self.send_request( - method='PUT', - url=url, - auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - data=Body, - headers=headers) - if rt is None: - continue - if rt.status_code == 200: - break - logger.error(rt.text) + rt = self.send_request( + method='PUT', + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + data=Body, + headers=headers) response = dict() response['ETag'] = rt.headers['ETag'] From 21f2caed0eae8350cee139b34a398f609c13776f Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Wed, 23 Aug 2017 13:38:40 +0800 Subject: [PATCH 63/71] Add the Error Info For Head Request --- qcloud_cos/cos_client.py | 20 ++++++++++++++++---- qcloud_cos/cos_exception.py | 10 +++++++--- qcloud_cos/test.py | 31 +++++++++++++++++++++---------- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index fa6f84bd..ecf860d2 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -138,7 +138,7 @@ def uri(self, bucket, path=None): class CosS3Client(object): """cos客户端类,封装相应请求""" - def __init__(self, conf, retry=2, session=None): + def __init__(self, conf, retry=1, session=None): self._conf = conf self._retry = retry # 重试的次数,分片上传时可适当增大 if session is None: @@ -175,9 +175,21 @@ def send_request(self, method, url, timeout=30, **kwargs): raise CosClientError(str(e)) if res.status_code >= 300: # 所有的3XX,4XX,5XX都认为是COSServiceError - msg = res.text - logger.error(msg) - raise CosServiceError(msg, res.status_code) + if method == 'HEAD': # Head 需要处理 + info = dict() + info['code'] = 'NoSuchResource' + info['message'] = 'The Resource You Head Not Exist' + info['resource'] = url + info['requestid'] = res.headers['x-cos-request-id'] + info['traceid'] = res.headers['x-cos-trace-id'] + logger.error(info) + raise CosServiceError(method, info, res.status_code) + else: + msg = res.text + if msg == '': # 服务器没有返回Error Body时 给出头部的信息 + msg = res.headers + logger.error(msg) + raise CosServiceError(method, msg, res.status_code) def put_object(self, Bucket, Body, Key, **kwargs): """单文件上传接口,适用于小文件,最大不得超过5GB""" diff --git a/qcloud_cos/cos_exception.py b/qcloud_cos/cos_exception.py index 8610e3b3..bb8c2dea 100644 --- a/qcloud_cos/cos_exception.py +++ b/qcloud_cos/cos_exception.py @@ -41,10 +41,14 @@ def __init__(self, message): class CosServiceError(CosException): """COS Server端错误,可以获取特定的错误信息""" - def __init__(self, message, status_code): + def __init__(self, method, message, status_code): CosException.__init__(self, message) - self._origin_msg = message - self._digest_msg = digest_xml(message) + if method == 'HEAD': # 对HEAD进行特殊处理 + self._origin_msg = '' + self._digest_msg = message + else: + self._origin_msg = message + self._digest_msg = digest_xml(message) self._status_code = status_code def get_origin_msg(self): diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 8a1aa02c..844a6ff7 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -17,6 +17,17 @@ def gen_file(path, size): _file.close() +def print_error_msg(e): + print e.get_origin_msg() + print e.get_digest_msg() + print e.get_status_code() + print e.get_error_code() + print e.get_error_msg() + print e.get_resource_location() + print e.get_trace_id() + print e.get_request_id() + + def setUp(): print "start test" @@ -67,14 +78,7 @@ def Test(): ContentDisposition='download.txt' ) except CosServiceError as e: - print e.get_origin_msg() - print e.get_digest_msg() - print e.get_status_code() - print e.get_error_code() - print e.get_error_msg() - print e.get_resource_location() - print e.get_trace_id() - print e.get_request_id() + print_error_msg(e) special_file_name = "对象()*'/. 存![]^&*~储{|}~()" print "Test Put Object Contains Special Characters " + special_file_name @@ -133,6 +137,15 @@ def Test(): Key=file_name ) + print "Test Head Object " + file_name + "123" + try: + response = client.head_object( + Bucket=test_bucket, + Key=file_name+"123" + ) + except CosServiceError as e: + print_error_msg(e) + print "Test Delete Object " + file_name response = client.head_object( Bucket=test_bucket, @@ -143,7 +156,6 @@ def Test(): response = client.list_objects( Bucket='test04' ) - print response print "Test Create Bucket" response = client.create_bucket( @@ -201,7 +213,6 @@ def Test(): Key='multipartfile.txt', UploadId=uploadid ) - print response lst = response['Part'] print "Test Complete MultipartUpload" From ab8da9ad766148e1f3dba679212625ae488cb178 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 24 Aug 2017 16:09:40 +0800 Subject: [PATCH 64/71] Compatible With New Region --- qcloud_cos/cos_client.py | 37 ++++++++++++++++++++++++++----------- qcloud_cos/test.py | 2 +- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index ecf860d2..86afb941 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -121,18 +121,33 @@ def uri(self, bucket, path=None): if path: if path[0] == '/': path = path[1:] - url = u"http://{bucket}-{uid}.{region}.myqcloud.com/{path}".format( - bucket=to_unicode(bucket), - uid=self._appid, - region=self._region, - path=to_unicode(path) - ) + if self._region.find("cn") == -1: + url = u"http://{bucket}-{uid}.cos.{region}.myqcloud.com/{path}".format( + bucket=to_unicode(bucket), + uid=self._appid, + region=self._region, + path=to_unicode(path) + ) + else: + url = u"http://{bucket}-{uid}.{region}.myqcloud.com/{path}".format( + bucket=to_unicode(bucket), + uid=self._appid, + region=self._region, + path=to_unicode(path) + ) else: - url = u"http://{bucket}-{uid}.{region}.myqcloud.com".format( - bucket=to_unicode(bucket), - uid=self._appid, - region=self._region - ) + if self._region.find("cn") == -1: + url = u"http://{bucket}-{uid}.cos.{region}.myqcloud.com".format( + bucket=to_unicode(bucket), + uid=self._appid, + region=self._region + ) + else: + url = u"http://{bucket}-{uid}.{region}.myqcloud.com".format( + bucket=to_unicode(bucket), + uid=self._appid, + region=self._region + ) return url diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 844a6ff7..57d7a15e 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -39,7 +39,7 @@ def tearDown(): def Test(): conf = CosConfig( Appid="1252448703", - Region="cn-north", + Region="ap-beijing-1", Access_id=ACCESS_ID, Access_key=ACCESS_KEY ) From d2d01f5227640419ba16aff74d0e9301ff1d5014 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 24 Aug 2017 16:41:56 +0800 Subject: [PATCH 65/71] Compatible With Region cos --- qcloud_cos/cos_auth.pyc | Bin 0 -> 3544 bytes qcloud_cos/cos_client.py | 65 ++++++++++++++--------------------- qcloud_cos/cos_client.pyc | Bin 0 -> 17350 bytes qcloud_cos/cos_exception.pyc | Bin 0 -> 4477 bytes qcloud_cos/cos_s3.log | 23 +++++++++++++ qcloud_cos/streambody.pyc | Bin 0 -> 1700 bytes qcloud_cos/test.py | 5 +-- qcloud_cos/xml2dict.pyc | Bin 0 -> 1840 bytes 8 files changed, 51 insertions(+), 42 deletions(-) create mode 100644 qcloud_cos/cos_auth.pyc create mode 100644 qcloud_cos/cos_client.pyc create mode 100644 qcloud_cos/cos_exception.pyc create mode 100644 qcloud_cos/cos_s3.log create mode 100644 qcloud_cos/streambody.pyc create mode 100644 qcloud_cos/xml2dict.pyc diff --git a/qcloud_cos/cos_auth.pyc b/qcloud_cos/cos_auth.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b7e39d59c8e154e9c98b03f870af510e21f6c9d GIT binary patch literal 3544 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 Y&XqP)10E~ziAEPJTe<9aW?Q56f8s<~F8}}l literal 0 HcmV?d00001 diff --git a/qcloud_cos/cos_exception.pyc b/qcloud_cos/cos_exception.pyc new file mode 100644 index 0000000000000000000000000000000000000000..26e228d9696207e74c434144a3c9475669a8506b GIT binary patch literal 4477 zcmc&&-EUMy6rZ`<-R`zU&;UXraV4l5rLAbx#2^t$6PnPP+(ka>!_DU2VSC%%d&`|! zq)GdLZ6x?XeIOc;C?xn56YG=m zI>Id$XxevBQ6a?#Q1nJrMu>4KriGZ6V%8B7hFI~D0?8U$ytSOkqUU*G6dKR7^Bow` zs&d?PqES^^m&&Surr=8NN2@<5nNt5`DKWeH$KtB$H=zn@{eG-_C#TF<9QEp8qW9$M z{U`iNTnju*(4?oDR`yL!xugs&p{XHcfs9yICn{By=b0{ycwRLQY87<(g|;HAtPSaq zL1Aq&(x?5Uej0_hb{$5rwX;IZNHKLs7%9dbF`g3R9kkiAQp`AF8Y5{jlM>SyXJ^wm z1OO68Y#r~kk1Y8HSlYcT*1@meM=aeE%RES|vn7^&kXWuI*7YE zusT8L8$;kaRju$dh^rRcKs~j)F$XMbRWwN$mCbtegV?WCRb&P$iXMgntE`$`y>IGJ zsXPLdGDiKeuo8^GYR%e5XdNz9YRV-L6$nLE5d;k@P}OA~Fo{y!NaENSlEa?VDhAL( z$hV=sYB9&!24NYBde{vzTyIAuWKO2!CYf{A%Psd7nU(9Mc>+@4sewvJyFwf8(~I;Y zZTF$*r%|<-YSbaFn*(vBh_5Kf^)smK7aBh;+&OOh)b?!$gRN!@-i=AfhK7Yv|Zu|m)%Sd^*n%Qt?4R{g?6B5QXnHUl2Ho>6;*OF z^woVlD!I$s^9#3ce7kh+xBC1SjkDM4KVNKIoU>TCee25N=>?xmqC$=wK+%U$ zwX>STS&ax(iU~&~yNFZ4z#h{tHButlLR4%A5n*V9hwT(7ml`mT@*=HaIqbmT-u+l) zIbhqMVtVl6BrJ!KN0CcW<1Ggf`tGyna~k(F;=87i?E+OG0~m@N*C2|qIIu*>QMW=8 zf@_glcjB{}qE^TavIha)><*RrQ^V}9w@nflea#^)cw zD#{Gjta~76?V&h-G?ul|^wxi}Y*Wj!F=Hn4it`}DkG$)?xaI~>swCH}K>i*K-Rm1d z24n3xG!SG2Hz^E9a=Va+qFSBd=+UEhXR(?Ht3$7CQ~OUXb!Z+l@t`Eb=7N38Lf z?4pEd9mn?#Sa#%Y%L-(9`$XpwWAUlaeTiBxQ$?xO?WgJ$s&-NJDpjwcYG*)ht=ie$ z-Hwlw4t&X{BVVp7*TH|8T$=t0#AkdC#M! appid: 1252448703, region: cn-north +Thu, 24 Aug 2017 16:40:04 cos_client.py[line:447] INFO copy object, url=:http://test04-1252448703.cos.cn-north.myqcloud.com/test.txt ,headers=:{'x-cos-metadata-directive': 'Copy', 'x-cos-copy-source': 'test01-1252448703.cos.cn-north.myqcloud.com/test.txt'} +Thu, 24 Aug 2017 16:40:04 cos_client.py[line:205] INFO put object, url=:http://test0xx-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB ,headers=:{'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} +Thu, 24 Aug 2017 16:40:05 cos_client.py[line:191] ERROR {'Content-Length': '0', 'Content-Type': 'application/xml', 'Server': 'tencent-cos', 'Connection': 'keep-alive', 'x-cos-trace-id': 'OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTczMmZiNDZmZjBmNTVjMGU4NTViNDhhYWVjNzNkNzI4MGU2OTkyMWM5NTE5MGVmOTg1MDViMmE0MzdjMTc4MzY=', 'Date': 'Thu, 24 Aug 2017 08:40:05 GMT', 'x-cos-request-id': 'NTk5ZTkwZTRfZWFhZDM1MGFfMjkwYV8xMTZjZDU='} +Thu, 24 Aug 2017 16:40:05 cos_client.py[line:205] INFO put object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/对象()*'/. 存![]^&*~储{|}~() ,headers=:{'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} +Thu, 24 Aug 2017 16:40:05 cos_client.py[line:223] INFO get object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/对象()*'/. 存![]^&*~储{|}~() ,headers=:{} +Thu, 24 Aug 2017 16:40:05 cos_client.py[line:251] INFO delete object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/对象()*'/. 存![]^&*~储{|}~() ,headers=:{} +Thu, 24 Aug 2017 16:40:06 cos_client.py[line:205] INFO put object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB ,headers=:{'x-cos-meta-tiedu': 'value1', 'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} +Thu, 24 Aug 2017 16:40:07 cos_client.py[line:223] INFO get object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB ,headers=:{} +Thu, 24 Aug 2017 16:40:08 cos_client.py[line:417] INFO head object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB ,headers=:{} +Thu, 24 Aug 2017 16:40:08 cos_client.py[line:417] INFO head object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB123 ,headers=:{} +Thu, 24 Aug 2017 16:40:08 cos_client.py[line:185] ERROR {'message': 'The Resource You Head Not Exist', 'code': 'NoSuchResource', 'resource': u'http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB123', 'requestid': 'NTk5ZTkwZThfMmJhZDM1MGFfNWZiZl8xMTJiM2I=', 'traceid': 'OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTBjYzE2MjAxN2M1MzJiOTdkZjMxMDVlYTZjN2FiMmI0ZWYwOWQwMTU1YmYwMjU3YTgwYWJmNGMzMTcxYjhkYzI='} +Thu, 24 Aug 2017 16:40:08 cos_client.py[line:417] INFO head object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB ,headers=:{} +Thu, 24 Aug 2017 16:40:08 cos_client.py[line:386] INFO list objects, url=:http://test01-1252448703.cos.cn-north.myqcloud.com ,headers=:{} +Thu, 24 Aug 2017 16:40:08 cos_client.py[line:358] INFO create bucket, url=:http://test67857-1252448703.cos.cn-north.myqcloud.com ,headers=:{'x-cos-acl': 'public-read'} +Thu, 24 Aug 2017 16:40:09 cos_client.py[line:372] INFO delete bucket, url=:http://test67857-1252448703.cos.cn-north.myqcloud.com ,headers=:{} +Thu, 24 Aug 2017 16:40:10 cos_client.py[line:265] INFO create multipart upload, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} +Thu, 24 Aug 2017 16:40:10 cos_client.py[line:319] INFO abort multipart upload, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?uploadId=15035640107b22d13cfd16ad8c8144ac0a4e2e3a019516e06052a238d9d2c538bbab6270c1 ,headers=:{} +Thu, 24 Aug 2017 16:40:10 cos_client.py[line:265] INFO create multipart upload, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} +Thu, 24 Aug 2017 16:40:10 cos_client.py[line:283] INFO put object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?partNumber=1&uploadId=150356401005d26e572e6c48784524519ed25e78078f4da2cc276dd8208555bbc058bf78aa ,headers=:{} +Thu, 24 Aug 2017 16:40:11 cos_client.py[line:283] INFO put object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?partNumber=2&uploadId=150356401005d26e572e6c48784524519ed25e78078f4da2cc276dd8208555bbc058bf78aa ,headers=:{} +Thu, 24 Aug 2017 16:40:12 cos_client.py[line:333] INFO list multipart upload, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?uploadId=150356401005d26e572e6c48784524519ed25e78078f4da2cc276dd8208555bbc058bf78aa ,headers=:{} +Thu, 24 Aug 2017 16:40:12 cos_client.py[line:299] INFO complete multipart upload, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?uploadId=150356401005d26e572e6c48784524519ed25e78078f4da2cc276dd8208555bbc058bf78aa ,headers=:{} diff --git a/qcloud_cos/streambody.pyc b/qcloud_cos/streambody.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d96b36d16f64e4409bb3a9ac44aabf5dbc880264 GIT binary patch literal 1700 zcmcIk!EVz)5S@*av?(c|!hs?Vk>C&sg2e%GK?qtnAfY0hLusUH<;I)Fjbo?Y4WTHx z5bm7elQ{4*d;q)|C#g7a3zj{eo!xyiZ)SGAU)x*9-@YGpY4LdYKgVb9LPU5KB}5%4 zC5p-vdGv*7PIS~!JlAekurB_M=fG`2ZM)or!@VrJSV5Lx-os~o2m>(eB!=k#Qi~B$&s(rnY1W{unIOX zwRUQpTc%dfV(-f`a3;AdTqa@k6ABYqR$@@4{63*ORu;_e&K1o{l-9W}XnYJmqiH>w zdE8OR0$OxlqOT#%%Jgx6xw%3S-YVzl3S4lI{m(Klga@)#R97etd2sg$&Zz4s5CMx1uD;V3cAGEXxtTy7LBGEg&}2@2TZ0nDp0spn;5V40@wlGW$$U1Y4&{$R(qR$sU5Xjs+X$x z-%(X{UENe$kaZ<|7WW79&{{4~t%q4O1~(n>-4zIHCLG*?xC~#k^;}{BfQfT&IdxT4 k^J-q*D_n8@B*@&HkBxO!7XOzp#Ld%!{WJC}hq&(j0oZ$WMgRZ+ literal 0 HcmV?d00001 diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 57d7a15e..7811880f 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -39,7 +39,7 @@ def tearDown(): def Test(): conf = CosConfig( Appid="1252448703", - Region="ap-beijing-1", + Region="cn-north", Access_id=ACCESS_ID, Access_key=ACCESS_KEY ) @@ -62,6 +62,7 @@ def Test(): copy_source = {'Bucket': 'test01', 'Key': '/test.txt'} print "Test Copy Object From Other Bucket " + response = client.copy_object( Bucket='test04', Key='test.txt', @@ -154,7 +155,7 @@ def Test(): print "Test List Objects" response = client.list_objects( - Bucket='test04' + Bucket=test_bucket ) print "Test Create Bucket" diff --git a/qcloud_cos/xml2dict.pyc b/qcloud_cos/xml2dict.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2c87c94e31f08e96b01528e777e6b415e7c07bd GIT binary patch literal 1840 zcmcIkO>fjl5Uuungh?hsu!04&5~Df!l9+%NaWE4ES+OS$4iYd@WSMbK@QlYE+&xhu zP4*K01e_69#EIK-LHv~c1AE!q@~UhyQ9$AXmb+Y4-PKiH@40LLt}gGqeD!2N)l@VNw04u1AAPKg7YqhxdNffLWuMC9WITP z8U@>~gXsZ_Mm6r?YyN?lqaG=@aA{67Qe>Tl6XoGmC};mYd$)Gp(xF4PMstT}ie0kx zNWSyEt01$93;YQLi12h zc}mrdA=_>Wat~?2hv_Cq7~E{)Ytvwszhz;%GQf7z3&|6&&yY2!PI@)L2KW z#w{xTV&#a4(FLfGGOH>>z`M+}U|1W(Y!M!mX#UO1Ip|yKgjMCbRVkwkFPEaAFHUiHGhmL%PK)A1`w;|_zk-Qx zxQwQ1ovlilL`fEg=0AA-O)#>vrwfzh+3oJe`n7IHXM;RWvfbO=nH{d(>UK7J%N;y^ zq0KC{r6G<%KFe%}2nWyRvQajbYK3VZ$(@`6#@G@ z5jRdn!2T-2_o_3vZ5-Y*d^rEQwuRQ~f0Q@CL+C;o%mjR=NFM`6+4ALNgjo_I7s<&m zzNdyojvK2$1BJ3ho?FW>Kc1v~t=!AAVX`Y%4ifNP@DrdHp#73%JtnH*^R{ajueO(( I>H?_x87yg!D*ylh literal 0 HcmV?d00001 From e541e0dad57f1c86f05b88a552bf4e92bd82d138 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Thu, 24 Aug 2017 16:46:46 +0800 Subject: [PATCH 66/71] delete pyc --- qcloud_cos/cos_auth.pyc | Bin 3544 -> 0 bytes qcloud_cos/cos_client.pyc | Bin 17350 -> 0 bytes qcloud_cos/cos_exception.pyc | Bin 4477 -> 0 bytes qcloud_cos/cos_s3.log | 23 ----------------------- qcloud_cos/streambody.pyc | Bin 1700 -> 0 bytes qcloud_cos/xml2dict.pyc | Bin 1840 -> 0 bytes 6 files changed, 23 deletions(-) delete mode 100644 qcloud_cos/cos_auth.pyc delete mode 100644 qcloud_cos/cos_client.pyc delete mode 100644 qcloud_cos/cos_exception.pyc delete mode 100644 qcloud_cos/cos_s3.log delete mode 100644 qcloud_cos/streambody.pyc delete mode 100644 qcloud_cos/xml2dict.pyc diff --git a/qcloud_cos/cos_auth.pyc b/qcloud_cos/cos_auth.pyc deleted file mode 100644 index 2b7e39d59c8e154e9c98b03f870af510e21f6c9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3544 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 Y&XqP)10E~ziAEPJTe<9aW?Q56f8s<~F8}}l diff --git a/qcloud_cos/cos_exception.pyc b/qcloud_cos/cos_exception.pyc deleted file mode 100644 index 26e228d9696207e74c434144a3c9475669a8506b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4477 zcmc&&-EUMy6rZ`<-R`zU&;UXraV4l5rLAbx#2^t$6PnPP+(ka>!_DU2VSC%%d&`|! zq)GdLZ6x?XeIOc;C?xn56YG=m zI>Id$XxevBQ6a?#Q1nJrMu>4KriGZ6V%8B7hFI~D0?8U$ytSOkqUU*G6dKR7^Bow` zs&d?PqES^^m&&Surr=8NN2@<5nNt5`DKWeH$KtB$H=zn@{eG-_C#TF<9QEp8qW9$M z{U`iNTnju*(4?oDR`yL!xugs&p{XHcfs9yICn{By=b0{ycwRLQY87<(g|;HAtPSaq zL1Aq&(x?5Uej0_hb{$5rwX;IZNHKLs7%9dbF`g3R9kkiAQp`AF8Y5{jlM>SyXJ^wm z1OO68Y#r~kk1Y8HSlYcT*1@meM=aeE%RES|vn7^&kXWuI*7YE zusT8L8$;kaRju$dh^rRcKs~j)F$XMbRWwN$mCbtegV?WCRb&P$iXMgntE`$`y>IGJ zsXPLdGDiKeuo8^GYR%e5XdNz9YRV-L6$nLE5d;k@P}OA~Fo{y!NaENSlEa?VDhAL( z$hV=sYB9&!24NYBde{vzTyIAuWKO2!CYf{A%Psd7nU(9Mc>+@4sewvJyFwf8(~I;Y zZTF$*r%|<-YSbaFn*(vBh_5Kf^)smK7aBh;+&OOh)b?!$gRN!@-i=AfhK7Yv|Zu|m)%Sd^*n%Qt?4R{g?6B5QXnHUl2Ho>6;*OF z^woVlD!I$s^9#3ce7kh+xBC1SjkDM4KVNKIoU>TCee25N=>?xmqC$=wK+%U$ zwX>STS&ax(iU~&~yNFZ4z#h{tHButlLR4%A5n*V9hwT(7ml`mT@*=HaIqbmT-u+l) zIbhqMVtVl6BrJ!KN0CcW<1Ggf`tGyna~k(F;=87i?E+OG0~m@N*C2|qIIu*>QMW=8 zf@_glcjB{}qE^TavIha)><*RrQ^V}9w@nflea#^)cw zD#{Gjta~76?V&h-G?ul|^wxi}Y*Wj!F=Hn4it`}DkG$)?xaI~>swCH}K>i*K-Rm1d z24n3xG!SG2Hz^E9a=Va+qFSBd=+UEhXR(?Ht3$7CQ~OUXb!Z+l@t`Eb=7N38Lf z?4pEd9mn?#Sa#%Y%L-(9`$XpwWAUlaeTiBxQ$?xO?WgJ$s&-NJDpjwcYG*)ht=ie$ z-Hwlw4t&X{BVVp7*TH|8T$=t0#AkdC#M! appid: 1252448703, region: cn-north -Thu, 24 Aug 2017 16:40:04 cos_client.py[line:447] INFO copy object, url=:http://test04-1252448703.cos.cn-north.myqcloud.com/test.txt ,headers=:{'x-cos-metadata-directive': 'Copy', 'x-cos-copy-source': 'test01-1252448703.cos.cn-north.myqcloud.com/test.txt'} -Thu, 24 Aug 2017 16:40:04 cos_client.py[line:205] INFO put object, url=:http://test0xx-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB ,headers=:{'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} -Thu, 24 Aug 2017 16:40:05 cos_client.py[line:191] ERROR {'Content-Length': '0', 'Content-Type': 'application/xml', 'Server': 'tencent-cos', 'Connection': 'keep-alive', 'x-cos-trace-id': 'OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTczMmZiNDZmZjBmNTVjMGU4NTViNDhhYWVjNzNkNzI4MGU2OTkyMWM5NTE5MGVmOTg1MDViMmE0MzdjMTc4MzY=', 'Date': 'Thu, 24 Aug 2017 08:40:05 GMT', 'x-cos-request-id': 'NTk5ZTkwZTRfZWFhZDM1MGFfMjkwYV8xMTZjZDU='} -Thu, 24 Aug 2017 16:40:05 cos_client.py[line:205] INFO put object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/对象()*'/. 存![]^&*~储{|}~() ,headers=:{'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} -Thu, 24 Aug 2017 16:40:05 cos_client.py[line:223] INFO get object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/对象()*'/. 存![]^&*~储{|}~() ,headers=:{} -Thu, 24 Aug 2017 16:40:05 cos_client.py[line:251] INFO delete object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/对象()*'/. 存![]^&*~储{|}~() ,headers=:{} -Thu, 24 Aug 2017 16:40:06 cos_client.py[line:205] INFO put object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB ,headers=:{'x-cos-meta-tiedu': 'value1', 'Content-Disposition': 'download.txt', 'Cache-Control': 'no-cache'} -Thu, 24 Aug 2017 16:40:07 cos_client.py[line:223] INFO get object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB ,headers=:{} -Thu, 24 Aug 2017 16:40:08 cos_client.py[line:417] INFO head object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB ,headers=:{} -Thu, 24 Aug 2017 16:40:08 cos_client.py[line:417] INFO head object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB123 ,headers=:{} -Thu, 24 Aug 2017 16:40:08 cos_client.py[line:185] ERROR {'message': 'The Resource You Head Not Exist', 'code': 'NoSuchResource', 'resource': u'http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB123', 'requestid': 'NTk5ZTkwZThfMmJhZDM1MGFfNWZiZl8xMTJiM2I=', 'traceid': 'OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTBjYzE2MjAxN2M1MzJiOTdkZjMxMDVlYTZjN2FiMmI0ZWYwOWQwMTU1YmYwMjU3YTgwYWJmNGMzMTcxYjhkYzI='} -Thu, 24 Aug 2017 16:40:08 cos_client.py[line:417] INFO head object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/tmp67857_2MB ,headers=:{} -Thu, 24 Aug 2017 16:40:08 cos_client.py[line:386] INFO list objects, url=:http://test01-1252448703.cos.cn-north.myqcloud.com ,headers=:{} -Thu, 24 Aug 2017 16:40:08 cos_client.py[line:358] INFO create bucket, url=:http://test67857-1252448703.cos.cn-north.myqcloud.com ,headers=:{'x-cos-acl': 'public-read'} -Thu, 24 Aug 2017 16:40:09 cos_client.py[line:372] INFO delete bucket, url=:http://test67857-1252448703.cos.cn-north.myqcloud.com ,headers=:{} -Thu, 24 Aug 2017 16:40:10 cos_client.py[line:265] INFO create multipart upload, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} -Thu, 24 Aug 2017 16:40:10 cos_client.py[line:319] INFO abort multipart upload, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?uploadId=15035640107b22d13cfd16ad8c8144ac0a4e2e3a019516e06052a238d9d2c538bbab6270c1 ,headers=:{} -Thu, 24 Aug 2017 16:40:10 cos_client.py[line:265] INFO create multipart upload, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?uploads ,headers=:{} -Thu, 24 Aug 2017 16:40:10 cos_client.py[line:283] INFO put object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?partNumber=1&uploadId=150356401005d26e572e6c48784524519ed25e78078f4da2cc276dd8208555bbc058bf78aa ,headers=:{} -Thu, 24 Aug 2017 16:40:11 cos_client.py[line:283] INFO put object, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?partNumber=2&uploadId=150356401005d26e572e6c48784524519ed25e78078f4da2cc276dd8208555bbc058bf78aa ,headers=:{} -Thu, 24 Aug 2017 16:40:12 cos_client.py[line:333] INFO list multipart upload, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?uploadId=150356401005d26e572e6c48784524519ed25e78078f4da2cc276dd8208555bbc058bf78aa ,headers=:{} -Thu, 24 Aug 2017 16:40:12 cos_client.py[line:299] INFO complete multipart upload, url=:http://test01-1252448703.cos.cn-north.myqcloud.com/multipartfile.txt?uploadId=150356401005d26e572e6c48784524519ed25e78078f4da2cc276dd8208555bbc058bf78aa ,headers=:{} diff --git a/qcloud_cos/streambody.pyc b/qcloud_cos/streambody.pyc deleted file mode 100644 index d96b36d16f64e4409bb3a9ac44aabf5dbc880264..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1700 zcmcIk!EVz)5S@*av?(c|!hs?Vk>C&sg2e%GK?qtnAfY0hLusUH<;I)Fjbo?Y4WTHx z5bm7elQ{4*d;q)|C#g7a3zj{eo!xyiZ)SGAU)x*9-@YGpY4LdYKgVb9LPU5KB}5%4 zC5p-vdGv*7PIS~!JlAekurB_M=fG`2ZM)or!@VrJSV5Lx-os~o2m>(eB!=k#Qi~B$&s(rnY1W{unIOX zwRUQpTc%dfV(-f`a3;AdTqa@k6ABYqR$@@4{63*ORu;_e&K1o{l-9W}XnYJmqiH>w zdE8OR0$OxlqOT#%%Jgx6xw%3S-YVzl3S4lI{m(Klga@)#R97etd2sg$&Zz4s5CMx1uD;V3cAGEXxtTy7LBGEg&}2@2TZ0nDp0spn;5V40@wlGW$$U1Y4&{$R(qR$sU5Xjs+X$x z-%(X{UENe$kaZ<|7WW79&{{4~t%q4O1~(n>-4zIHCLG*?xC~#k^;}{BfQfT&IdxT4 k^J-q*D_n8@B*@&HkBxO!7XOzp#Ld%!{WJC}hq&(j0oZ$WMgRZ+ diff --git a/qcloud_cos/xml2dict.pyc b/qcloud_cos/xml2dict.pyc deleted file mode 100644 index e2c87c94e31f08e96b01528e777e6b415e7c07bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1840 zcmcIkO>fjl5Uuungh?hsu!04&5~Df!l9+%NaWE4ES+OS$4iYd@WSMbK@QlYE+&xhu zP4*K01e_69#EIK-LHv~c1AE!q@~UhyQ9$AXmb+Y4-PKiH@40LLt}gGqeD!2N)l@VNw04u1AAPKg7YqhxdNffLWuMC9WITP z8U@>~gXsZ_Mm6r?YyN?lqaG=@aA{67Qe>Tl6XoGmC};mYd$)Gp(xF4PMstT}ie0kx zNWSyEt01$93;YQLi12h zc}mrdA=_>Wat~?2hv_Cq7~E{)Ytvwszhz;%GQf7z3&|6&&yY2!PI@)L2KW z#w{xTV&#a4(FLfGGOH>>z`M+}U|1W(Y!M!mX#UO1Ip|yKgjMCbRVkwkFPEaAFHUiHGhmL%PK)A1`w;|_zk-Qx zxQwQ1ovlilL`fEg=0AA-O)#>vrwfzh+3oJe`n7IHXM;RWvfbO=nH{d(>UK7J%N;y^ zq0KC{r6G<%KFe%}2nWyRvQajbYK3VZ$(@`6#@G@ z5jRdn!2T-2_o_3vZ5-Y*d^rEQwuRQ~f0Q@CL+C;o%mjR=NFM`6+4ALNgjo_I7s<&m zzNdyojvK2$1BJ3ho?FW>Kc1v~t=!AAVX`Y%4ifNP@DrdHp#73%JtnH*^R{ajueO(( I>H?_x87yg!D*ylh From 335758e9cd27a352cb57819da5389165af3d23b5 Mon Sep 17 00:00:00 2001 From: dt3310321 Date: Fri, 25 Aug 2017 17:04:42 +0800 Subject: [PATCH 67/71] Add temporary token --- qcloud_cos/cos_client.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 8a389924..d07474f3 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -107,11 +107,12 @@ def mapped(headers): class CosConfig(object): """config类,保存用户相关信息""" - def __init__(self, Appid, Region, Access_id, Access_key): + def __init__(self, Appid, Region, Access_id, Access_key, Token=None): self._appid = Appid self._region = Region self._access_id = Access_id self._access_key = Access_key + self._token = Token logger.info("config parameter-> appid: {appid}, region: {region}".format( appid=Appid, region=Region)) @@ -156,6 +157,8 @@ def get_auth(self, Method, Bucket, Key=None, **kwargs): return auth(r).headers['Authorization'] def send_request(self, method, url, timeout=30, **kwargs): + if self._conf._token is not None: + kwargs['headers']['x-cos-security-token'] = self._conf._token try: for j in range(self._retry): if method == 'POST': @@ -174,8 +177,8 @@ def send_request(self, method, url, timeout=30, **kwargs): logger.exception('url:%s, exception:%s' % (url, str(e))) raise CosClientError(str(e)) - if res.status_code >= 300: # 所有的3XX,4XX,5XX都认为是COSServiceError - if method == 'HEAD': # Head 需要处理 + if res.status_code >= 400: # 所有的4XX,5XX都认为是COSServiceError + if method == 'HEAD' and res.status_code == 404: # Head 需要处理 info = dict() info['code'] = 'NoSuchResource' info['message'] = 'The Resource You Head Not Exist' @@ -453,12 +456,14 @@ def copy_object(self, Bucket, Key, CopySource, CopyStatus='Copy', **kwargs): data = xml_to_dict(rt.text) return data - def list_buckets(self): + def list_buckets(self, **kwargs): """列出所有bucket""" + headers = mapped(kwargs) url = 'http://service.cos.myqcloud.com/' rt = self.send_request( method='GET', url=url, + headers=headers, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), ) data = xml_to_dict(rt.text) From 2bb8d19808523741c4abfd5ed67284af6e1f6a16 Mon Sep 17 00:00:00 2001 From: tiedu Date: Sat, 26 Aug 2017 10:53:19 +0800 Subject: [PATCH 68/71] Modify the code structure --- qcloud_cos/cos_client.py | 93 +++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index d07474f3..1f408e07 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -194,6 +194,7 @@ def send_request(self, method, url, timeout=30, **kwargs): logger.error(msg) raise CosServiceError(method, msg, res.status_code) + # s3 object interface begin def put_object(self, Bucket, Body, Key, **kwargs): """单文件上传接口,适用于小文件,最大不得超过5GB""" headers = mapped(kwargs) @@ -259,6 +260,51 @@ def delete_object(self, Bucket, Key, **kwargs): headers=headers) return None + def head_object(self, Bucket, Key, **kwargs): + """获取文件信息""" + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("head object, url=:{url} ,headers=:{headers}".format( + url=url, + headers=headers)) + rt = self.send_request( + method='HEAD', + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) + return rt.headers + + def gen_copy_source_url(self, CopySource): + """拼接拷贝源url""" + if 'Bucket' in CopySource.keys(): + bucket = CopySource['Bucket'] + else: + raise CosClientError('CopySource Need Parameter Bucket') + if 'Key' in CopySource.keys(): + key = CopySource['Key'] + else: + raise CosClientError('CopySource Need Parameter Key') + url = self._conf.uri(bucket=bucket, path=key).encode('utf8') + url = url[7:] # copysource不支持http://开头,去除 + return url + + def copy_object(self, Bucket, Key, CopySource, CopyStatus='Copy', **kwargs): + """文件拷贝,文件信息修改""" + headers = mapped(kwargs) + headers['x-cos-copy-source'] = self.gen_copy_source_url(CopySource) + headers['x-cos-metadata-directive'] = CopyStatus + url = self._conf.uri(bucket=Bucket, path=Key) + logger.info("copy object, url=:{url} ,headers=:{headers}".format( + url=url, + headers=headers)) + rt = self.send_request( + method='PUT', + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) + data = xml_to_dict(rt.text) + return data + def create_multipart_upload(self, Bucket, Key, **kwargs): """创建分片上传,适用于大文件上传""" headers = mapped(kwargs) @@ -352,6 +398,7 @@ def list_parts(self, Bucket, Key, UploadId, **kwargs): else: return data + # s3 bucket interface begin def create_bucket(self, Bucket, **kwargs): """创建一个bucket""" headers = mapped(kwargs) @@ -411,51 +458,7 @@ def list_objects(self, Bucket, Delimiter="", Marker="", MaxKeys=1000, Prefix="", else: return data - def head_object(self, Bucket, Key, **kwargs): - """获取文件信息""" - headers = mapped(kwargs) - url = self._conf.uri(bucket=Bucket, path=Key) - logger.info("head object, url=:{url} ,headers=:{headers}".format( - url=url, - headers=headers)) - rt = self.send_request( - method='HEAD', - url=url, - auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers) - return rt.headers - - def gen_copy_source_url(self, CopySource): - """拼接拷贝源url""" - if 'Bucket' in CopySource.keys(): - bucket = CopySource['Bucket'] - else: - raise CosClientError('CopySource Need Parameter Bucket') - if 'Key' in CopySource.keys(): - key = CopySource['Key'] - else: - raise CosClientError('CopySource Need Parameter Key') - url = self._conf.uri(bucket=bucket, path=key).encode('utf8') - url = url[7:] # copysource不支持http://开头,去除 - return url - - def copy_object(self, Bucket, Key, CopySource, CopyStatus='Copy', **kwargs): - """文件拷贝,文件信息修改""" - headers = mapped(kwargs) - headers['x-cos-copy-source'] = self.gen_copy_source_url(CopySource) - headers['x-cos-metadata-directive'] = CopyStatus - url = self._conf.uri(bucket=Bucket, path=Key) - logger.info("copy object, url=:{url} ,headers=:{headers}".format( - url=url, - headers=headers)) - rt = self.send_request( - method='PUT', - url=url, - auth=CosS3Auth(self._conf._access_id, self._conf._access_key), - headers=headers) - data = xml_to_dict(rt.text) - return data - + # service interface begin def list_buckets(self, **kwargs): """列出所有bucket""" headers = mapped(kwargs) From 11e7e07a031aacab158b22b1b91978eeaf9354eb Mon Sep 17 00:00:00 2001 From: tiedu Date: Sat, 26 Aug 2017 12:45:57 +0800 Subject: [PATCH 69/71] Add the Expired Time For Auth --- qcloud_cos/cos_client.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 1f408e07..09e6e433 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -147,13 +147,11 @@ def __init__(self, conf, retry=1, session=None): else: self._session = session - def get_auth(self, Method, Bucket, Key=None, **kwargs): + def get_auth(self, Method, Bucket, Key=None, Expired=10000, headers={}, params={}): """获取签名""" - headers = mapped(kwargs) - # TODO(tiedu) 检查header的参数合法性 url = self._conf.uri(bucket=Bucket, path=Key) - r = Request(Method, url) - auth = CosS3Auth(self._conf._access_id, self._conf._access_key) + r = Request(Method, url, headers=headers, params=params) + auth = CosS3Auth(self._conf._access_id, self._conf._access_key, Expired) return auth(r).headers['Authorization'] def send_request(self, method, url, timeout=30, **kwargs): @@ -239,10 +237,10 @@ def get_object(self, Bucket, Key, **kwargs): response[k] = rt.headers[k] return response - def get_presigned_download_url(self, Bucket, Key): + def get_presigned_download_url(self, Bucket, Key, Expired=10000): """生成预签名的下载url""" url = self._conf.uri(bucket=Bucket, path=Key) - sign = self.get_auth(Method='GET', Bucket=Bucket, Key=Key) + sign = self.get_auth(Method='GET', Bucket=Bucket, Key=Key, Expired=10000) url = url + '?sign=' + urllib.quote(sign) return url From bf4c0c52fd5d24d9cf8d06ac8e722cc7f7dd1d78 Mon Sep 17 00:00:00 2001 From: tiedu Date: Sat, 26 Aug 2017 16:36:41 +0800 Subject: [PATCH 70/71] Add acl --- qcloud_cos/cos_client.py | 116 ++++++++++++++++++++++++++++++++------- qcloud_cos/test.py | 35 ++++++++++++ qcloud_cos/xml2dict.py | 4 +- 3 files changed, 132 insertions(+), 23 deletions(-) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 09e6e433..d3dc79af 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -82,6 +82,10 @@ def xml_to_dict(data): """V5使用xml格式,将response中的xml转换为dict""" root = xml.etree.ElementTree.fromstring(data) xmldict = Xml2Dict(root) + xmlstr = str(xmldict) + xmlstr = xmlstr.replace("{http://www.qcloud.com/document/product/436/7751}", "") + xmlstr = xmlstr.replace("{http://www.w3.org/2001/XMLSchema-instance}", "") + xmldict = eval(xmlstr) return xmldict @@ -351,11 +355,8 @@ def complete_multipart_upload(self, Bucket, Key, UploadId, MultipartUpload={}, * data=dict_to_xml(MultipartUpload), timeout=1200, # 分片上传大文件的时间比较长,设置为20min headers=headers) - response = dict() data = xml_to_dict(rt.text) - for key in data.keys(): - response[key[key.find('}')+1:]] = data[key] - return response + return data def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs): """放弃一个已经存在的分片上传任务,删除所有已经存在的分片""" @@ -383,18 +384,45 @@ def list_parts(self, Bucket, Key, UploadId, **kwargs): url=url, auth=CosS3Auth(self._conf._access_id, self._conf._access_key), headers=headers) + data = xml_to_dict(rt.text) + if 'Part' in data.keys() and isinstance(data['Part'], dict): # 只有一个part,将dict转为list,保持一致 + lst = [] + lst.append(data['Part']) + data['Part'] = lst + return data + + def put_object_acl(self, Bucket, Key, **kwargs): + """设置object ACL""" + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?acl") + logger.info("put object acl, url=:{url} ,headers=:{headers}".format( + url=url, + headers=headers)) + rt = self.send_request( + method='PUT', + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) + return None + def get_object_acl(self, Bucket, Key, **kwargs): + """获取object ACL""" + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path=Key+"?acl") + logger.info("get object acl, url=:{url} ,headers=:{headers}".format( + url=url, + headers=headers)) + rt = self.send_request( + method='GET', + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) data = xml_to_dict(rt.text) - if 'Part' in data.keys(): - if isinstance(data['Part'], list): - return data - else: # 只有一个part,将dict转为list,保持一致 - lst = [] - lst.append(data['Part']) - data['Part'] = lst - return data - else: - return data + if data['AccessControlList'] is not None and isinstance(data['AccessControlList']['Grant'], dict): + lst = [] + lst.append(data['AccessControlList']['Grant']) + data['AccessControlList']['Grant'] = lst + return data # s3 bucket interface begin def create_bucket(self, Bucket, **kwargs): @@ -445,16 +473,58 @@ def list_objects(self, Bucket, Delimiter="", Marker="", MaxKeys=1000, Prefix="", auth=CosS3Auth(self._conf._access_id, self._conf._access_key)) data = xml_to_dict(rt.text) - if 'Contents' in data.keys(): - if isinstance(data['Contents'], list): - return data - else: # 只有一个Contents,将dict转为list,保持一致 + if 'Contents' in data.keys() and isinstance(data['Contents'], dict): # 只有一个Contents,将dict转为list,保持一致 lst = [] lst.append(data['Contents']) data['Contents'] = lst - return data - else: - return data + return data + + def head_bucket(self, Bucket, **kwargs): + """获取bucket信息""" + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket) + logger.info("head bucket, url=:{url} ,headers=:{headers}".format( + url=url, + headers=headers)) + rt = self.send_request( + method='HEAD', + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) + return None + + def put_bucket_acl(self, Bucket, **kwargs): + """设置bucket ACL""" + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path="?acl") + logger.info("put bucket acl, url=:{url} ,headers=:{headers}".format( + url=url, + headers=headers)) + rt = self.send_request( + method='PUT', + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) + return None + + def get_bucket_acl(self, Bucket, **kwargs): + """获取bucket ACL""" + headers = mapped(kwargs) + url = self._conf.uri(bucket=Bucket, path="?acl") + logger.info("get bucket acl, url=:{url} ,headers=:{headers}".format( + url=url, + headers=headers)) + rt = self.send_request( + method='GET', + url=url, + auth=CosS3Auth(self._conf._access_id, self._conf._access_key), + headers=headers) + data = xml_to_dict(rt.text) + if data['AccessControlList'] is not None and isinstance(data['AccessControlList']['Grant'], dict): + lst = [] + lst.append(data['AccessControlList']['Grant']) + data['AccessControlList']['Grant'] = lst + return data # service interface begin def list_buckets(self, **kwargs): @@ -468,6 +538,10 @@ def list_buckets(self, **kwargs): auth=CosS3Auth(self._conf._access_id, self._conf._access_key), ) data = xml_to_dict(rt.text) + if data['Buckets'] is not None and isinstance(data['Buckets']['Bucket'], dict): + lst = [] + lst.append(data['Buckets']['Bucket']) + data['Buckets']['Bucket'] = lst return data if __name__ == "__main__": diff --git a/qcloud_cos/test.py b/qcloud_cos/test.py index 7811880f..077291de 100644 --- a/qcloud_cos/test.py +++ b/qcloud_cos/test.py @@ -147,6 +147,19 @@ def Test(): except CosServiceError as e: print_error_msg(e) + print "Test Put Object ACL " + file_name + response = client.put_object_acl( + Bucket=test_bucket, + Key=file_name, + ACL='public-read-write' + ) + + print "Test Get Object ACL" + file_name + response = client.get_object_acl( + Bucket=test_bucket, + Key=file_name + ) + print "Test Delete Object " + file_name response = client.head_object( Bucket=test_bucket, @@ -164,11 +177,33 @@ def Test(): ACL='public-read' ) + print "Test PUT Bucket ACL" + try: + response = client.put_bucket_acl( + Bucket='test'+file_id, + ACL='public-read-writea' + ) + except CosServiceError as e: + print_error_msg(e) + + print "Test GET Bucket ACL" + response = client.get_bucket_acl( + Bucket='test'+file_id, + ) + print "Test Delete Bucket" response = client.delete_bucket( Bucket='test'+file_id ) + print "Test Head Bucket" + try: + response = client.head_bucket( + Bucket='test'+file_id + ) + except CosServiceError as e: + print_error_msg(e) + print "Test Create MultipartUpload" response = client.create_multipart_upload( Bucket=test_bucket, diff --git a/qcloud_cos/xml2dict.py b/qcloud_cos/xml2dict.py index cfa23414..dedd5c14 100644 --- a/qcloud_cos/xml2dict.py +++ b/qcloud_cos/xml2dict.py @@ -35,12 +35,12 @@ def updateDict(self, aDict): if __name__ == "__main__": s = """ - + 10 1test1 2test2 3test3 """ root = xml.etree.ElementTree.fromstring(s) - xmldict = XmlDictConfig(root) + xmldict = Xml2Dict(root) print xmldict From 01552dbafc1484d9f994c0a64571014aefc1f4ce Mon Sep 17 00:00:00 2001 From: tiedu Date: Sat, 26 Aug 2017 16:52:45 +0800 Subject: [PATCH 71/71] Update README.rst support pip install --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index a2a143ea..62b9a075 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,7 @@ __________ 使用pip安装 :: - pip install -U qcloud_cos_v5 + pip install -U cos-python-sdk-v5 手动安装::