Python Rich: Markdown, JSON, and Layouts in the Terminal
python rich markdown json and layouts: Learn how to use Python Rich to render Markdown, JSON, and multi-panel layouts in the terminal with syntax highlighting and resp...
python rich markdown json and layouts requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
Plain text output from a Python CLI quickly becomes unreadable once you need to show structured data, formatted documentation, or multiple panels of information. The Rich library solves this by rendering Markdown, JSON, and custom layouts directly in the terminal. This article shows how to use Python Rich to render Markdown, JSON, and layouts together for a polished command-line interface.
What Rich Provides for Terminal Output
Rich is a Python library that adds colors, styles, tables, panels, and more to terminal output. Instead of manually inserting ANSI escape codes, you use high-level objects that Rich renders for you. Three of its most useful components for data-heavy CLIs are Markdown, JSON, and Layout. Markdown renders formatted text with headings, emphasis, and code blocks. JSON displays JSON data with syntax highlighting and indentation. Layout divides the terminal into resizable regions that can each contain different Rich renderables.
These components work together. You can put a Markdown document in one panel and a JSON payload in another, then arrange them side by side or stacked. The result is a terminal interface that feels like a lightweight GUI without leaving the command line.
Rendering Markdown with Rich
The rich.markdown.Markdown class takes a string containing Markdown and renders it with proper formatting. You pass it to Console.print() like any other renderable. Here is a minimal example:
from rich.console import Console from rich.markdown import Markdown console = Console() markdown_text = """ # Project Status **Updated:** 2024-11-05 ## Highlights - API rate limit increased - New endpoint for batch processing """ console.print(Markdown(markdown_text))
Rich parses the Markdown and applies styles: headings are bold and colored, emphasis is italic, and inline code gets a background. It also handles links and images, though images are shown as text placeholders in the terminal. The Markdown object accepts options like code_theme to control syntax highlighting of fenced code blocks within the Markdown.
For dynamic content, you can create a new Markdown instance whenever the text changes. This is useful when you are rendering log output or documentation that updates in real time.
Displaying JSON with Rich
The rich.json.JSON class renders JSON with syntax highlighting and proper indentation. You can pass a JSON string directly, or use a dictionary and let Rich serialize it. Here is an example:
from rich.console import Console from rich.json import JSON console = Console() data = { "user": "alice", "roles": ["admin", "editor"], "last_login": "2024-11-05T10:30:00Z" } console.print(JSON.from_data(data))
JSON.from_data() is a class method that accepts a Python object and converts it to a JSON string internally. Alternatively, you can pass a raw JSON string to JSON(json_string). Rich colors keys, strings, numbers, and booleans differently, making it easy to spot structural issues at a glance.
When you have large JSON payloads, you can control the indentation with the indent parameter and enable or disable highlight. For example, JSON(json_str, indent=4) produces more readable output. If the JSON is malformed, Rich raises a JSONDecodeError; you should catch that if you are handling untrusted input.
Building Responsive Layouts with Rich
The rich.layout.Layout class lets you split the terminal into rows and columns. You define a layout tree, then assign renderables to each leaf. The layout automatically resizes when the terminal window changes. Here is a basic two-column layout:
from rich.console import Console from rich.layout import Layout from rich.panel import Panel from rich.markdown import Markdown from rich.json import JSON console = Console() layout = Layout() layout.split_row( Layout(name="left"), Layout(name="right") ) markdown = Markdown("# Docs\n\nThis is the left panel.") json_data = JSON.from_data({"status": "ok", "count": 42}) layout["left"].update(Panel(markdown, title="Documentation")) layout["right"].update(Panel(json_data, title="Response")) console.print(layout)
The split_row method creates side-by-side panels. You can also use split_column for vertical stacking, or nest them to create complex grids. Each Layout has a size attribute to set a fixed width or height, and a ratio to control proportional sizing. For example, Layout(name="left", ratio=2) makes the left panel twice as wide as the right when both have ratio=1.
Layouts are not limited to panels; you can put any Rich renderable inside, including tables, text, or even other layouts. This makes them ideal for dashboards that combine multiple data sources.
Combining Markdown, JSON, and Layouts in One View
A common pattern in CLI tools is to show a help document alongside the JSON response from an API. You can achieve this by placing a Markdown object in one layout region and a JSON object in another. The following example builds a three-region layout: a header, a left column with Markdown, and a right column with JSON.
from rich.console import Console from rich.layout import Layout from rich.panel import Panel from rich.markdown import Markdown from rich.json import JSON console = Console() layout = Layout() layout.split_column( Layout(name="header", size=3), Layout(name="body") ) layout["body"].split_row( Layout(name="docs", ratio=2), Layout(name="data", ratio=1) ) header = Panel("API Console", style="bold blue") markdown = Markdown("# Usage\n\nCall `GET /v1/users` to list users.") json_data = JSON.from_data({"users": [{"id": 1, "name": "Alice"}]}) layout["header"].update(header) layout["docs"].update(Panel(markdown, title="Docs")) layout["data"].update(Panel(json_data, title="JSON Response")) console.print(layout)
When you run this, the terminal shows a header panel at the top, with the Markdown on the left and the JSON on the right. The layout reflows automatically if you resize the terminal, so the content remains readable. You can update any region later by calling update() again with a new renderable, which is useful for interactive applications that refresh periodically.
One thing to keep in mind is that Layout does not handle scrolling internally. If a panel's content exceeds the available space, Rich will truncate it. For long documents, consider using a rich.panel.Panel with expand=False or implementing a pager, or use Console.print with soft_wrap=True to avoid wrapping issues.
Performance and Output Size Considerations
Rich adds a parsing and styling layer on top of plain text output. For small Markdown strings and JSON objects, the overhead is negligible. But when you render a multi-megabyte JSON file or a very long Markdown document, the initial parsing can take noticeable time and produce a large amount of ANSI escape codes, which slows down terminal rendering.
If you are dealing with large data, you have a few options. For JSON, you can use the indent parameter sparingly or set highlight=False to reduce styling work. For Markdown, you can limit the input size before passing it to Rich. Alternatively, you can use Rich's Console.capture() to test the output size and decide whether to truncate.
Another consideration is non-TTY environments. When you pipe your script's output to a file or another command, Rich automatically disables colors and styles if the output is not a terminal. This is controlled by the force_terminal and no_color options on Console. If you want to force plain text output, you can create a Console(force_terminal=False).
Choosing Between Rich and Plain Text Output
Rich is not always the right choice. If you are writing a script that will be used in automated pipelines where output is parsed by other tools, plain text or JSON is more appropriate. Rich's styled output is meant for human eyes, not for machine consumption. For example, a curl-like tool that outputs JSON for scripting should not use Rich's JSON renderer; it should print raw JSON.
Use Rich when you are building an interactive CLI, a development tool, or a diagnostic utility where the user is looking at the terminal directly. The combination of Markdown, JSON, and layouts gives you a way to present complex information without requiring a GUI. Just be aware of the performance tradeoff and the fact that the output is not easily parseable by other programs.
If you need to support both human and machine-readable output, you can add a --json flag to your CLI that prints raw JSON, while the default output uses Rich. This gives you the best of both worlds: a pleasant experience for interactive use and a stable format for automation.