進捗表示

Richは、長時間実行されるタスク(ファイルのコピーなど)の進捗状況に関する継続的に更新される情報を表示できます。表示される情報は設定可能で、デフォルトでは「タスク」の説明、プログレスバー、完了率、残り時間の推定が表示されます。

Richの進捗表示は、それぞれバーと進捗情報を持つ複数のタスクをサポートしています。スレッドまたはプロセスで作業が行われている並行タスクの追跡に使用できます。

進捗表示の外観を確認するには、コマンドラインから次のコマンドを実行してみてください。

python -m rich.progress

注記

ProgressはJupyter Notebookでも動作しますが、自動更新は無効化されている点に注意してください。refresh()を明示的に呼び出すか、update()を呼び出す際にrefresh=Trueを設定する必要があります。または、各ループで自動的に更新を行うtrack()関数を使用してください。

基本的な使用方法

基本的な使用方法としては、リストや範囲オブジェクトなどのシーケンスと、作業中のジョブのオプションの説明を受け入れるtrack()関数を呼び出します。track関数はシーケンスから値を生成し、各反復で進捗情報を更新します。例を以下に示します。

import time
from rich.progress import track

for i in track(range(20), description="Processing..."):
    time.sleep(1)  # Simulate work being done

高度な使用方法

表示に複数のタスクが必要な場合、または進捗表示の列を設定する必要がある場合は、Progressクラスを直接操作できます。Progressオブジェクトを作成したら、add_task()でタスクを追加し、update()で進捗を更新します。

Progressクラスは、コンテキストマネージャーとして使用することを目的としており、進捗表示の開始と停止を自動的に行います。

簡単な例を以下に示します。

import time

from rich.progress import Progress

with Progress() as progress:

    task1 = progress.add_task("[red]Downloading...", total=1000)
    task2 = progress.add_task("[green]Processing...", total=1000)
    task3 = progress.add_task("[cyan]Cooking...", total=1000)

    while not progress.finished:
        progress.update(task1, advance=0.5)
        progress.update(task2, advance=0.3)
        progress.update(task3, advance=0.9)
        time.sleep(0.02)

タスクに関連付けられたtotal値は、進捗が100%に達するまでに完了する必要があるステップの数です。このコンテキストでのステップとは、アプリケーションにとって意味のあるものなら何でも構いません。ファイルの読み取りバイト数、処理された画像の数などです。

タスクの更新

add_task()を呼び出すと、タスクIDが返されます。このIDを使用して、作業が完了した場合、または情報が変更された場合にupdate()を呼び出します。通常、ステップが完了するたびにcompletedを更新する必要があります。completedを直接更新するか、現在のcompleted値に追加するadvanceを設定することでこれを行うことができます。

update()メソッドは、タスクにも関連付けられたキーワード引数を収集します。これを使用して、進捗表示にレンダリングする追加情報を提供します。追加の引数はtask.fieldsに格納され、列クラスで参照できます。

タスクの非表示

タスクのvisible値を更新することで、タスクの表示/非表示を切り替えることができます。タスクはデフォルトで表示されますが、visible=Falseadd_task()を呼び出すことによって非表示のタスクを追加することもできます。

一時的な進捗

通常、進捗コンテキストマネージャーを終了する場合(またはstop()を呼び出す場合)、最後に更新された表示が、カーソルが次の行にある状態でターミナルに残ります。Progressコンストラクタでtransient=Trueを設定することで、終了時に進捗表示を消去することもできます。例を以下に示します。

with Progress(transient=True) as progress:
    task = progress.add_task("Working", total=100)
    do_work(task)

一時的な進捗表示は、タスクが完了したときにターミナルの出力を最小限に抑えたい場合に役立ちます。

不定の進捗

タスクを追加すると、自動的に開始され、0%のプログレスバーが表示され、残り時間は現在時刻から計算されます。サーバーからの応答を待機したり、ディレクトリ内のファイルをカウントしたりするなど、進捗の更新を開始するまでに長い遅延がある場合は、うまく機能しない可能性があります(例)。このような場合は、start=Falseまたはtotal=Noneadd_task()を呼び出すことができます。これにより、ユーザーに何かが動作中であることを知らせる脈打つアニメーションが表示されます。これは、不定プログレスバーと呼ばれます。ステップ数がわかったら、start_task()を呼び出すと0%のプログレスバーが表示され、その後は通常どおりupdate()を呼び出します。

自動更新

デフォルトでは、進捗情報は1秒間に10回更新されます。Progressコンストラクタのrefresh_per_second引数で更新頻度を設定できます。更新頻度がそれほど高くないことがわかっている場合は、これを10よりも低い値に設定する必要があります。

更新頻度が非常に低い場合は、自動更新を完全に無効にすることもできます。これを行うには、コンストラクタでauto_refresh=Falseを設定します。自動更新を無効にした場合は、タスクを更新した後にrefresh()を手動で呼び出す必要があります。

展開

プログレスバーは、タスク情報を表示するために必要なターミナルの幅のみを使用します。Progressコンストラクタでexpand引数を設定すると、Richは進捗表示をすべての利用可能な幅に拡大します。

Progressコンストラクタの位置引数を使用して、進捗表示の列をカスタマイズできます。列は、フォーマット文字列またはProgressColumnオブジェクトとして指定します。

フォーマット文字列は、Taskインスタンスである単一の値「task」でレンダリングされます。たとえば、"{task.description}"は列にタスクの説明を表示し、"{task.completed} of {task.total}"は完了したステップの総数と完了したステップ数を表示します。キーワード引数を使用して~rich.progress.Progress.updateに渡される追加フィールドはtask.fieldsに格納されます。次の構文を使用して、フォーマット文字列に追加できます。"extra info: {task.fields[extra]}"

デフォルトの列は次のものと同等です。

progress = Progress(
    TextColumn("[progress.description]{task.description}"),
    BarColumn(),
    TaskProgressColumn(),
    TimeRemainingColumn(),
)

デフォルトに加えて独自の列を持つProgressを作成するには、get_default_columns()を使用します。

progress = Progress(
    SpinnerColumn(),
    *Progress.get_default_columns(),
    TimeElapsedColumn(),
)

次の列オブジェクトを使用できます。

  • BarColumn バーを表示します。

  • TextColumn テキストを表示します。

  • TimeElapsedColumn 経過時間を表示します。

  • TimeRemainingColumn 残り時間の推定値を表示します。

  • MofNCompleteColumn 完了状況を "{task.completed}/{task.total}" として表示します(完了数と総数が整数の場合に最適です)。

  • FileSizeColumn ファイルサイズとして進捗状況を表示します(ステップがバイト単位であることを前提としています)。

  • TotalFileSizeColumn ファイルの総サイズを表示します(ステップがバイト単位であることを前提としています)。

  • DownloadColumn ダウンロードの進捗状況を表示します(ステップがバイト単位であることを前提としています)。

  • TransferSpeedColumn 転送速度を表示します(ステップがバイト単位であることを前提としています)。

  • SpinnerColumn 「スピナー」アニメーションを表示します。

  • RenderableColumn カラムに任意のRichレンダラブルを表示します。

独自の列を実装するには、ProgressColumnクラスを拡張し、他の列と同様に使用します。

テーブル列

Richは、Progressインスタンス内のタスクに対してTableを構築します。このタスクテーブルの列の作成方法をカスタマイズするには、Columnコンストラクタのtable_column引数を指定します。これはColumnインスタンスである必要があります。

次の例は、説明がターミナル幅の3分の1を占め、バーが残りの3分の2を占めるプログレスバーを示しています。

from time import sleep

from rich.table import Column
from rich.progress import Progress, BarColumn, TextColumn

text_column = TextColumn("{task.description}", table_column=Column(ratio=1))
bar_column = BarColumn(bar_width=None, table_column=Column(ratio=2))
progress = Progress(text_column, bar_column, expand=True)

with progress:
    for n in progress.track(range(100)):
        progress.print(n)
        sleep(0.1)

stdout/stderrのリダイレクト

進捗表示の視覚的な表示を壊さないように、Richはstdoutstderrをリダイレクトします。これにより、組み込みのprint文を使用できます。この機能はデフォルトで有効になっていますが、redirect_stdoutまたはredirect_stderrFalseに設定することで無効にできます。

カスタマイズ

Progressクラスが、進捗表示に関して必要なものを正確に提供しない場合は、get_renderablesメソッドをオーバーライドできます。たとえば、次のクラスは、進捗表示の周りにPanelをレンダリングします。

from rich.panel import Panel
from rich.progress import Progress

class MyProgress(Progress):
    def get_renderables(self):
        yield Panel(self.make_tasks_table(self.tasks))

ファイルからの読み込み

Richは、ファイルを読み取るときにプログレスバーを生成する簡単な方法を提供します。open()を呼び出すと、読み取り中にプログレスバーを表示するコンテキストマネージャーが返されます。これは、読み取りを行うコードを簡単に変更できない場合に特に役立ちます。

次の例は、JSONファイルを読み取るときにどのように進捗状況を表示するかを示しています。

import json
import rich.progress

with rich.progress.open("data.json", "rb") as file:
    data = json.load(file)
print(data)

ファイルオブジェクトが既に存在する場合は、wrap_file()を呼び出すことができます。これは、プログレスバーを表示するようにファイルをラップするコンテキストマネージャーを返します。この関数を使用する場合は、読み取るバイト数または文字数を設定する必要があります。

これはインターネットからURLを読み取る例です。

from time import sleep
from urllib.request import urlopen

from rich.progress import wrap_file

response = urlopen("https://www.textualize.io")
size = int(response.headers["Content-Length"])

with wrap_file(response, size) as file:
    for line in file:
        print(line.decode("utf-8"), end="")
        sleep(0.1)

複数のファイルから読み取る必要がある場合は、open()またはwrap_file()を使用して、既存のProgressインスタンスにファイルの進捗状況を追加できます。

cpコマンドの最小限のクローンであるファイルコピー中にプログレスバーを表示するcp_progress.py <https://github.com/willmcgugan/rich/blob/master/examples/cp_progress.py>を参照してください。

複数のProgress

単一のProgressインスタンスでは、タスクごとに異なる列を持つことはできません。ただし、ライブ表示には、任意の数のProgressインスタンスを含めることができます。複数のProgressインスタンスの使用例については、live_progress.pydynamic_progress.pyを参照してください。

プログレス表示の現実的なアプリケーションについては、downloader.pyを参照してください。このスクリプトは、プログレスバー、転送速度、ファイルサイズを使用して、複数のファイルを同時にダウンロードできます。