Click
Click crea CLIs con decoradores. Maneja el texto de ayuda, la conversión de tipos, los subcomandos y la salida de terminal mejor que argparse puro.
Receta
import click
@click.command()
@click.option("--name", default="World", help="A quién saludar")
def hello(name):
click.echo(f"Hello, {name}!")
if __name__ == "__main__":
hello()Cuándo usar esto:
- Herramientas CLI multi-comando
- Mensajes de ayuda y error amigables para el usuario
- Se necesitan prompts, colores y barras de progreso
Ejemplo funcional
import click
@click.group()
@click.option("--verbose", "-v", is_flag=True)
@click.pass_context
def cli(ctx, verbose):
ctx.ensure_object(dict)
ctx.obj["verbose"] = verbose
@cli.command()
@click.argument("filename", type=click.Path(exists=True))
@click.option("--format", type=click.Choice(["json", "csv"]), default="json")
@click.pass_context
def convert(ctx, filename, format):
if ctx.obj["verbose"]:
click.echo(f"Converting {filename} to {format}", err=True)
# lógica de conversión
click.echo(f"Done: {filename}")
@cli.command()
@click.option("--force", is_flag=True, help="Omitir confirmación")
def clean(force):
if not force and not click.confirm("Delete all temp files?"):
raise click.Abort()
click.echo("Cleaned.")
if __name__ == "__main__":
cli()Lo que esto demuestra:
@click.group()para subcomandosclick.Path(exists=True)valida rutas de archivoclick.Choicerestringe los valores de las opcionesclick.confirmpara prompts interactivoserr=Trueenvía la salida detallada a stderr
Análisis profundo
Click vs argparse
| Característica | Click | argparse |
|---|---|---|
| Sintaxis | Decoradores | Imperativa |
| Formato de ayuda | Rico | Básico |
| Pruebas | CliRunner | parse_args |
| Prompts | Incorporado | Manual |
Errores comunes
- No usar
click.echo: problemas de codificación en Windows. Solución: siempre usarclick.echo, noprint. - Falta
pass_context: opciones del padre no disponibles. Solución:@click.pass_contextyctx.obj. - Callback del comando no testeable: solo invocación de CLI. Solución: usar
CliRunneren pytest. - Demasiadas opciones en un comando: inutilizable. Solución: dividir en subcomandos o archivo de configuración.
- Click sin punto de entrada: los usuarios no pueden instalar globalmente. Solución: registrar en
[project.scripts].
Alternativas
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
| Typer | Se prefieren las anotaciones de tipo | No hay tipado en el proyecto |
| argparse | Cero dependencias | Se necesita CLI rica |
| cyclopts | Configuración de dataclass | El equipo conoce Click |
Preguntas frecuentes
¿Click o Typer?
Typer si usas anotaciones de tipo en todas partes. Click para más control y madurez.
¿Cómo pruebo aplicaciones Click?
from click.testing import CliRunner; runner = CliRunner(); runner.invoke(cli, ["convert", "f.txt"]).
¿Cómo agrego autocompletado de shell?
@click.group() + instalar autocompletado: _MYAPP_COMPLETE=bash_source myapp.
¿Cómo manejo excepciones?
Deja que las excepciones se propaguen para obtener tracebacks, o captura y raise click.ClickException("msg") para errores limpios.
¿Múltiples argumentos?
Múltiples decoradores @click.argument() en orden.
¿Valores predeterminados de variables de entorno?
@click.option("--host", envvar="HOST", default="localhost").
¿Cómo muestro una barra de progreso?
with click.progressbar(items) as bar: ....
¿Click y async?
Usa @click.command() con asyncio.run() dentro, o el fork asyncclick.
¿Cómo versiono una CLI?
Decorador @click.version_option().
¿Grupos anidados?
Los grupos pueden contener grupos: @cli.group() dentro de otro grupo.
Relacionado
- Typer - CLI con anotaciones de tipo sobre Click
- argparse - alternativa de la biblioteca estándar
- Salida Rica - formato mejorado
- Mejores Prácticas de CLI - directrices de diseño
Versiones de Stack: Esta página fue escrita para Python 3.14.0, 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+.