|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- # -*- coding: utf-8 -*-
- # MinIO Python Library for Amazon S3 Compatible Cloud Storage,
- # (C) 2018 MinIO, Inc.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
-
- """
- This module implements a progress printer while communicating with MinIO server
-
- :copyright: (c) 2018 by MinIO, Inc.
- :license: Apache 2.0, see LICENSE for more details.
-
- """
-
- import sys
- import time
- from queue import Empty, Queue
- from threading import Thread
-
- _BAR_SIZE = 20
- _KILOBYTE = 1024
- _FINISHED_BAR = '#'
- _REMAINING_BAR = '-'
-
- _UNKNOWN_SIZE = '?'
- _STR_MEGABYTE = ' MB'
-
- _HOURS_OF_ELAPSED = '%d:%02d:%02d'
- _MINUTES_OF_ELAPSED = '%02d:%02d'
-
- _RATE_FORMAT = '%5.2f'
- _PERCENTAGE_FORMAT = '%3d%%'
- _HUMANINZED_FORMAT = '%0.2f'
-
- _DISPLAY_FORMAT = '|%s| %s/%s %s [elapsed: %s left: %s, %s MB/sec]'
-
- _REFRESH_CHAR = '\r'
-
-
- class Progress(Thread):
- """
- Constructs a :class:`Progress` object.
- :param interval: Sets the time interval to be displayed on the screen.
- :param stdout: Sets the standard output
-
- :return: :class:`Progress` object
- """
-
- def __init__(self, interval=1, stdout=sys.stdout):
- Thread.__init__(self)
- self.daemon = True
- self.total_length = 0
- self.interval = interval
- self.object_name = None
-
- self.last_printed_len = 0
- self.current_size = 0
-
- self.display_queue = Queue()
- self.initial_time = time.time()
- self.stdout = stdout
- self.start()
-
- def set_meta(self, total_length, object_name):
- """
- Metadata settings for the object. This method called before uploading
- object
- :param total_length: Total length of object.
- :param object_name: Object name to be showed.
- """
- self.total_length = total_length
- self.object_name = object_name
- self.prefix = self.object_name + ': ' if self.object_name else ''
-
- def run(self):
- displayed_time = 0
- while True:
- try:
- # display every interval secs
- task = self.display_queue.get(timeout=self.interval)
- except Empty:
- elapsed_time = time.time() - self.initial_time
- if elapsed_time > displayed_time:
- displayed_time = elapsed_time
- self.print_status(current_size=self.current_size,
- total_length=self.total_length,
- displayed_time=displayed_time,
- prefix=self.prefix)
- if self.current_size == self.total_length:
- # once we have done uploading everything return
- self.done_progress()
- return
- continue
-
- current_size, total_length = task
- displayed_time = time.time() - self.initial_time
- self.print_status(current_size=current_size,
- total_length=total_length,
- displayed_time=displayed_time,
- prefix=self.prefix)
- self.display_queue.task_done()
- if current_size == total_length:
- # once we have done uploading everything return
- self.done_progress()
- return
-
- def update(self, size):
- """
- Update object size to be showed. This method called while uploading
- :param size: Object size to be showed. The object size should be in
- bytes.
- """
- if not isinstance(size, int):
- raise ValueError('{} type can not be displayed. '
- 'Please change it to Int.'.format(type(size)))
-
- self.current_size += size
- self.display_queue.put((self.current_size, self.total_length))
-
- def done_progress(self):
- self.total_length = 0
- self.object_name = None
- self.last_printed_len = 0
- self.current_size = 0
-
- def print_status(self, current_size, total_length, displayed_time, prefix):
- if total_length == 0:
- return
- formatted_str = prefix + format_string(
- current_size, total_length, displayed_time)
- self.stdout.write(_REFRESH_CHAR + formatted_str + ' ' *
- max(self.last_printed_len - len(formatted_str), 0))
- self.stdout.flush()
- self.last_printed_len = len(formatted_str)
-
-
- def seconds_to_time(seconds):
- """
- Consistent time format to be displayed on the elapsed time in screen.
- :param seconds: seconds
- """
- minutes, seconds = divmod(int(seconds), 60)
- hours, m = divmod(minutes, 60)
- if hours:
- return _HOURS_OF_ELAPSED % (hours, m, seconds)
- else:
- return _MINUTES_OF_ELAPSED % (m, seconds)
-
-
- def format_string(current_size, total_length, elapsed_time):
- """
- Consistent format to be displayed on the screen.
- :param current_size: Number of finished object size
- :param total_length: Total object size
- :param elapsed_time: number of seconds passed since start
- """
-
- n_to_mb = current_size / _KILOBYTE / _KILOBYTE
- elapsed_str = seconds_to_time(elapsed_time)
-
- rate = _RATE_FORMAT % (
- n_to_mb / elapsed_time) if elapsed_time else _UNKNOWN_SIZE
- frac = float(current_size) / total_length
- bar_length = int(frac * _BAR_SIZE)
- bar = (_FINISHED_BAR * bar_length +
- _REMAINING_BAR * (_BAR_SIZE - bar_length))
- percentage = _PERCENTAGE_FORMAT % (frac * 100)
- left_str = (
- seconds_to_time(
- elapsed_time / current_size * (total_length - current_size))
- if current_size else _UNKNOWN_SIZE)
-
- humanized_total = _HUMANINZED_FORMAT % (
- total_length / _KILOBYTE / _KILOBYTE) + _STR_MEGABYTE
- humanized_n = _HUMANINZED_FORMAT % n_to_mb + _STR_MEGABYTE
-
- return _DISPLAY_FORMAT % (bar, humanized_n, humanized_total, percentage,
- elapsed_str, left_str, rate)
|