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

Введение:
В этой статье мы обсудим улучшение взаимодействия с пользователем с помощью Python. При этом наиболее важным пользовательским опытом, который мы можем предоставить, является визуальная подсказка или уведомление пользователя о ходе выполнения задачи или действия.
На мой взгляд, загрузка и скачивание файлов через HTTP являются наиболее распространенными вариантами использования, с которыми столкнется каждый разработчик Python. Если вы еще этого не сделали, сохраните страницу. Вы можете столкнуться с одним из таких случаев когда-нибудь. 🙂
Значение этой статьи заключается в отображении индикатора выполнения с помощью tqdm, и мы сосредоточимся на tqdm, а не на загрузке или выгрузке файлов.
Забрать:
В конце этой статьи вы должны быть в состоянии
- Отображение индикатора выполнения с помощью tqdm для загрузки файлов
- Отображение индикатора выполнения с помощью tqdm для загрузки файлов
- Иметь базовое представление о библиотеке 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://tqdm.github.io/
- https://stackoverflow.com/questions/15644964/python-progress-bar-and-downloads
Первоначально опубликовано на https://dock2learn.com.
Дополнительные материалы на plainenglish.io