Rich & Textual
Rich hace que la salida de la terminal sea legible: colores, tablas, barras de progreso, tracebacks con resaltado de sintaxis. Textual se basa en Rich para crear interfaces de usuario de terminal (TUI) completas con widgets, diseños y eventos asíncronos. Juntos reemplazan la depuración frágil con print y el código repetitivo de curses.
Receta
from rich.console import Console
from rich.table import Table
console = Console()
table = Table(title="Estado de Despliegue")
table.add_column("Servicio")
table.add_column("Versión")
table.add_row("api", "2.1.0")
table.add_row("worker", "2.1.0")
console.print(table)Cuándo usar esto:
- Herramientas CLI que los operadores ejecutan a diario (despliegue, migración, correcciones de datos)
- Scripts de larga duración que necesitan retroalimentación de progreso
- Paneles internos sin presupuesto para una interfaz web
- Salida de errores bonita durante el desarrollo local
Ejemplo Funcional
from __future__ import annotations
import time
from dataclasses import dataclass
from rich.console import Console
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
@dataclass
class Job:
name: str
rows: int
def process_jobs(jobs: list[Job]) -> None:
console = Console(stderr=True)
with Progress(
SpinnerColumn(),
TextColumn("[bold blue]{task.description}"),
BarColumn(),
TaskProgressColumn(),
console=console,
) as progress:
task_id = progress.add_task("Procesando", total=sum(j.rows for j in jobs))
for job in jobs:
progress.update(task_id, description=job.name)
for _ in range(job.rows):
time.sleep(0.01)
progress.advance(task_id)
console.print("[green]Hecho[/green]")
if __name__ == "__main__":
process_jobs([Job("usuarios", 50), Job("pedidos", 30)])Lo que esto demuestra:
Console(stderr=True)mantiene stdout libre para canalizaciones (piping)Progresscompone columnas para el spinner, etiqueta, barra y porcentaje- La descripción de la tarea se actualiza por nombre de trabajo
- Marcado de color (
[green]) sin códigos de escape manuales
Inmersión Profunda
Cómo Funciona
- Console - Detecta el ancho de la terminal, el soporte de color y la representación de emojis; retrocede elegantemente en los registros de CI.
- Marcado - Etiquetas de estilo
[bold red]error[/];console.print(obj)imprime bonitamente dataclasses y diccionarios. - Pantalla en vivo -
rich.live.Liveactualiza tablas o registros en el lugar sin parpadeos. - Textual - Framework TUI basado en eventos; las aplicaciones heredan de
App, definencompose()para widgets, manejanon_button_pressed, etc.
Rich vs Textual
| Herramienta | Mejor para |
|---|---|
| Rich | Salida CLI de un solo uso, progreso, embellecimiento de registros |
| Textual | TUI interactivas: asistentes de configuración, seguidores de registros, consolas de operaciones internas |
curses de stdlib | Dependencias mínimas solo en sistemas embebidos |
Notas de Python
# Instala tracebacks de Rich globalmente en un punto de entrada CLI
from rich.traceback import install
install(show_locals=True)
# Esqueleto mínimo de aplicación Textual
from textual.app import App, ComposeResult
from textual.widgets import Header, Footer, Static
class HelloApp(App):
def compose(self) -> ComposeResult:
yield Header()
yield Static("Hola desde Textual")
yield Footer()
if __name__ == "__main__":
HelloApp().run()Trampas Comunes
- Imprimir tablas en stdout en CLIs canalizadas - Rompe
jqogrepposteriores. Solución:Console(file=sys.stderr)para salida humana. - Asumir color en CI - Algunos ejecutores eliminan ANSI. Solución:
Console(force_terminal=True)solo cuando sea necesario; probar en modo plano. - Textual sin disciplina asíncrona - Bloquear
time.sleepen manejadores congela la interfaz de usuario. Solución:await asyncio.sleeporun_worker. - Tablas enormes en terminales estrechas - Las columnas se truncan de forma confusa. Solución:
table.add_column(..., overflow="fold")o exportar CSV. - Rich en código de biblioteca incondicionalmente - Fuerza Rich como una dependencia dura para los consumidores. Solución: salida bonita opcional detrás de un indicador
--verbose. - Duplicación de manejadores de registro -
LoggingHandlerde Rich más un manejador stdlib duplica las líneas. Solución: configurar un árbol de manejadores.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
click + print plano | CLIs simples con formato mínimo | Los operadores necesitan tablas, progreso o estado en vivo |
typer | Reemplazo de argparse tipado | Necesitas interfaces interactivas a pantalla completa |
blessed / prompt_toolkit | REPLs con mucha entrada | Quieres diseños de widgets declarativos (Textual) |
| Interfaz Web (FastAPI + HTMX) | Los usuarios no técnicos necesitan acceso | Servidores solo SSH o entornos aislados |
Preguntas Frecuentes
¿Rich funciona en terminales de Windows?
Sí, Rich detecta las limitaciones de las consolas heredadas y se degrada elegantemente. Windows Terminal admite color completo.
¿Puedo usar Rich dentro de pytest?
Sí, Console(record=True) captura la salida para aserciones; evita las barras de progreso en las ejecuciones de prueba predeterminadas.
¿Cuándo debería elegir Textual en lugar de una pequeña aplicación web?
Cuando los operadores viven en sesiones SSH y necesitas flujos de trabajo controlados por teclado sin alojar otro servicio.
¿Cómo registro JSON y sigo viéndolo bonito localmente?
Mantén los registros de producción como JSON en stdout; adjunta el manejador Rich solo cuando LOG_FORMAT=pretty en desarrollo.
¿Textual admite clics del ratón?
Sí, en terminales compatibles; habilítalo en la configuración de la aplicación; aún así, proporciona alternativas de teclado.
¿Cómo pruebo una aplicación Textual?
Usa el framework de prueba asíncrono textual.pilot para simular pulsaciones de teclas y afirmar el estado del widget.
¿Puede Rich renderizar Markdown?
rich.markdown.Markdown renderiza MD en la terminal, útil para extensiones de --help.
¿Cómo desactivo los colores para scripting?
Establece NO_COLOR=1 en el entorno; Rich respeta el estándar.
¿Es Rich lento para salidas grandes?
Renderizar 10k filas en línea es lento; pagina, muestrea o escribe en un archivo y abre un editor.
¿Puedo incrustar Rich en FastAPI?
Rich se dirige a terminales, no a HTTP; úsalo en comandos de administración y CLIs de trabajadores, no en respuestas de API.
Relacionado
- Conceptos Básicos de Herramientas CLI - puntos de entrada de argparse/typer
- Conceptos Básicos de Errores y Registro - patrones de registro estructurado
- Configuración de pytest - pruebas de herramientas CLI
- Productividad del Shell - flujo de trabajo de terminal
Versiones de Stack: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.