OSS_OBJECT_TAGGING = "x-oss-tagging" OSS_OBJECT_TAGGING_COPY_DIRECTIVE = "x-oss-tagging-directive" def determine_part_size(total_size,
                        preferred_size=None):
    """确定分片上传是分片的大小。

    :param int total_size: 总共需要上传的长度
    :param int preferred_size: 用户期望的分片大小。如果不指定则采用defaults.part_size

    :return: 分片大小
    """
    if not preferred_size:
        preferred_size = defaults.part_size

    return _determine_part_size_internal(total_size, preferred_size, defaults.max_part_count) class SizedFileAdapter(object):
    """通过这个适配器（Adapter），可以把原先的 `file_object` 的长度限制到等于 `size`。"""
    def __init__(self, file_object, size):
        self.file_object = file_object
        self.size = size
        self.offset = 0

    def read(self, amt=None):
        if self.offset >= self.size:
            return ''

        if (amt is None or amt < 0) or (amt + self.offset >= self.size):
            data = self.file_object.read(self.size - self.offset)
            self.offset = self.size
            return data

        self.offset += amt
        return self.file_object.read(amt)

    @property
    def len(self):
        return self.size OSS_OBJECT_TAGGING = "x-oss-tagging" class LifecycleExpiration(object):
    """过期删除操作。

    :param days: 表示在文件修改后过了这么多天，就会匹配规则，从而被删除
    :type days: int

    :param date: 表示在该日期之后，规则就一直生效。即每天都会对符合前缀的文件执行删除操作（如，删除），而不管文件是什么时候生成的。*不建议使用*
    :type date: `datetime.date`

    :param created_before_date: delete files if their last modified time earlier than created_before_date
    :type created_before_date: `datetime.date`

    :param expired_detete_marker: 真实文件删除之后是否自动移除删除标记，适用于多版本场景。
    :param expired_detete_marker: bool

    """
    def __init__(self, days=None, date=None, created_before_date=None, expired_detete_marker=None):
        not_none_fields = 0
        if days is not None:
            not_none_fields += 1
        if date is not None:
            not_none_fields += 1
        if created_before_date is not None:
            not_none_fields += 1
        if expired_detete_marker is not None:
            not_none_fields += 1

        if not_none_fields > 1:
            raise ClientError('More than one field(days, date and created_before_date, expired_detete_marker) has been specified')

        self.days = days
        self.date = date
        self.created_before_date = created_before_date
        self.expired_detete_marker = expired_detete_marker class LifecycleRule(object):
    """生命周期规则。

    :param id: 规则名
    :type id: str

    :param prefix: 只有文件名匹配该前缀的文件才适用本规则
    :type prefix: str

    :param expiration: 过期删除操作。
    :type expiration: :class:`LifecycleExpiration`

    :param status: 启用还是禁止该规则。可选值为 `LifecycleRule.ENABLED` 或 `LifecycleRule.DISABLED`

    :param storage_transitions: 存储类型转换规则
    :type storage_transitions: list of class:`StorageTransition <oss2.models.StorageTransition>`

    :param tagging: object tagging 规则
    :type tagging: :class:`Tagging <oss2.models.StorageTransition>`
    
    :param noncurrent_version_expiration: 指定Object非当前版本生命周期规则的过期属性。适用于多版本场景。
    :type noncurrent_version_expiration class:`NoncurrentVersionExpiration <oss2.models.NoncurrentVersionExpiration>`

    :param noncurrent_version_sotrage_transitions: 在有效生命周期中，OSS何时将指定Object的非当前版本转储为IA或者Archive存储类型，适用于多版本场景。
    :type noncurrent_version_sotrage_transitions: list of class:`NoncurrentVersionStorageTransition <oss2.models.NoncurrentVersionStorageTransition>`
    """

    ENABLED = 'Enabled'
    DISABLED = 'Disabled'

    def __init__(self, id, prefix,
                 status=ENABLED, expiration=None,
                 abort_multipart_upload=None,
                 storage_transitions=None, tagging=None,
                 noncurrent_version_expiration=None,
                 noncurrent_version_sotrage_transitions=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
        self.noncurrent_version_expiration = noncurrent_version_expiration
        self.noncurrent_version_sotrage_transitions = noncurrent_version_sotrage_transitions class BucketLifecycle(object):
    """Bucket的生命周期配置。

    :param rules: 规则列表，
    :type rules: list of :class:`LifecycleRule <oss2.models.LifecycleRule>`
    """
    def __init__(self, rules=None):
        self.rules = rules or [] class AbortMultipartUpload(object):
    """删除parts

    :param days: 删除相对最后修改时间days天之后的parts
    :param created_before_date: 删除最后修改时间早于created_before_date的parts

    """
    def __init__(self, days=None, created_before_date=None):
        if days is not None and created_before_date is not None:
            raise ClientError('days and created_before_date should not be both specified')

        self.days = days
        self.created_before_date = created_before_date class TaggingRule(object):

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

    def add(self, key, value):

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

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

        if len(value) > _MAX_OBJECT_TAGGING_VALUE_LENGTH:
            raise ClientError("Tagging 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)

    def to_query_string(self):
        query_string = ''

        for key in self.tagging_rule:
            query_string += urlquote(key)
            query_string += '='
            query_string += urlquote(self.tagging_rule[key])
            query_string += '&'

        if len(query_string) == 0:
            return ''
        else:
            query_string = query_string[:-1]

        return query_string class Tagging(object):

    def __init__(self, tagging_rules=None):
        
        self.tag_set = tagging_rules or TaggingRule() 

    def __str__(self):

        tag_str = ""
        
        tagging_rule = self.tag_set.tagging_rule

        for key in tagging_rule:
            tag_str += key
            tag_str += "#" + tagging_rule[key] + " "

        return tag_str class StorageTransition(object):
    """transit objects

    :param days: 将相对最后修改时间days天之后的Object转储
    :param created_before_date: 将最后修改时间早于created_before_date的对象转储
    :param storage_class: 对象转储到OSS的目标存储类型
    """
    def __init__(self, days=None, created_before_date=None, storage_class=None):
        if days is not None and created_before_date is not None:
            raise ClientError('days and created_before_date should not be both specified')

        self.days = days
        self.created_before_date = created_before_date
        self.storage_class = storage_class class PartInfo(object):
    """表示分片信息的文件。

    该文件既用于 :func:`list_parts <oss2.Bucket.list_parts>` 的输出，也用于 :func:`complete_multipart_upload
    <oss2.Bucket.complete_multipart_upload>` 的输入。

    :param int part_number: 分片号
    :param str etag: 分片的ETag
    :param int size: 分片的大小。用在 `list_parts` 的结果里，也用与分片对象做crc combine得到整个对象crc64值
    :param int last_modified: 该分片最后修改的时间戳，类型为int。参考 :ref:`unix_time`
    :param int part_crc: 该分片的crc64值
    """
    def __init__(self, part_number, etag, size=None, last_modified=None, part_crc=None):
        self.part_number = part_number
        self.etag = etag
        self.size = size
        self.last_modified = last_modified
        self.part_crc = part_crc
import os
import oss2
import datetime
from oss2.headers import OSS_OBJECT_TAGGING, OSS_OBJECT_TAGGING_COPY_DIRECTIVE
from oss2 import SizedFileAdapter, determine_part_size
from oss2.headers import OSS_OBJECT_TAGGING
from oss2.models import (LifecycleExpiration, LifecycleRule,
                         BucketLifecycle, AbortMultipartUpload,
                         TaggingRule, Tagging, StorageTransition, PartInfo)

    offset += num_to_upload
    part_number += 1

# Complete the multipart upload task.
result = bucket.complete_multipart_upload(dest_object_name, upload_id, parts)

# Obtain the metadata of the destination object.
head_info = bucket.head_object(dest_object_name)

# Query the size of the destination object.
dest_object_size = head_info.content_length
print('dest object size:', dest_object_size)

# Compare the size of the destination object with that of the source object.
assert dest_object_size == total_size

# Query the tags of the source object.
result = bucket.get_object_tagging(src_object_name)
for key in result.tag_set.tagging_rule:
    print('src tagging key: {}, value: {}'.format(key, result.tag_set.tagging_rule[key]))

# Query the tags added to the destination object.
result = bucket.get_object_tagging(dest_object_name)
for key in result.tag_set.tagging_rule:
    print('dest tagging key: {}, value: {}'.format(key, result.tag_set.tagging_rule[key]))


# The following code provides an example on how to add tags to a symbolic link:
# Specify the full path of the destination object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name.
object_name = 'exampledir/exampleobject.txt'
# Specify the full path of the symbolic link object. Example: shortcut/myobject.txt.
symlink_name = 'shortcut/myobject.txt'

# Configure the tagging string.
tagging = "k1=v1&k2=v2&k3=v3"

# If tags contain characters, you must encode the keys and values of the tags by using URL encoding.
k4 = "k4+-="
v4 = "+-=._:/"
tagging += "&" + oss2.urlquote(k4) + "=" + oss2.urlquote(v4)

# Configure the tags in the HTTP headers.
headers = dict()
headers[OSS_OBJECT_TAGGING] = tagging

# Add a symbolic link to the object.
# Specify the headers when you call the put_symlink operation so that the tags are added to the symbolic link.
result = bucket.put_symlink(object_name, symlink_name, headers=headers)
print('http response status: ', result.status)

# Query the tags added to the symbolic link.
result = bucket.get_object_tagging(symlink_name)
for key in result.tag_set.tagging_rule:
    print('tagging key: {}, value: {}'.format(key, result.tag_set.tagging_rule[key]))



# The following code provides an example on how to query the tags of the exampleobject.txt object in the exampledir directory of the examplebucket bucket:
# Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name.
object_name = 'exampledir/exampleobject.txt'

# Query the tags of the object.
result = bucket.get_object_tagging(object_name)

# View the tags of the object.
for key in result.tag_set.tagging_rule:
    print('tagging key: {}, value: {}'.format(key, result.tag_set.tagging_rule[key]))


# The following code provides an example on how to query the tags of a specified version of the exampleobject.txt object in the exampledir directory of the examplebucket bucket:
# Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name.
object_name = 'exampledir/exampleobject.txt'
# Specify the version ID of the object. Example: CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****.
version_id = 'CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****'

params = dict()
params['versionId'] = version_id

result = bucket.get_object_tagging(object_name, params=params)
print(result)



# The following code provides an example on how to delete the tags of the exampleobject.txt object in the exampledir directory of the examplebucket bucket:
# Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name.
object_name = 'exampledir/exampleobject.txt'

# Remove the tags of the object.
result = bucket.delete_object_tagging(object_name)
print('http response status: ', result.status)


# The following code provides an example on how to delete the tags of a specified version of the exampleobject.txt object in the exampledir directory of the examplebucket bucket:
# Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name.
object_name = 'exampledir/exampleobject.txt'
# Specify the version ID of the object.
version_id = 'CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****'

params = dict()
params['versionId'] = version_id
bucket.delete_object_tagging(object_name, params=params)



# The following code provides an example on how to add tagging configurations to a lifecycle rule:
# Specify that objects expire three days after they are last modified.
# Set the name of the expiration rule and the prefix to match the objects.
rule1 = LifecycleRule('rule1', 'tests/',
                      # Enable the expiration rule.
                      status=LifecycleRule.ENABLED,
                      # Set the validity period to three days after the last modified date.
                      expiration=LifecycleExpiration(days=3))

# Specify that the objects last modified before the specified date expire.
# Set the name of the expiration rule and the prefix to match the objects.
rule2 = LifecycleRule('rule2', 'logging-',
                      # Disable the expiration rule.
                      status=LifecycleRule.DISABLED,
                      # Specify that the objects last modified before the specified date expire.

                      expiration=LifecycleExpiration(created_before_date=datetime.date(2018, 12, 12)))