CLI: argumentos sin frameworks¶
6 minutos de lectura · 2 abril 2026
Click es una librería preciosa. La he usado durante años. Pero el setup mental de Click —decoradores, contextos, grupos— solo se rentabiliza si la CLI va a vivir mucho tiempo y crecer.
Para el 80% de los scripts internos,
sys.argvy unmatchresuelven mejor que cualquier framework.
Lo que sigue es lo que uso ahora, después de un año limpiando CLIs propias y ajenas.
La heurística¶
Antes de instalar nada, me hago tres preguntas:
- ¿Va a tener más de tres subcomandos?
- ¿Va a tenerlos subcomandos anidados (
git remote add ...)? - ¿Va a ser distribuido a gente que no lo escribió?
Si la respuesta a las tres es no, no necesitas Click. Probablemente tampoco necesites argparse con todas sus secciones.
Nivel 0: sys.argv y nada más¶
import sys
def main():
args = sys.argv[1:]
if not args or args[0] in ("-h", "--help"):
print("uso: limpiar <ruta> [--dry-run]")
return 0
ruta = args[0]
dry_run = "--dry-run" in args
return ejecutar(ruta, dry_run=dry_run)
if __name__ == "__main__":
raise SystemExit(main())
Cuatro líneas de "parsing". Suficiente para el 60% de los scripts que tengo en ~/bin.
Nivel 1: argparse minimalista¶
Cuando aparece un flag con valor (--retries=3) o más de una posicional, paso a argparse pero sin subcomandos:
import argparse
def main():
p = argparse.ArgumentParser(description="Limpia builds viejos")
p.add_argument("ruta")
p.add_argument("--retries", type=int, default=3)
p.add_argument("--dry-run", action="store_true")
a = p.parse_args()
return ejecutar(a.ruta, retries=a.retries, dry_run=a.dry_run)
Sigue siendo legible de un vistazo. Sigue siendo cero dependencias.
Nivel 2: subcomandos con match¶
Cuando aparece el primer subcomando, no salto a Click. Salto a un match sobre el primer argumento:
def main():
cmd, *rest = sys.argv[1:] or ["help"]
match cmd:
case "build": return cmd_build(rest)
case "clean": return cmd_clean(rest)
case "deploy": return cmd_deploy(rest)
case "help" | "-h" | "--help":
print(__doc__)
return 0
case _:
print(f"comando desconocido: {cmd}", file=sys.stderr)
return 2
Cada cmd_* parsea sus propios flags con argparse local. La CLI crece sin que el archivo principal se convierta en un grafo de decoradores.
Cuándo sí usar Click¶
- Cuando el comando es público y la documentación generada importa.
- Cuando hay completion en shell que el usuario debe instalar.
- Cuando hay grupos anidados de verdad, no por adelantarse al futuro.
Click resuelve esos tres problemas mejor que nada. Solo que no son los problemas que tenía mi script de cinco minutos.
Tres heurísticas¶
- Empieza por
sys.argv. Si te pica, sube un nivel. Casi nunca pica. - Subcomandos =
match, no decoradores. El tipocasees una herramienta de routing tan buena como cualquier router. - No tomes la decisión a priori. Empieza pequeño y migra cuando el dolor sea real.
Próxima entrada
Los flags --dry-run y --verbose tienen patrones de implementación que merece la pena estandarizar. En la siguiente parte cuento los míos.
¿Comentarios o correcciones? info@encodigo.es.