This page describes how Rich's major subsystems fit together and how data flows from user code to terminal output. It covers the renderable protocol, the rendering pipeline, and the role of each core module. For detailed documentation on individual subsystems, see:
Rich is organized around five interlocking subsystems:
| Subsystem | Primary Module | Role |
|---|---|---|
| Console | rich/console.py | Entry point; drives the rendering pipeline, manages output |
| Renderable Protocol | rich/console.py | Contract that any object can implement to be printable |
| Text & Markup | rich/text.py, rich/markup.py | Styled text with spans; markup parsing |
| Segments | rich/segment.py | Atomic output units: (text, style, control) tuples |
| Styles & Colors | rich/style.py, rich/color.py | Immutable style descriptors rendered to ANSI escape codes |
| Live | rich/live.py | Auto-refreshing dynamic display built on top of Console |
Any object Rich can display must satisfy one of two protocols, both defined in rich/console.py:
RichCast rich/console.py252-259 — implements __rich__(), returning another renderable or a string. Used to add a Rich representation to a type without needing to know about ConsoleOptions.
ConsoleRenderable rich/console.py262-269 — implements __rich_console__(console, options), which yields Segment objects or further renderables. This is the core rendering interface.
The union type RenderableType rich/console.py273-274 captures what console.print() accepts:
RenderableType = Union[ConsoleRenderable, RichCast, str]
And RenderResult rich/console.py277 is what __rich_console__ returns:
RenderResult = Iterable[Union[RenderableType, Segment]]
This means renderables can yield other renderables, which are recursively resolved by the Console during rendering.
Protocol resolution diagram:
Sources: rich/console.py252-277 rich/console.py1073-1150
The following diagram maps user code actions to the internal class methods that execute them.
End-to-end rendering pipeline:
Sources: rich/console.py1073-1150 rich/console.py1570-1640 rich/console.py819-826
ConsoleOptionsConsoleOptions rich/console.py119-249 is a dataclass passed to every __rich_console__ call. It carries the rendering context: terminal dimensions, encoding, justify/overflow settings, and whether the target is a terminal. Renderables use options.update(width=...) to produce modified copies when delegating to sub-renderables.
| Field | Type | Purpose |
|---|---|---|
size | ConsoleDimensions | Terminal width × height |
max_width / min_width | int | Constrains renderable width |
is_terminal | bool | Whether writing to a real terminal |
encoding | str | Target encoding (e.g. "utf-8") |
justify | JustifyMethod | Override for text justification |
markup | bool | Whether markup is enabled |
height | Optional[int] | Constrained height, if any |
SegmentSegment rich/segment.py64-99 is a NamedTuple with three fields. It is the final intermediate form before ANSI strings are written to the file.
| Field | Type | Purpose |
|---|---|---|
text | str | The literal text content |
style | Optional[Style] | Visual style to apply |
control | Optional[Sequence[ControlCode]] | Terminal control sequence (cursor, clear, etc.) |
A segment with a non-None control field has cell_length == 0 and is not counted as printable text.
StyleStyle rich/style.py36 is an immutable object holding color (foreground/background) and attribute bits (bold, italic, underline, etc.). It converts to ANSI codes via _make_ansi_codes(color_system) rich/style.py340-381 and is combined with + to layer styles.
RenderHookRenderHook rich/console.py550-567 is an abstract class with a single method process_renderables(renderables). Hooks are pushed onto a stack in Console._render_hooks and called before rendering begins. The Live class uses this mechanism to intercept output and redirect it above the live display.
The following diagram shows which source files implement each subsystem and how they depend on each other.
Sources: rich/console.py38-63 rich/segment.py1-31 rich/style.py1-11 rich/color.py1-18
Live rich/live.py is built on top of Console and uses the RenderHook mechanism. When active, it:
RenderHook via Console.push_render_hook() rich/console.py849-856console.print() calls, moving them above the live display_RefreshThread that periodically re-renders its renderable to the same terminal regionProgress and Status are both implemented using Live as their display engine.
Sources: rich/console.py828-847 rich/console.py849-861
Console uses a threading.RLock (Console._lock) rich/console.py720 to protect buffer mutations. Buffer state itself (_buffer, _buffer_index, _theme_stack) is stored in ConsoleThreadLocals rich/console.py542-547 a threading.local subclass, so each thread maintains its own buffer and theme stack. This allows multiple threads to print concurrently without interleaving output at the segment level.
Sources: rich/console.py542-547 rich/console.py720 rich/console.py776-793
| User action | Method | Where it leads |
|---|---|---|
console.print(x) | Console.print() | → Console.render() → segments → buffer → _check_buffer() |
console.log(x) | Console.log() | Wraps content in a log table, then → Console.print() |
console.capture() | Capture context manager | Raises _buffer_index, collects segments, returns string |
with Live(...) as live: | Live.__enter__() | Registers RenderHook, starts refresh thread |
console.status("...") | Console.status() | Creates Status which wraps Live |
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.