使用 rich 终端#

颜色系统#

终端写入颜色有几种“标准”,但并非所有标准都被普遍支持。Rich会自动检测合适的颜色系统,或者你可以通过为 :class:~rich.console.Console 构造函数提供 color_system 参数来手动设置它。

你可以将 color_system 设置为以下值之一:

  • None:完全禁用颜色。

  • "auto":将自动检测颜色系统。

  • "standard":可以显示8种颜色,包括正常和亮色变化,总共16种颜色。

  • "256":可以显示来自”standard”的16种颜色加上一个固定的240种颜色调色板。

  • "truecolor":可以显示1670万种颜色,这很可能是你的显示器能显示的所有颜色。

  • "windows":在传统的Windows终端中可以显示8种颜色。新的Windows终端可以显示”truecolor”。

警告

在设置颜色系统时要小心,如果你设置的颜色系统高于你的终端支持的级别,你的文本可能无法阅读。

打印#

要向终端写入富文本内容,请使用 print()方法。Rich会通过对象的 __str__ 方法将其转换为字符串,并执行一些简单的语法高亮。它还会美观地打印任何容器,如字典和列表。如果你打印一个字符串,它将渲染 console_markup。以下是一些示例:

from rich.console import Console
console = Console()

console.print([1, 2, 3])
console.print("[blue underline]看起来像一个链接")
# console.print(locals())
console.print("FOO", style="white on blue")
[1, 2, 3]
看起来像一个链接
FOO

你还可以使用 print() 来渲染支持Console Protocol 的对象,包括Rich的内置对象,如 TextTableSyntax,以及其他自定义对象。

记录日志#

~rich.console.Console.log方法提供了与print相同的功能,但增加了一些对正在运行的应用程序进行调试有用的功能。日志记录在左侧的一列中写入当前时间,并在右侧的一列中写入调用该方法的文件和行。下面是一个示例:

from rich.console import Console

console = Console()
console.log("这是一条日志信息")
[07:08:26] 这是一条日志信息                                                                         2188820476.py:4

打印 JSON#

print_json()

console.print_json('[false, true, null, "foo"]')
[
  false,
  true,
  null,
  "foo"
]
from rich.json import JSON

console.log(JSON('["foo", "bar"]'))
           [                                                                                        4213963421.py:3
             "foo",                                                                                                
             "bar"                                                                                                 
           ]                                                                                                       

低级别输出#

除了 print()log() 方法外,Rich 还提供 ~rich.console.Console.out方法,它提供了一种更低级别的方式向终端写入内容。out() 方法将所有位置参数转换为字符串,并且不会进行美观打印、自动换行或应用标记到输出,但可以应用基本样式,并且可以选择性地进行高亮显示。

下面是一个示例:

console.out("Locals", locals())
Locals {'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': <module 'builtins' (built-in)>, '__builtins__': <module 'builtins' (built-in)>, '_ih': ['', 'from rich.console import Console\nconsole = Console()\n\nconsole.print([1, 2, 3])\nconsole.print("[blue underline]看起来像一个链接")\n# console.print(locals())\nconsole.print("FOO", style="white on blue")', 'from rich.console import Console\n\nconsole = Console()\nconsole.log("这是一条日志信息")', 'console.print_json(\'[false, true, null, "foo"]\')', 'from rich.json import JSON\n\nconsole.log(JSON(\'["foo", "bar"]\'))', 'console.out("Locals", locals())'], '_oh': {}, '_dh': [PosixPath('/home/runner/work/d2py/d2py/doc/topics/tools/tasks/rich/console')], 'In': ['', 'from rich.console import Console\nconsole = Console()\n\nconsole.print([1, 2, 3])\nconsole.print("[blue underline]看起来像一个链接")\n# console.print(locals())\nconsole.print("FOO", style="white on blue")', 'from rich.console import Console\n\nconsole = Console()\nconsole.log("这是一条日志信息")', 'console.print_json(\'[false, true, null, "foo"]\')', 'from rich.json import JSON\n\nconsole.log(JSON(\'["foo", "bar"]\'))', 'console.out("Locals", locals())'], 'Out': {}, 'get_ipython': <bound method InteractiveShell.get_ipython of <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7f7a2426ff20>>, 'exit': <IPython.core.autocall.ZMQExitAutocall object at 0x7f7a2631fa40>, 'quit': <IPython.core.autocall.ZMQExitAutocall object at 0x7f7a2631fa40>, 'open': <function open at 0x7f7a26fd94e0>, '_': '', '__': '', '___': '', '_i': 'from rich.json import JSON\n\nconsole.log(JSON(\'["foo", "bar"]\'))', '_ii': 'console.print_json(\'[false, true, null, "foo"]\')', '_iii': 'from rich.console import Console\n\nconsole = Console()\nconsole.log("这是一条日志信息")', '_i1': 'from rich.console import Console\nconsole = Console()\n\nconsole.print([1, 2, 3])\nconsole.print("[blue underline]看起来像一个链接")\n# console.print(locals())\nconsole.print("FOO", style="white on blue")', 'Console': <class 'rich.console.Console'>, 'console': <console width=115 ColorSystem.TRUECOLOR>, '_i2': 'from rich.console import Console\n\nconsole = Console()\nconsole.log("这是一条日志信息")', '_i3': 'console.print_json(\'[false, true, null, "foo"]\')', '_i4': 'from rich.json import JSON\n\nconsole.log(JSON(\'["foo", "bar"]\'))', 'JSON': <class 'rich.json.JSON'>, '_i5': 'console.out("Locals", locals())'}

rich 规则#

rule() 方法将绘制一条带有可选标题的水平线,这是一种将终端输出划分为不同部分的好方法。

console.rule("[bold red]Chapter 2")
──────────────────────────────────────────────────── Chapter 2 ────────────────────────────────────────────────────

文件输出#

你可以告诉 Console 对象通过在构造函数上设置 file 参数来写入文件,该参数应该是一个用于写入文本的类似文件的对象。你可以使用此方法将内容写入文件,而不会显示在终端上。下面是一个示例:

import sys
from rich.console import Console
from datetime import datetime

with open("report.txt", "wt") as report_file:
    console = Console(file=report_file)
    console.rule(f"Report Generated {datetime.now().ctime()}")

注意,当写入文件时,如果你不希望将输出包装到当前控制台宽度,你可能需要显式设置 width 参数。

捕获输出#

在某些情况下,你可能希望捕获 Console 的输出,而不是直接将其写入终端。你可以使用 capture() 方法来实现这一点,该方法返回一个上下文管理器。在退出此上下文管理器时,调用 get() 方法以返回本来会被写入终端的字符串。下面是一个示例:

from rich.console import Console
console = Console()
with console.capture() as capture:
    console.print("[bold red]Hello[/] World")
str_output = capture.get()

print(str_output)

Hello World

捕获输出的另一种方法是将 Console 的文件设置为 io.StringIO。如果你在单元测试中测试控制台输出,这是推荐的方法。下面是一个示例:

from io import StringIO
from rich.console import Console
console = Console(file=StringIO())
console.print("[bold red]Hello[/] World")
str_output = console.file.getvalue()
Hello World

Emoji 表情#

将名称放在两个冒号之间即可在控制台输出中插入 emoji 表情符。示例如下:

console.print(":smiley: :vampire: :pile_of_poo: :thumbs_up: :raccoon:")
😃 🧛 💩 👍 🦝

表格(Tables)#

Rich 可以使用 Unicode 框字符来呈现多变的表格。Rich 包含多种边框,样式,单元格对齐等格式设置的选项。下面是一个简单的示例:

from rich.console import Console
from rich.table import Column, Table

console = Console()

table = Table(show_header=True, header_style="bold magenta")
table.add_column("Date", style="dim", width=12)
table.add_column("Title")
table.add_column("Production Budget", justify="right")
table.add_column("Box Office", justify="right")
table.add_row(
    "Dec 20, 2019", "Star Wars: The Rise of Skywalker", "$275,000,000", "$375,126,118"
)
table.add_row(
    "May 25, 2018",
    "[red]Solo[/red]: A Star Wars Story",
    "$275,000,000",
    "$393,151,347",
)
table.add_row(
    "Dec 15, 2017",
    "Star Wars Ep. VIII: The Last Jedi",
    "$262,000,000",
    "[bold]$1,332,539,889[/bold]",
)

console.print(table)
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Date          Title                              Production Budget      Box Office ┃
┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ Dec 20, 2019 │ Star Wars: The Rise of Skywalker  │      $275,000,000 │   $375,126,118 │
│ May 25, 2018 Solo: A Star Wars Story           │      $275,000,000 │   $393,151,347 │
│ Dec 15, 2017 │ Star Wars Ep. VIII: The Last Jedi │      $262,000,000 │ $1,332,539,889 │
└──────────────┴───────────────────────────────────┴───────────────────┴────────────────┘

进度条(Progress Bars)#

Rich 可以渲染多种“无闪烁”的进度条图形,以跟踪长时间运行的任务。

基本用法:用 track 函数调用任何程序并迭代结果。下面是一个例子:

from rich.progress import track

def do_step(step):
    ...

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


状态动画(Status)#

对于那些很难计算进度的情况,你可以使用 status 方法,它会展示一个“环形旋转(spinner)”的动画和文字信息。这个动画并不会妨碍你正常使用控制台。下面是个例子:

from time import sleep
from rich.console import Console

console = Console()
tasks = [f"task {n}" for n in range(1, 3)]

with console.status("[bold green]Working on tasks...") as status:
    while tasks:
        task = tasks.pop(0)
        sleep(1)
        console.log(f"{task} complete")
[07:08:57] task 1 complete                                                                         2994640024.py:11
[07:08:58] task 2 complete                                                                         2994640024.py:11

你可以通过 spinner 参数指定一种动画效果。执行以下命令来查看所有可选值:

python3 -m rich.spinner

树(Tree)#

Rich 可以渲染一个包含引导线的树(tree)。对于展示文件目录结构和其他分级数据来说,树是理想选择。

树的标签可以是简单文本或任何 Rich 能渲染的东西。执行以下命令查看演示:

!python -m rich.tree
📁 Renderables
├── 📁 Atomic
╠══ 📄 Syntax
  1 class Segment(NamedTuple):                                          
  2     text: str = ""                                                  
  3     style: Optional[Style] = None                                   
  4     is_control: bool = False                                        
  5                                                                     
╚══ 📄 Markdown
    ╭──────────────────────────────────────────────────────────────────────╮
                              example.md                              
                                                                      
 ▌ Hello, World!                                                      
 ▌ Markdown all the things                                            
    ╰──────────────────────────────────────────────────────────────────────╯
└── 📁 Containers
    ┣━━ 📄 Panels
    ╭──────────────╮
     Just a panel 
    ╰──────────────╯
    ┗━━ 📄 Table
        ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
         Released      Title                                  Box Office         ┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
         Dec 20, 2019  Star Wars: The Rise of Skywalker     $952,110,690          May 25, 2018  Solo: A Star Wars Story              $393,151,347          Dec 15, 2017  Star Wars Ep. V111: The Last Jedi  $1,332,539,889          Dec 16, 2016  Rogue One: A Star Wars Story       $1,332,439,889         └──────────────┴───────────────────────────────────┴────────────────┘

列(Columns)#

Rich 可以将内容通过排列整齐的,具有相等或最佳的宽度的列来呈现。下面是(macOS / Linux)ls命令的一个非常基本的克隆,用于用列来显示目录列表:

import os
import sys

from rich import print
from rich.columns import Columns

directory = os.listdir(".")
print(Columns(directory))
index.md intro.ipynb use.ipynb

Markdown#

Rich 可以呈现markdown,并可相当不错的将其格式转移到终端。

为了渲染 markdown,请导入Markdown类,并使用包含 markdown 代码的字符串来构造它,然后将其打印到控制台。例子如下:

from rich.console import Console
from rich.markdown import Markdown

console = Console()
with open("README.md") as readme:
    markdown = Markdown(readme.read())
console.print(markdown)
%load_ext rich
from rich.console import Console
from rich.markdown import Markdown

markdown = Markdown("# hi\n## fg")
markdown
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                       hi                                                        ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛


                                                        fg                                                         

语法高亮(Syntax Highlighting)#

Rich 使用 pygments 库来实现语法高亮显示。用法类似于渲染 markdown。构造 Syntax 对象并将其打印到控制台。下面是一个例子:

from rich.console import Console
from rich.syntax import Syntax

my_code = '''
def iter_first_last(values: Iterable[T]) -> Iterable[Tuple[bool, bool, T]]:
    """Iterate and generate a tuple with a flag for first and last value."""
    iter_values = iter(values)
    try:
        previous_value = next(iter_values)
    except StopIteration:
        return
    first = True
    for value in iter_values:
        yield first, False, previous_value
        first = False
        previous_value = value
    yield first, True, previous_value
'''
syntax = Syntax(my_code, "python", theme="monokai", line_numbers=True)
console = Console()
console.print(syntax)
   1                                                                                                               
   2 def iter_first_last(values: Iterable[T]) -> Iterable[Tuple[bool, bool, T]]:                                   
   3     """Iterate and generate a tuple with a flag for first and last value."""                                  
   4     iter_values = iter(values)                                                                                
   5     try:                                                                                                      
   6         previous_value = next(iter_values)                                                                    
   7     except StopIteration:                                                                                     
   8         return                                                                                                
   9     first = True                                                                                              
  10     for value in iter_values:                                                                                 
  11         yield first, False, previous_value                                                                    
  12         first = False                                                                                         
  13         previous_value = value                                                                                
  14     yield first, True, previous_value                                                                         
  15                                                                                                               

栈回溯信息(Tracebacks)#

Rich 可以渲染出漂亮的栈回溯信息,它比标准的 Python 格式更容易阅读,且能显示更多的代码。您可以将 Rich 设置为默认的栈回溯处理程序,这样所有未捕获的异常都将由 Rich 为渲染。

下面是在 OSX(在 Linux 上也类似)系统的效果:

from rich.console import Console


def foo(n):
    return bar(n)


def bar(n):
    return foo(n)


console = Console()

try:
    foo(1)
except Exception:
    console.print_exception(max_frames=20)
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
 in <module>:15                                                                                   
                                                                                                  
   12 console = Console()                                                                         
   13                                                                                             
   14 try:                                                                                        
 15 foo(1)                                                                                  
   16 except Exception:                                                                           
   17 console.print_exception(max_frames=20)                                                  
   18                                                                                             
                                                                                                  
 in foo:5                                                                                         
                                                                                                  
    2                                                                                             
    3                                                                                             
    4 def foo(n):                                                                                 
  5 return bar(n)                                                                           
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
                                                                                                  
 in bar:9                                                                                         
                                                                                                  
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
  9 return foo(n)                                                                           
   10                                                                                             
   11                                                                                             
   12 console = Console()                                                                         
                                                                                                  
 in foo:5                                                                                         
                                                                                                  
    2                                                                                             
    3                                                                                             
    4 def foo(n):                                                                                 
  5 return bar(n)                                                                           
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
                                                                                                  
 in bar:9                                                                                         
                                                                                                  
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
  9 return foo(n)                                                                           
   10                                                                                             
   11                                                                                             
   12 console = Console()                                                                         
                                                                                                  
 in foo:5                                                                                         
                                                                                                  
    2                                                                                             
    3                                                                                             
    4 def foo(n):                                                                                 
  5 return bar(n)                                                                           
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
                                                                                                  
 in bar:9                                                                                         
                                                                                                  
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
  9 return foo(n)                                                                           
   10                                                                                             
   11                                                                                             
   12 console = Console()                                                                         
                                                                                                  
 in foo:5                                                                                         
                                                                                                  
    2                                                                                             
    3                                                                                             
    4 def foo(n):                                                                                 
  5 return bar(n)                                                                           
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
                                                                                                  
 in bar:9                                                                                         
                                                                                                  
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
  9 return foo(n)                                                                           
   10                                                                                             
   11                                                                                             
   12 console = Console()                                                                         
                                                                                                  
 in foo:5                                                                                         
                                                                                                  
    2                                                                                             
    3                                                                                             
    4 def foo(n):                                                                                 
  5 return bar(n)                                                                           
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
                                                                                                  
                                    ... 2958 frames hidden ...                                    
                                                                                                  
 in bar:9                                                                                         
                                                                                                  
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
  9 return foo(n)                                                                           
   10                                                                                             
   11                                                                                             
   12 console = Console()                                                                         
                                                                                                  
 in foo:5                                                                                         
                                                                                                  
    2                                                                                             
    3                                                                                             
    4 def foo(n):                                                                                 
  5 return bar(n)                                                                           
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
                                                                                                  
 in bar:9                                                                                         
                                                                                                  
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
  9 return foo(n)                                                                           
   10                                                                                             
   11                                                                                             
   12 console = Console()                                                                         
                                                                                                  
 in foo:5                                                                                         
                                                                                                  
    2                                                                                             
    3                                                                                             
    4 def foo(n):                                                                                 
  5 return bar(n)                                                                           
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
                                                                                                  
 in bar:9                                                                                         
                                                                                                  
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
  9 return foo(n)                                                                           
   10                                                                                             
   11                                                                                             
   12 console = Console()                                                                         
                                                                                                  
 in foo:5                                                                                         
                                                                                                  
    2                                                                                             
    3                                                                                             
    4 def foo(n):                                                                                 
  5 return bar(n)                                                                           
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
                                                                                                  
 in bar:9                                                                                         
                                                                                                  
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
  9 return foo(n)                                                                           
   10                                                                                             
   11                                                                                             
   12 console = Console()                                                                         
                                                                                                  
 in foo:5                                                                                         
                                                                                                  
    2                                                                                             
    3                                                                                             
    4 def foo(n):                                                                                 
  5 return bar(n)                                                                           
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
                                                                                                  
 in bar:9                                                                                         
                                                                                                  
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
  9 return foo(n)                                                                           
   10                                                                                             
   11                                                                                             
   12 console = Console()                                                                         
                                                                                                  
 in foo:5                                                                                         
                                                                                                  
    2                                                                                             
    3                                                                                             
    4 def foo(n):                                                                                 
  5 return bar(n)                                                                           
    6                                                                                             
    7                                                                                             
    8 def bar(n):                                                                                 
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
RecursionError: maximum recursion depth exceeded