Tables and trees
Choose the right Rich component — tables for columnar data, trees for hierarchies — and know when to skip formatting entirely.
- Identify when tabular output is appropriate for structured, multi-column data
- Identify when tree output fits hierarchical or nested data
- Choose the right Rich component for each situation
- Explain when plain text or JSON is better than formatted output
Rich gives you two high-level layout tools beyond coloured text: Table for
columnar data and Tree for hierarchical data. Choosing the right one is a
design decision, not a technical one.
Tables for columnar data
A table is the right choice when your output has a fixed set of named columns and one row per item. The human eye moves down a column far faster than it parses a line of key=value pairs.
Compare these two outputs from a file-scanner tool:
# Plain text (hard to scan)
report.py: 212 lines, 7 errors, last modified 2024-01-15
utils.py: 84 lines, 0 errors, last modified 2024-01-10
main.py: 301 lines, 12 errors, last modified 2024-01-18# Table (easy to scan)
┌──────────┬───────┬────────┬──────────────┐
│ File │ Lines │ Errors │ Modified │
├──────────┼───────┼────────┼──────────────┤
│ report.py│ 212 │ 7 │ 2024-01-15 │
│ utils.py │ 84 │ 0 │ 2024-01-10 │
│ main.py │ 301 │ 12 │ 2024-01-18 │
└──────────┴───────┴────────┴──────────────┘A user looking for files with errors runs their eye down the Errors column
in under a second. With the flat format, they read every line.
Trees for hierarchical data
A tree represents containment or parent-child relationships. File system structures, dependency graphs, and module hierarchies are natural trees. Flat lists cannot represent these without losing the structure.
Rich's Tree component makes it easy:
from rich.tree import Tree
tree = Tree("project/")
src = tree.add("src/")
src.add("main.py")
src.add("utils.py")
tree.add("tests/").add("test_main.py")
tree.add("pyproject.toml")This renders with proper branch characters, indentation, and optional styling. The visual hierarchy mirrors the actual hierarchy.
When to skip formatting
Rich output is for humans. When your tool's output is consumed by another program — via a pipe, a shell script, or a CI log parser — Rich's ANSI codes and box-drawing characters are noise.
Two rules of thumb:
- If the output goes to a file or a pipe, emit plain text or JSON.
- Rich handles this automatically: it detects whether stdout is a terminal and strips ANSI codes when it is not.
For tools where machine consumption is a primary use case, add a --json flag
that bypasses Rich entirely and outputs structured JSON. Let the human-friendly
display be the default; let --json be the escape hatch.
Rich's Console(force_terminal=True) overrides the auto-detection. Use it in
tests when you want to assert on styled output, and Console(no_color=True)
when you want clean output for snapshot testing.
Where to go next
Next: colour conventions — establishing consistent colour semantics across your tool so users build reliable intuitions.