python的rich包

提供多样式的显示


python -m rich.progress


[17:27:42] Text may be printed while the progress bars are rendering.                             progress.py:1095 [17:27:45] ┌────────────────────────────────────────────────────────────────────────────────────┐ progress.py:1095
            In fact, any renderable will work                                                  
           └────────────────────────────────────────────────────────────────────────────────────┘
[17:27:46] Such as tables...                                                                      progress.py:1095 [17:27:47] ┌─────┬─────┬─────┐                                                                    progress.py:1095
            foo  bar  baz 
           ├─────┼─────┼─────┤
            1    2    3   
           └─────┴─────┴─────┘
[17:27:50] Pretty printed structures...                                                           progress.py:1095 [17:27:51] {'type': 'example', 'text': 'Pretty printed'}                                          progress.py:1095 [17:27:53] Syntax...                                                                              progress.py:1095
              1 def loop_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]:                   progress.py:1095
              2     """Iterate and generate a tuple with a flag for last value."""
              3     iter_values = iter(values)
              4     try:
              5         previous_value = next(iter_values)
              6     except StopIteration:
              7         return
              8     for value in iter_values:
              9         yield False, previous_value
             10         previous_value = value
             11     yield True, previous_value
[17:27:54] ─────────────────────────────────── Give it a try! ─────────────────────────────────── progress.py:1095

进度条

from rich.progress import track
import time 

def do_step(step):
    time.sleep(step)

for step in track(range(100)):
    do_step(step)

# python demo.py
# Working... ---------- -----------------------------  26% 0:01:14

多个任务进度条


from concurrent.futures import ThreadPoolExecutor
from functools import partial
import os.path
import sys
from typing import Iterable
from urllib.request import urlopen

from rich.progress import (
    BarColumn,
    DownloadColumn,
    TextColumn,
    TransferSpeedColumn,
    TimeRemainingColumn,
    Progress,
    TaskID,
)


progress = Progress(
    TextColumn("[bold blue]{task.fields[filename]}", justify="right"),
    BarColumn(bar_width=None),
    "[progress.percentage]{task.percentage:>3.1f}%",
    "•",
    DownloadColumn(),
    "•",
    TransferSpeedColumn(),
    "•",
    TimeRemainingColumn(),
)


def copy_url(task_id: TaskID, url: str, path: str) -> None:
    """Copy data from a url to a local file."""
    response = urlopen(url)
    # This will break if the response doesn't contain content length
    progress.update(task_id, total=int(response.info()["Content-length"]))
    with open(path, "wb") as dest_file:
        progress.start_task(task_id)
        for data in iter(partial(response.read, 32768), b""):
            dest_file.write(data)
            progress.update(task_id, advance=len(data))


def download(urls: Iterable[str], dest_dir: str):
    """Download multuple files to the given directory."""
    with progress:
        with ThreadPoolExecutor(max_workers=4) as pool:
            for url in urls:
                filename = url.split("/")[-1]
                dest_path = os.path.join(dest_dir, filename)
                task_id = progress.add_task("download", filename=filename, start=False)
                pool.submit(copy_url, task_id, url, dest_path)


if __name__ == "__main__":
    # Try with https://releases.ubuntu.com/20.04/ubuntu-20.04.1-desktop-amd64.iso
    if sys.argv[1:]:
        download(sys.argv[1:], "./")
    else:
        print("Usage:\n\tpython downloader.py URL1 URL2 URL3 (etc)")

Rich

Buy me a 肥仔水!