Saltar al contenido
jesusprodriguez.com

python-automation

Python: scripts de automatización

Scripts de automatización que se pueden reejecutar sin miedo: dry-run, logging, códigos de salida honestos e idempotencia.

stack:
Python
versión:
v1.0.0
actualizada:
tamaño:
3.1 KB
lectura:
2 min
licencia:
CC-BY-4.0

Cuándo se activa

Al escribir CLIs, tareas programadas, tratamiento de ficheros o integraciones con APIs.

description: Escribe scripts de automatización y procesamiento de datos en Python que se puedan reejecutar sin miedo. Úsala al crear scripts de CLI, tareas programadas, tratamiento de ficheros o integraciones con APIs y LLMs.

  • argparse y dry-run
  • logging
  • pathlib y encoding
  • APIs con timeout

Cómo se le pide

> Escribe un script que sincronice la carpeta de facturas con el SFTP, con dry-run por defecto.

Escríbeselo tal cual al agente: la skill se carga sola por la descripción, no hay que nombrarla.

Cómo se instala

/plugin marketplace add https://jesusprodriguez.com/skills/marketplace.json
/plugin install ingenieria@jprodriguez-toolkit

La vía nativa, y la única que se actualiza sola: el marketplace se añade una vez y `/plugin marketplace update` trae las versiones nuevas. Las skills quedan con espacio de nombres propio (`azure-devops:azure-pr-review`).

El fichero, entero

Esto es exactamente lo que descargas: sin resúmenes ni recortes.

Python: scripts de automatización

Un script de automatización se ejecuta desatendido y a menudo sobre datos reales. Estas reglas evitan los desastres silenciosos.

Esqueleto

#!/usr/bin/env python3
"""Descripción en una línea de lo que hace el script."""
from __future__ import annotations

import argparse
import logging
import sys
from pathlib import Path

log = logging.getLogger(Path(__file__).stem)


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("origen", type=Path)
    parser.add_argument("--dry-run", action="store_true",
                        help="muestra lo que haría sin escribir nada")
    parser.add_argument("-v", "--verbose", action="store_true")
    args = parser.parse_args(argv)

    logging.basicConfig(
        level=logging.DEBUG if args.verbose else logging.INFO,
        format="%(levelname)s %(name)s: %(message)s",
    )

    if not args.origen.exists():
        log.error("no existe: %s", args.origen)
        return 1

    return 0


if __name__ == "__main__":
    sys.exit(main())

Reglas

  1. --dry-run en todo lo que escriba, borre o publique. Es la diferencia entre un fallo y un incidente.
  2. pathlib en lugar de os.path, y nunca concatenación de rutas con +.
  3. logging, no print. El script acabará en cron o en CI, donde print se pierde y no lleva marca de tiempo.
  4. Código de salida honesto: 0 solo si todo fue bien. Un script que siempre devuelve 0 rompe cualquier automatización que lo encadene.
  5. Idempotencia: ejecutarlo dos veces debe dejar el mismo estado. Si no es posible, escribe primero a un fichero temporal y renombra al final.

Entorno y dependencias

uv venv && uv pip install -r requirements.txt   # o python -m venv .venv
  • Fija las versiones en requirements.txt. Un script que funcionaba en marzo y falla en junio suele ser una dependencia que subió de major.
  • Secretos por variables de entorno (os.environ["API_KEY"], que falla fuerte si no está) o .env fuera del control de versiones. Nunca en el código.

Ficheros y datos

  • CSV/JSON: abre siempre con encoding="utf-8" explícito; el valor por defecto en Windows no es UTF-8 y el script se romperá solo en esa máquina.
  • Para volúmenes grandes, itera en streaming en lugar de cargar todo en memoria: for line in f antes que f.readlines().

Llamadas a APIs y LLMs

  • timeout= obligatorio en toda petición HTTP: sin él, un cuelgue del servidor bloquea el script para siempre.
  • Reintentos con espera exponencial solo en errores 429 y 5xx; un 4xx no se arregla repitiendo.
  • Cachea las respuestas caras en disco durante el desarrollo: iterar sobre el prompt no debería costar una llamada de pago cada vez.