25. Automatizar tareas repetitivas con scripts de Python

25.1 Objetivo del tema

Una suite automatizada no solo necesita pruebas. También necesita tareas auxiliares: limpiar reportes, crear carpetas, listar pruebas, verificar estructura y ejecutar comandos frecuentes.

En este tema crearemos scripts de Python para automatizar tareas repetitivas del proyecto y reducir errores manuales.

Objetivo práctico: crear scripts simples que preparen, limpien y diagnostiquen el proyecto de pruebas.

25.2 Por qué usar scripts de Python

Podríamos escribir comandos manualmente en la terminal, pero los scripts tienen ventajas:

  • Documentan el proceso en código.
  • Reducen errores al repetir comandos.
  • Funcionan de forma parecida en distintos sistemas operativos.
  • Pueden validar condiciones antes de ejecutar.
  • Pueden combinar varias tareas en un solo comando.

25.3 Crear carpeta scripts

Crea una carpeta para scripts auxiliares:

mkdir scripts

La estructura quedará así:

automatizacion-pruebas-python/
|-- app/
|-- tests/
|-- reports/
|-- scripts/
`-- run_tests.py

25.4 Script para preparar carpetas

Crea scripts/preparar_proyecto.py:

from pathlib import Path


CARPETAS = [
    Path("reports"),
    Path("tests/data"),
    Path("tests/helpers"),
]


def main():
    for carpeta in CARPETAS:
        carpeta.mkdir(parents=True, exist_ok=True)
        print(f"Carpeta lista: {carpeta}")


if __name__ == "__main__":
    main()

Ejecuta:

python scripts/preparar_proyecto.py

25.5 Script para limpiar reportes

Crea scripts/limpiar_reportes.py:

import shutil
from pathlib import Path


REPORTS_DIR = Path("reports")


def main():
    if REPORTS_DIR.exists():
        shutil.rmtree(REPORTS_DIR)
        print("Reportes eliminados")

    REPORTS_DIR.mkdir()
    print("Carpeta reports creada")


if __name__ == "__main__":
    main()

Ejecuta:

python scripts/limpiar_reportes.py

25.6 Script para listar pruebas

Crea scripts/listar_pruebas.py:

import subprocess
import sys


def main():
    comando = [sys.executable, "-m", "pytest", "--collect-only", "-q"]
    resultado = subprocess.run(comando, check=False)
    return resultado.returncode


if __name__ == "__main__":
    raise SystemExit(main())

Ejecuta:

python scripts/listar_pruebas.py

Este script ayuda a revisar qué pruebas detecta pytest.

25.7 Script para verificar estructura

Crea scripts/verificar_estructura.py:

from pathlib import Path


RUTAS_REQUERIDAS = [
    Path("app"),
    Path("tests"),
    Path("tests/data"),
    Path("tests/helpers"),
    Path("pytest.ini"),
    Path("run_tests.py"),
]


def main():
    faltantes = [ruta for ruta in RUTAS_REQUERIDAS if not ruta.exists()]

    if faltantes:
        print("Faltan rutas requeridas:")
        for ruta in faltantes:
            print(f"- {ruta}")
        return 1

    print("Estructura correcta")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Ejecuta:

python scripts/verificar_estructura.py

25.8 Usar códigos de salida

Los scripts deben devolver 0 cuando todo está bien y un valor distinto de 0 cuando hay un problema.

Este patrón permite que otros scripts sepan si una tarea fue exitosa:

if __name__ == "__main__":
    raise SystemExit(main())

25.9 Script para ejecutar una rutina completa

Crea scripts/rutina_local.py:

import subprocess
import sys


def ejecutar(comando):
    print("Ejecutando:", " ".join(comando))
    resultado = subprocess.run(comando, check=False)
    return resultado.returncode


def main():
    pasos = [
        [sys.executable, "scripts/verificar_estructura.py"],
        [sys.executable, "scripts/preparar_proyecto.py"],
        [sys.executable, "run_tests.py", "--reporte"],
    ]

    for paso in pasos:
        codigo = ejecutar(paso)
        if codigo != 0:
            return codigo

    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Ejecuta:

python scripts/rutina_local.py

25.10 Detener la rutina ante un error

La rutina anterior se detiene si un paso devuelve error:

if codigo != 0:
    return codigo

Esto evita ejecutar pruebas o generar reportes si la estructura del proyecto está incompleta.

25.11 Evitar comandos destructivos innecesarios

Los scripts deben ser cuidadosos. Por ejemplo, limpiar la carpeta reports es razonable porque contiene archivos generados. En cambio, borrar carpetas de código o pruebas sería peligroso.

Antes de eliminar archivos, verifica que el script actúe sobre rutas esperadas y limitadas.

25.12 Reutilizar funciones entre scripts

Si varios scripts comparten lógica, puedes crear scripts/utils.py:

import subprocess


def ejecutar(comando):
    print("Ejecutando:", " ".join(comando))
    return subprocess.run(comando, check=False).returncode

Luego importarlo desde otros scripts:

from scripts.utils import ejecutar

25.13 Crear __init__.py en scripts

Para importar desde scripts.utils, crea:

type nul > scripts\__init__.py

En Linux o macOS:

touch scripts/__init__.py

25.14 Agregar argumentos a scripts

Podemos usar argparse para hacer scripts más flexibles. Ejemplo para limpiar reportes:

import argparse


def leer_argumentos():
    parser = argparse.ArgumentParser()
    parser.add_argument("--crear", action="store_true", help="Crea reports después de limpiar")
    return parser.parse_args()

No hace falta agregar argumentos si el script tiene una sola tarea clara.

25.15 Documentar scripts en README

Agrega una sección al README.md:

## Scripts auxiliares

Preparar carpetas:

python scripts/preparar_proyecto.py

Limpiar reportes:

python scripts/limpiar_reportes.py

Listar pruebas:

python scripts/listar_pruebas.py

Rutina local:

python scripts/rutina_local.py

Un script sin documentación puede quedar olvidado aunque sea útil.

25.16 Scripts y run_tests.py

run_tests.py debe seguir concentrado en ejecutar pruebas. Los scripts auxiliares pueden encargarse de tareas alrededor de la suite.

  • run_tests.py: ejecutar pytest con opciones.
  • limpiar_reportes.py: limpiar artefactos.
  • verificar_estructura.py: validar rutas esperadas.
  • rutina_local.py: combinar varias tareas.

25.17 Probar scripts manualmente

Antes de confiar en un script, ejecútalo varias veces:

python scripts/verificar_estructura.py
python scripts/preparar_proyecto.py
python scripts/limpiar_reportes.py
python scripts/rutina_local.py

Un buen script debe poder repetirse sin romper el proyecto.

25.18 Cuándo crear un script nuevo

Crea un script cuando una tarea:

  • Se repite muchas veces.
  • Tiene varios pasos.
  • Puede fallar por errores manuales.
  • Debe ejecutarse igual en distintos equipos.
  • Necesita validaciones previas.

No crees scripts para acciones triviales que no se repetirán.

25.19 Problemas frecuentes

  • El script funciona solo desde una carpeta: documenta que debe ejecutarse desde la raíz o calcula rutas absolutas desde __file__.
  • No se detiene cuando falla un paso: revisa códigos de salida.
  • Duplica lógica de run_tests.py: deja cada script con una responsabilidad clara.
  • Borra archivos importantes: limita la limpieza a carpetas generadas.
  • Nadie sabe que existe: documenta el script en README.

25.20 Ejercicio práctico

Crea scripts/diagnostico.py. El script debe:

  • Verificar la estructura del proyecto.
  • Listar las pruebas detectadas.
  • Ejecutar la suite rápida con run_tests.py --tipo rapida.
  • Detenerse si algún paso falla.

25.21 Solución propuesta

Archivo scripts/diagnostico.py:

import subprocess
import sys


def ejecutar(comando):
    print("Ejecutando:", " ".join(comando))
    return subprocess.run(comando, check=False).returncode


def main():
    pasos = [
        [sys.executable, "scripts/verificar_estructura.py"],
        [sys.executable, "scripts/listar_pruebas.py"],
        [sys.executable, "run_tests.py", "--tipo", "rapida"],
    ]

    for paso in pasos:
        codigo = ejecutar(paso)
        if codigo != 0:
            return codigo

    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Ejecuta:

python scripts/diagnostico.py

25.22 Lista de verificación

Antes de continuar con el próximo tema, verifica lo siguiente:

  • Existe una carpeta scripts.
  • Los scripts tienen una responsabilidad clara.
  • Los scripts devuelven códigos de salida correctos.
  • Las tareas destructivas se limitan a carpetas generadas.
  • Los scripts se documentan en README.
  • La rutina local se detiene si un paso falla.
  • Las pruebas se siguen ejecutando con python -m pytest desde los scripts.

25.23 Conclusión

En este tema automatizamos tareas repetitivas con scripts de Python. Estos scripts ayudan a preparar el proyecto, limpiar artefactos, listar pruebas y ejecutar rutinas completas con menos errores manuales.

En el próximo tema crearemos comandos simples para ejecutar suites por objetivo, llevando esta automatización a una interfaz más cómoda para el uso diario.