← 中文资源

简体中文版本

Rich 动态表格实时展示

用 Rich 的 Live 模式渲染动态 CLI 表格:后台任务推进时原地刷新行数据,状态着色,结束输出干净总结。

阅读英文原文

示例说明

进度类 CLI 输出的痛点是重绘闪烁:print 每次追加新行,屏幕越滚越长。Live 上下文把同一块终端区域变成原地刷新的画布——表格数据变了就 update,刷新频率限速防止撕裂。Rich 的样式对象按状态着色,肉眼即可分辨进行中与已完成。

技术要点

  • Live 上下文圈定原地刷新区域
  • refresh_per_second 限速防终端撕裂
  • Text 样式按状态动态着色

代码解读

build_table 每次根据当前数据重建表格,状态到样式的映射集中定义;deploy 循环里模拟任务推进——运行中的行累计耗时,超过阈值转为完成,随后 live.update 重绘。退出 Live 后控制台恢复正常输出模式,打印总结行。

使用建议

行数超过终端高度时改用 Rich 的滚动表格或分页。刷新率四赫兹够用,更高无感且费 CPU。结构化结果仍要写文件供脚本消费。

代码示例

import asyncio
import time

from rich.console import Console
from rich.live import Live
from rich.table import Table
from rich.text import Text

console = Console()


def build_table(rows: list[dict]) -> Table:
    table = Table(title='Deployment Progress')
    table.add_column('Service')
    table.add_column('Status')
    table.add_column('Duration', justify='right')

    status_style = {
        'pending': 'dim',
        'running': 'yellow',
        'done': 'green',
        'failed': 'red',
    }
    for row in rows:
        style = status_style.get(row['status'], 'white')
        table.add_row(
            row['name'],
            Text(row['status'], style=style),
            f"{row['elapsed']:.1f}s",
        )
    return table


async def deploy(rows: list[dict]) -> None:
    with Live(build_table(rows), console=console, refresh_per_second=4) as live:
        pending = [r for r in rows if r['status'] == 'pending']
        while pending:
            await asyncio.sleep(0.4)
            for row in rows:
                if row['status'] == 'running':
                    row['elapsed'] += 0.4
                    if row['elapsed'] >= 1.2:
                        row['status'] = 'done'
            live.update(build_table(rows))
            pending = [r for r in rows if r['status'] != 'done']


services = [
    {'name': 'api-gateway', 'status': 'running', 'elapsed': 0.0},
    {'name': 'billing', 'status': 'pending', 'elapsed': 0.0},
    {'name': 'search', 'status': 'pending', 'elapsed': 0.0},
]
services[1]['status'] = 'running'
services[2]['status'] = 'running'

asyncio.run(deploy(services))
console.print('deployment complete')