oss2.iterators 源代码

优质
小牛编辑
128浏览
2023-12-01
# -*- coding: utf-8 -*-

"""
oss2.iterators
~~~~~~~~~~~~~~

This module contains some easy-to-use iterators for enumerating bucket, file, parts and more.
"""

from .models import MultipartUploadInfo, SimplifiedObjectInfo
from .exceptions import ServerError

from . import defaults


class _BaseIterator(object):
    def __init__(self, marker, max_retries):
        self.is_truncated = True
        self.next_marker = marker

        max_retries = defaults.get(max_retries, defaults.request_retries)
        self.max_retries = max_retries if max_retries > 0 else 1

        self.entries = []

    def _fetch(self):
        raise NotImplemented    # pragma: no cover

    def __iter__(self):
        return self

    def __next__(self):
        while True:
            if self.entries:
                return self.entries.pop(0)

            if not self.is_truncated:
                raise StopIteration

            self.fetch_with_retry()

    def next(self):
        return self.__next__()

    def fetch_with_retry(self):
        for i in range(self.max_retries):
            try:
                self.is_truncated, self.next_marker = self._fetch()
            except ServerError as e:
                if e.status // 100 != 5:
                    raise

                if i == self.max_retries - 1:
                    raise
            else:
                return


[文档]class BucketIterator(_BaseIterator):
    """Iterator for bucket.

    Returns a :class:`SimplifiedBucketInfo <oss2.models.SimplifiedBucketInfo>` instance for each iteration (via next()).

    :param service: :class:`Service <oss2.Service>` instance .
    :param prefix: Bucket name prefix. Only buckets with the prefix specified are listed.
    :param marker: Paging marker. Only lists buckets whose name is after the marker in the lexicographic order.
    :param max_keys: The maximum number of keys to return for `list_objects` . Note that the total entries the iterator returns can be more than that.
    """
    def __init__(self, service, prefix='', marker='', max_keys=100, max_retries=None):
        super(BucketIterator, self).__init__(marker, max_retries)
        self.service = service
        self.prefix = prefix
        self.max_keys = max_keys

    def _fetch(self):
        result = self.service.list_buckets(prefix=self.prefix,
                                           marker=self.next_marker,
                                           max_keys=self.max_keys)
        self.entries = result.buckets

        return result.is_truncated, result.next_marker


[文档]class ObjectIterator(_BaseIterator):
    """Iterator for files in a bucket.

    Returns a :class:`SimplifiedObjectInfo <oss2.models.SimplifiedObjectInfo>` instance for each iteration (via next()).
    When `SimplifiedObjectInfo.is_prefix()` is True, the object is a common prefix (directory, not a file); Otherwise, it is a file.

    :param bucket: :class:`Bucket <oss2.Bucket>` instance.
    :param prefix: The file name prefix.
    :param delimiter: Delimiter for the directory.
    :param marker: Paging marker.
    :param max_keys: The maximum number of keys to return for each `list_objects` call. Note that the total entries that the iterator returns can be more than this value.
    """
    def __init__(self, bucket, prefix='', delimiter='', marker='', max_keys=100, max_retries=None):
        super(ObjectIterator, self).__init__(marker, max_retries)

        self.bucket = bucket
        self.prefix = prefix
        self.delimiter = delimiter
        self.max_keys = max_keys

    def _fetch(self):
        result = self.bucket.list_objects(prefix=self.prefix,
                                          delimiter=self.delimiter,
                                          marker=self.next_marker,
                                          max_keys=self.max_keys)
        self.entries = result.object_list + [SimplifiedObjectInfo(prefix, None, None, None, None, None)
                                             for prefix in result.prefix_list]
        self.entries.sort(key=lambda obj: obj.key)

        return result.is_truncated, result.next_marker


[文档]class MultipartUploadIterator(_BaseIterator):
    """Iterator of ongoing parts in multiparts upload.

    Returns a :class:`MultipartUploadInfo <oss2.models.MultipartUploadInfo>` instance for each iteration.
    When `MultipartUploadInfo.is_prefix()` is True, the instance is a folder. Otherwise it is a file.

    :param bucket: :class:`Bucket <oss2.Bucket>` instance.
    :param prefix: The file key prefix. Only parts of those files will be listed.
    :param delimiter: The directory delimeter.
    :param key_marker: Paging marker.
    :param upload_id_marker: Paging upload ID marker.
    :param max_uploads: Maximum entries for each `list_multipart_uploads` call. Note that the total entries that the iterator returns can be more than this value.
    """
    def __init__(self, bucket,
                 prefix='', delimiter='', key_marker='', upload_id_marker='',
                 max_uploads=1000, max_retries=None):
        super(MultipartUploadIterator, self).__init__(key_marker, max_retries)

        self.bucket = bucket
        self.prefix = prefix
        self.delimiter = delimiter
        self.next_upload_id_marker = upload_id_marker
        self.max_uploads = max_uploads

    def _fetch(self):
        result = self.bucket.list_multipart_uploads(prefix=self.prefix,
                                                    delimiter=self.delimiter,
                                                    key_marker=self.next_marker,
                                                    upload_id_marker=self.next_upload_id_marker,
                                                    max_uploads=self.max_uploads)
        self.entries = result.upload_list + [MultipartUploadInfo(prefix, None, None) for prefix in result.prefix_list]
        self.entries.sort(key=lambda u: u.key)

        self.next_upload_id_marker = result.next_upload_id_marker
        return result.is_truncated, result.next_key_marker


[文档]class ObjectUploadIterator(_BaseIterator):
    """Iterator of ongoing multiparts uploads.

    It returns a :class:`MultipartUploadInfo <oss2.models.MultipartUploadInfo>` instance for each iteration.
    When `MultipartUploadInfo.is_prefix()` is true, it means the common prefix (folder).

    :param bucket: :class:`Bucket <oss2.Bucket>` instance.
    :param key: The object key.
    :param max_uploads: Max entries for each list_multipart_uploads call. Note that the total entries the iterator returns can be more than this value.
    """
    def __init__(self, bucket, key, max_uploads=1000, max_retries=None):
        super(ObjectUploadIterator, self).__init__('', max_retries)
        self.bucket = bucket
        self.key = key
        self.next_upload_id_marker = ''
        self.max_uploads = max_uploads

    def _fetch(self):
        result = self.bucket.list_multipart_uploads(prefix=self.key,
                                                    key_marker=self.next_marker,
                                                    upload_id_marker=self.next_upload_id_marker,
                                                    max_uploads=self.max_uploads)

        self.entries = [u for u in result.upload_list if u.key == self.key]
        self.next_upload_id_marker = result.next_upload_id_marker

        if not result.is_truncated or not self.entries:
            return False, result.next_key_marker

        if result.next_key_marker > self.key:
            return False, result.next_key_marker

        return result.is_truncated, result.next_key_marker


[文档]class PartIterator(_BaseIterator):
    """Iterator of uploaded parts of a specific multipart upload.

    It returns a :class:`PartInfo <oss2.models.PartInfo>` instance for each iteration.

    :param bucket: :class:`Bucket <oss2.Bucket>` instance.
    :param key: Object key.
    :param upload_id: Upload ID.
    :param marker: Paging marker.
    :param max_parts: The max parts for each `list_parts` call. Note that the total entries the iterator returns can be more than this value.
    """
    def __init__(self, bucket, key, upload_id,
                 marker='0', max_parts=1000, max_retries=None):
        super(PartIterator, self).__init__(marker, max_retries)

        self.bucket = bucket
        self.key = key
        self.upload_id = upload_id
        self.max_parts = max_parts

    def _fetch(self):
        result = self.bucket.list_parts(self.key, self.upload_id,
                                        marker=self.next_marker,
                                        max_parts=self.max_parts)
        self.entries = result.parts

        return result.is_truncated, result.next_marker


[文档]class LiveChannelIterator(_BaseIterator):
    """Iterator of Live Channel in a bucket.

    It returns a :class:`LiveChannelInfo <oss2.models.LiveChannelInfo>` instance for each iteration.

    :param bucket: :class:`Bucket <oss2.Bucket>` instance.
    :param prefix: Live Channel prefix.
    :param marker: Paging marker.
    :param max_keys: Max entries for each `list_live_channel` call. Note that the total entries that the iterator returns can be more than this value.
    """
    def __init__(self, bucket, prefix='', marker='', max_keys=100, max_retries=None):
        super(LiveChannelIterator, self).__init__(marker, max_retries)

        self.bucket = bucket
        self.prefix = prefix
        self.max_keys = max_keys

    def _fetch(self):
        result = self.bucket.list_live_channel(prefix=self.prefix,
                                               marker=self.next_marker,
                                               max_keys=self.max_keys)
        self.entries = result.channels

        return result.is_truncated, result.next_marker