Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1. add random test bucket name 2. add delete test file after finish 3… #173

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions oss2/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ class Bucket(_Base):
STAT = 'stat'
BUCKET_INFO = 'bucketInfo'
PROCESS = 'x-oss-process'
TAGGING = 'tagging'

def __init__(self, auth, endpoint, bucket_name,
is_cname=False,
Expand Down Expand Up @@ -1595,6 +1596,50 @@ def process_object(self, key, process):
resp = self.__do_object('POST', key, params={Bucket.PROCESS: ''}, data=process_data)
logger.debug("Process object done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
return ProcessObjectResult(resp)

def put_object_tagging(self, key, input, headers=None):
"""

:param str key: 上传tagging的对象名称,不能为空。

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1、注释最好用英文
2、参数input最好能换一个有意义的,比如 tagBody

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

注释这里 沿用的之前的风格,参数名称我换下

:param input: tag 标签内容
:type input: :class:`ObjectTagging <oss2.models.ObjectTagging>` 对象

:return: :class:`RequestResult <oss2.models.RequestResult>`
"""
logger.debug("Start to put object tagging, bucket: {0}, key: {1}, tagging: {2}".format(
self.bucket_name, to_string(key), input))

if headers is not None:
headers = http.CaseInsensitiveDict(headers)

data = self.__convert_data(ObjectTagging, xml_utils.to_put_object_tagging, input)
resp = self.__do_object('PUT', key, data=data, params={Bucket.TAGGING: ''}, headers=headers)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1、需要对key是否为空进行合法性检查
2、需要对data进行合法性检查,是否是一个ObjectTagging对象

Copy link
Collaborator Author

@coderall coderall Apr 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1、key为空,现在所有接口都没有判断
2、参数类型也不用,如果不是这个类型,后面访问类中变量或方法时会报异常


return RequestResult(resp)

def get_object_tagging(self, key):

"""
:param str key: 要获取tagging的对象名称
:return: :class:`ObjectTagging <oss2.models.ObjectTagging>`
"""
logger.debug("Start to get object tagging, bucket: {0}, key: {1}".format(
self.bucket_name, to_string(key)))
resp = self.__do_object('GET', key, params={Bucket.TAGGING: ''})

return self._parse_result(resp, xml_utils.parse_get_object_tagging, GetObjectTaggingResult)

def delete_object_tagging(self, key):
"""
:param str key: 要删除tagging的对象名称
:return: :class:`ObjectTagging <oss2.models.ObjectTagging>`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete 接口的返回值 是否需要定义为 ObjectTagging ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里写的有问题,我改下

"""
logger.debug("Start to delete object tagging, bucket: {0}, key: {1}".format(
self.bucket_name, to_string(key)))
resp = self.__do_object('DELETE', key, params={Bucket.TAGGING: ''})
logger.debug("Delete object tagging done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
return RequestResult(resp)

def _get_bucket_config(self, config):
"""获得Bucket某项配置,具体哪种配置由 `config` 指定。该接口直接返回 `RequestResult` 对象。
Expand Down
2 changes: 1 addition & 1 deletion oss2/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class Auth(AuthBase):
'response-expires', 'response-content-disposition', 'cors', 'lifecycle',
'restore', 'qos', 'referer', 'stat', 'bucketInfo', 'append', 'position', 'security-token',
'live', 'comp', 'status', 'vod', 'startTime', 'endTime', 'x-oss-process',
'symlink', 'callback', 'callback-var']
'symlink', 'callback', 'callback-var', 'tagging']
)

def _sign_request(self, req, bucket_name, key):
Expand Down
3 changes: 3 additions & 0 deletions oss2/headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
OSS_SERVER_SIDE_ENCRYPTION = "x-oss-server-side-encryption"
OSS_SERVER_SIDE_ENCRYPTION_KEY_ID = "x-oss-server-side-encryption-key-id"

OSS_OBJECT_TAGGING = "x-oss-tagging"
OSS_OBJECT_TAGGING_COPY_DIRECTIVE = "x-oss-tagging-directive"


class RequestHeader(dict):
def __init__(self, *arg, **kw):
Expand Down
46 changes: 45 additions & 1 deletion oss2/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ class LifecycleRule(object):
:param expiration: 过期删除操作。
:type expiration: :class:`LifecycleExpiration`
:param status: 启用还是禁止该规则。可选值为 `LifecycleRule.ENABLED` 或 `LifecycleRule.DISABLED`
:param storage_transitions: 存储类型转换规则
:type storage_transitions: :class:`StorageTransition`
:param tagging: object tagging 规则
:type tagging: :class:`ObjectTagging`
"""

ENABLED = 'Enabled'
Expand All @@ -560,13 +564,14 @@ class LifecycleRule(object):
def __init__(self, id, prefix,
status=ENABLED, expiration=None,
abort_multipart_upload=None,
storage_transitions=None):
storage_transitions=None, tagging=None):
self.id = id
self.prefix = prefix
self.status = status
self.expiration = expiration
self.abort_multipart_upload = abort_multipart_upload
self.storage_transitions = storage_transitions
self.tagging = tagging


class BucketLifecycle(object):
Expand Down Expand Up @@ -878,3 +883,42 @@ def __init__(self, resp):
self.object = result['object']
if 'status' in result:
self.process_status = result['status']

_MAX_OBJECT_TAGGING_KEY_LENGTH=128
_MAX_OBJECT_TAGGING_VALUE_LENGTH=256

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这些常量定义有统一地方放吗?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

写的时候也在想这个事,但是好像没有统一定义的地方

class ObjectTagging(object):

def __init__(self, tagging_rules=None):

self.tag_set = tagging_rules or ObjectTaggingRule()

class ObjectTaggingRule(object):

def __init__(self):
self.tagging_rule = dict()

def add(self, key, value):

if key is None or key == '':
raise ClientError("ObjectTagging key should not be empty")

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value为空是否需要校验一下?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

后端接受value为空的情况

if len(key) > _MAX_OBJECT_TAGGING_KEY_LENGTH:
raise ClientError("ObjectTagging key is too long")

if len(value) > _MAX_OBJECT_TAGGING_VALUE_LENGTH:
raise ClientError("ObjectTagging value is too long")

self.tagging_rule[key] = value

def delete(self, key):
del self.tagging_rule[key]

def len(self):
return len(self.tagging_rule)

class GetObjectTaggingResult(RequestResult, ObjectTagging):

def __init__(self, resp):
RequestResult.__init__(self, resp)
ObjectTagging.__init__(self)
57 changes: 55 additions & 2 deletions oss2/xml_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
Owner,
AccessControlList,
AbortMultipartUpload,
StorageTransition)
StorageTransition,
ObjectTagging,
ObjectTaggingRule)

from .compat import urlunquote, to_unicode, to_string
from .utils import iso8601_to_unixtime, date_to_iso8601, iso8601_to_date
Expand Down Expand Up @@ -422,21 +424,36 @@ def parse_lifecycle_storage_transitions(storage_transition_nodes):

return storage_transitions

def parse_lifecycle_object_taggings(lifecycle_tagging_nodes, url_encoded):

if lifecycle_tagging_nodes is None:
return ObjectTagging()

tagging_rule = ObjectTaggingRule()
for tag_node in lifecycle_tagging_nodes:
key = _find_object(tag_node, 'Key', url_encoded)
value = _find_object(tag_node, 'Value', url_encoded)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要确认一下,在lifecycle 里, key 和value 是否受 url_encoded 标志位的影响。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

和后端开发同学确认,有关tagging的返回,在body里面都不会 urlencode,这里的代码我改下

tagging_rule.add(key, value)

return ObjectTagging(tagging_rule)

def parse_get_bucket_lifecycle(result, body):
root = ElementTree.fromstring(body)
url_encoded = _is_url_encoding(root)

for rule_node in root.findall('Rule'):
expiration = parse_lifecycle_expiration(rule_node.find('Expiration'))
abort_multipart_upload = parse_lifecycle_abort_multipart_upload(rule_node.find('AbortMultipartUpload'))
storage_transitions = parse_lifecycle_storage_transitions(rule_node.findall('Transition'))
tagging = parse_lifecycle_object_taggings(rule_node.findall('Tag'), url_encoded)
rule = LifecycleRule(
_find_tag(rule_node, 'ID'),
_find_tag(rule_node, 'Prefix'),
status=_find_tag(rule_node, 'Status'),
expiration=expiration,
abort_multipart_upload=abort_multipart_upload,
storage_transitions=storage_transitions
storage_transitions=storage_transitions,
tagging=tagging
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

两个变量名怎么是一样的?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

diff 结果应该符合预期吧

)
result.rules.append(rule)

Expand Down Expand Up @@ -567,6 +584,13 @@ def to_put_bucket_lifecycle(bucket_lifecycle):
_add_text_child(storage_transition_node, 'CreatedBeforeDate',
date_to_iso8601(storage_transition.created_before_date))

tagging = rule.tagging
if tagging:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tagging是bool类型吗?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python的语法习惯,这里tagging是ObjectTagging类型

tagging_rule = tagging.tag_set.tagging_rule
for key in tagging.tag_set.tagging_rule:
tag_node = ElementTree.SubElement(rule_node, 'Tag')
_add_text_child(tag_node, 'Key', key)
_add_text_child(tag_node, 'Value', tagging_rule[key])
return _node_to_string(root)


Expand Down Expand Up @@ -741,3 +765,32 @@ def to_get_select_json_object_meta(json_meta_param):
raise SelectOperationClientError("The json_meta_param contains unsupported key " + key, "")

return _node_to_string(root)

def to_put_object_tagging(object_tagging):
root = ElementTree.Element("Tagging")
tag_set = ElementTree.SubElement(root, "TagSet")

for item in object_tagging.tag_set.tagging_rule:
tag_xml = ElementTree.SubElement(tag_set, "Tag")
_add_text_child(tag_xml, 'Key', item)
_add_text_child(tag_xml, 'Value', object_tagging.tag_set.tagging_rule[item])

return _node_to_string(root)

def parse_get_object_tagging(result, body):
root = ElementTree.fromstring(body)
url_encoded = _is_url_encoding(root)
tagset_node = root.find('TagSet')

if tagset_node is None:
return result

tagging_rules = ObjectTaggingRule()
for tag_node in tagset_node.findall('Tag'):
key = _find_object(tag_node, 'Key', url_encoded)
value = _find_object(tag_node, 'Value', url_encoded)
tagging_rules.add(key, value)

result.tag_set = tagging_rules
return result

Empty file added tests/__init__.py
Empty file.
10 changes: 7 additions & 3 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
OSS_ID = os.getenv("OSS_TEST_ACCESS_KEY_ID")
OSS_SECRET = os.getenv("OSS_TEST_ACCESS_KEY_SECRET")
OSS_ENDPOINT = os.getenv("OSS_TEST_ENDPOINT")
OSS_BUCKET = os.getenv("OSS_TEST_BUCKET")
OSS_TEST_BUCKET = os.getenv("OSS_TEST_BUCKET")
OSS_CNAME = os.getenv("OSS_TEST_CNAME")
OSS_CMK = os.getenv("OSS_TEST_CMK")
OSS_REGION = os.getenv("OSS_TEST_REGION", "cn-hangzhou")
Expand All @@ -30,7 +30,11 @@
def random_string(n):
return ''.join(random.choice(string.ascii_lowercase) for i in range(n))


OSS_BUCKET = ''
if OSS_TEST_BUCKET is None:
OSS_BUCKET = 'aliyun-oss-python-sdk-'+random_string(10)
else:
OSS_BUCKET = OSS_TEST_BUCKET + random_string(10)

def random_bytes(n):
return oss2.to_bytes(random_string(n))
Expand Down Expand Up @@ -82,7 +86,7 @@ def setUp(self):

global OSS_AUTH_VERSION
OSS_AUTH_VERSION = os.getenv('OSS_TEST_AUTH_VERSION')

self.bucket = oss2.Bucket(oss2.make_auth(OSS_ID, OSS_SECRET, OSS_AUTH_VERSION), OSS_ENDPOINT, OSS_BUCKET)

try:
Expand Down
Loading