Показать индикатор выполнения для загрузки и скачивания файлов

Введение:

В этой статье мы обсудим улучшение взаимодействия с пользователем с помощью Python. При этом наиболее важным пользовательским опытом, который мы можем предоставить, является визуальная подсказка или уведомление пользователя о ходе выполнения задачи или действия.

На мой взгляд, загрузка и скачивание файлов через HTTP являются наиболее распространенными вариантами использования, с которыми столкнется каждый разработчик Python. Если вы еще этого не сделали, сохраните страницу. Вы можете столкнуться с одним из таких случаев когда-нибудь. 🙂

Значение этой статьи заключается в отображении индикатора выполнения с помощью tqdm, и мы сосредоточимся на tqdm, а не на загрузке или выгрузке файлов.

Забрать:

В конце этой статьи вы должны быть в состоянии

  1. Отображение индикатора выполнения с помощью tqdm для загрузки файлов
  2. Отображение индикатора выполнения с помощью tqdm для загрузки файлов
  3. Иметь базовое представление о библиотеке tqdm

тквдм:

tqdm означает "прогресс" по-арабски (taqadum, تقدّم) и является аббревиатурой от "я так тебя люблю" по-испански (te quiero demasiado). - Из документов

Использование tqdm для отображения индикатора выполнения загрузки:

Допустим, у нас есть вариант использования загрузки нескольких файлов на сервер через http. Конечно, мы будем использовать наш модуль requests для загрузки файлов за нас. Мы также будем использовать ThreadPoolExecutor для имитации параллелизма.

Синтаксис:

Это синтаксис для инициализации tqdm и атрибутов, которые можно установить.

def __init__(self, iterable=None, desc=None, total=None, leave=True, file=None,
                 ncols=None, mininterval=0.1, maxinterval=10.0, miniters=None,
                 ascii=None, disable=False, unit='it', unit_scale=False,
                 dynamic_ncols=False, smoothing=0.3, bar_format=None, initial=0,
                 position=None, postfix=None, unit_divisor=1000, write_bytes=None,
                 lock_args=None, nrows=None, colour=None, delay=0, gui=False,
                 **kwargs):
        """
        Parameters
        ----------
        iterable  : iterable, optional
            Iterable to decorate with a progressbar.
            Leave blank to manually manage the updates.
        desc  : str, optional
            Prefix for the progressbar.
        total  : int or float, optional
            The number of expected iterations. If unspecified,
            len(iterable) is used if possible. If float("inf") or as a last
            resort, only basic progress statistics are displayed
            (no ETA, no progressbar).
            If `gui` is True and this parameter needs subsequent updating,
            specify an initial arbitrary large positive number,
            e.g. 9e9.
        leave  : bool, optional
            If [default: True], keeps all traces of the progressbar
            upon termination of iteration.
            If `None`, will leave only if `position` is `0`.
        file  : `io.TextIOWrapper` or `io.StringIO`, optional
            Specifies where to output the progress messages
            (default: sys.stderr). Uses `file.write(str)` and `file.flush()`
            methods.  For encoding, see `write_bytes`.
        ncols  : int, optional
            The width of the entire output message. If specified,
            dynamically resizes the progressbar to stay within this bound.
            If unspecified, attempts to use environment width. The
            fallback is a meter width of 10 and no limit for the counter and
            statistics. If 0, will not print any meter (only stats).
        mininterval  : float, optional
            Minimum progress display update interval [default: 0.1] seconds.
        maxinterval  : float, optional
            Maximum progress display update interval [default: 10] seconds.
            Automatically adjusts `miniters` to correspond to `mininterval`
            after long display update lag. Only works if `dynamic_miniters`
            or monitor thread is enabled.
        miniters  : int or float, optional
            Minimum progress display update interval, in iterations.
            If 0 and `dynamic_miniters`, will automatically adjust to equal
            `mininterval` (more CPU efficient, good for tight loops).
            If > 0, will skip display of specified number of iterations.
            Tweak this and `mininterval` to get very efficient loops.
            If your progress is erratic with both fast and slow iterations
            (network, skipping items, etc) you should set miniters=1.
        ascii  : bool or str, optional
            If unspecified or False, use unicode (smooth blocks) to fill
            the meter. The fallback is to use ASCII characters " 123456789#".
        disable  : bool, optional
            Whether to disable the entire progressbar wrapper
            [default: False]. If set to None, disable on non-TTY.
        unit  : str, optional
            String that will be used to define the unit of each iteration
            [default: it].
        unit_scale  : bool or int or float, optional
            If 1 or True, the number of iterations will be reduced/scaled
            automatically and a metric prefix following the
            International System of Units standard will be added
            (kilo, mega, etc.) [default: False]. If any other non-zero
            number, will scale `total` and `n`.
        dynamic_ncols  : bool, optional
            If set, constantly alters `ncols` and `nrows` to the
            environment (allowing for window resizes) [default: False].
        smoothing  : float, optional
            Exponential moving average smoothing factor for speed estimates
            (ignored in GUI mode). Ranges from 0 (average speed) to 1
            (current/instantaneous speed) [default: 0.3].
        bar_format  : str, optional
            Specify a custom bar string formatting. May impact performance.
            [default: '{l_bar}{bar}{r_bar}'], where
            l_bar='{desc}: {percentage:3.0f}%|' and
            r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, '
              '{rate_fmt}{postfix}]'
            Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt,
              percentage, elapsed, elapsed_s, ncols, nrows, desc, unit,
              rate, rate_fmt, rate_noinv, rate_noinv_fmt,
              rate_inv, rate_inv_fmt, postfix, unit_divisor,
              remaining, remaining_s, eta.
            Note that a trailing ": " is automatically removed after {desc}
            if the latter is empty.
        initial  : int or float, optional
            The initial counter value. Useful when restarting a progress
            bar [default: 0]. If using float, consider specifying `{n:.3f}`
            or similar in `bar_format`, or specifying `unit_scale`.
        position  : int, optional
            Specify the line offset to print this bar (starting from 0)
            Automatic if unspecified.
            Useful to manage multiple bars at once (eg, from threads).
        postfix  : dict or *, optional
            Specify additional stats to display at the end of the bar.
            Calls `set_postfix(**postfix)` if possible (dict).
        unit_divisor  : float, optional
            [default: 1000], ignored unless `unit_scale` is True.
        write_bytes  : bool, optional
            If (default: None) and `file` is unspecified,
            bytes will be written in Python 2. If `True` will also write
            bytes. In all other cases will default to unicode.
        lock_args  : tuple, optional
            Passed to `refresh` for intermediate output
            (initialisation, iterating, and updating).
        nrows  : int, optional
            The screen height. If specified, hides nested bars outside this
            bound. If unspecified, attempts to use environment height.
            The fallback is 20.
        colour  : str, optional
            Bar colour (e.g. 'green', '#00ff00').
        delay  : float, optional
            Don't display until [default: 0] seconds have elapsed.
        gui  : bool, optional
            WARNING: internal parameter - do not use.
            Use tqdm.gui.tqdm(...) instead. If set, will attempt to use
            matplotlib animations for a graphical output [default: False].

        Returns
        -------
        out  : decorated iterator.

Код:

import requests
from tqdm import tqdm
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import as_completed
import os, time


def upload():
    """
    A function to upload to a http server using requests
    url: https://httpbin.org/post -- A test url
    """

    file_path = '/home/<your>/<path>/'

    # list all the files from a given path
    files_to_upload = os.listdir(file_path)

    # tqdm is used as a context manager
    with tqdm(total=len(files_to_upload), desc="Uploading", initial=0, unit_scale=True, colour='green') as pbar:
        with ThreadPoolExecutor(max_workers=20) as executor:
            for file_name in files_to_upload:
                with open(os.path.join(file_path, file_name), 'rb') as f:
                    files = {'file': (file_name, f.read())}
                    futures = executor.submit(requests.post,
                                              url='https://httpbin.org/post',
                                              files=files)

                    if as_completed(futures):
                        pbar.update(1)
                        time.sleep(0.02)
    return "complete"

upload()

Индикатор выполнения выглядит примерно так, как показано ниже. Конечно, вы можете выбрать интересующий вас цвет, чтобы заполнить полосу. Я выбрал зеленый, так как он дает пользователю ощущение удовлетворения, когда полоса заполняется. 😉

Теперь, когда у нас есть индикатор выполнения, работающий для загрузок, нам нужно реализовать его и для загрузок. Однако на этот раз мы будем использовать wrapattr.

Использование tqdm wrapattr для отображения индикатора загрузки:

Синтаксис и использование:

@classmethod
    @contextmanager
    def wrapattr(cls, stream, method, total=None, bytes=True, **tqdm_kwargs):
        """
        stream  : file-like object.
        method  : str, "read" or "write". The result of `read()` and
            the first argument of `write()` should have a `len()`.
        >>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj:
        ...     while True:
        ...         chunk = fobj.read(chunk_size)
        ...         if not chunk:
        ...             break
        """

Теперь мы будем использовать wrapattr для отображения индикатора загрузки файлов с помощью requests.

import requests
from tqdm import tqdm
from concurrent.futures import ThreadPoolExecutor
import os, time
import shutil

def initiate_download(self):
    
    download_path = "<your download path>"
    
    # list of urls to download
    url_lst = "<your list of urls to download>"
    
    # use threads to download multiple files for concurrency
    with ThreadPoolExecutor(max_workers=20) as executor:
        result_lst = list()
        for url in url_lst:
            future = executor.submit(download, url)
            result_lst.append(future)

        for res in result_lst:
            # do something with your result
            pass

def download():

    response = requests.get(url='<your http url>', stream=True)
    file_size = int(zip_resp.headers.get('content-length'))

    with open("<your file path on your system>", "wb") as f:
        with tqdm.wrapattr(response.raw, "read", total=file_size, desc="Downloading", colour='green') as r_raw:
            shutil.copyfileobj(r_raw, f)

    return "Success"


initiate_download()

Что мне лично нравится в wrapattr, так это то, что вы можете использовать его для чтения или записи атрибута, а tqdm позаботится обо всем. Вам не нужно ни вручную обновлять индикатор выполнения, ни беспокоиться о content-length.

В отличие от подхода, который мы обсуждали для загрузки, это намного проще, поскольку позволяет избежать хлопот, связанных с ручным обновлением индикатора выполнения.

Я обсудил 2 разных способа обновления индикатора выполнения с помощью tqdm.

wrapattr очень полезен, если вы используете shutil для записи файлов в файловую систему, как мы будем писать в raw format.

Резюме:

  • tqdm — отличная библиотека для отображения индикаторов выполнения ваших загрузок и загрузок.
  • Он отлично работает с модулем requests.
  • tqdm поддерживает различные цвета. Пожалуйста, ознакомьтесь с их документацией, чтобы узнать о них.
  • Поддерживает контекстный менеджер, что весьма полезно.
  • wrapattr автоматически выполняет обратный вызов обновления. Хорошо работает с shutil

Использованная литература:

Первоначально опубликовано на https://dock2learn.com.

Дополнительные материалы на plainenglish.io