Implementación de utilidades en Python: argparse, logging y envío de correos

Introducción

El desarrollo de aplicaciones Python robustas requiere tres mecanismos recurrentes: la interacción por línea de comandos, el registro de eventos y la notificación automatizada. A continuación se presenta una implementación práctica de cada uno de estos componentes, con ejemplos reutilizables y listos para integrar en proyectos reales.

Construcción de interfaces de línea de comandos con argparse

El módulo argparse permite definir argumentos, opciones, valores por defecto y mensajes de ayuda sin dependencias externas. Su uso correcto mejora la usabilidad de scripts y facilita la automatización.

Ejemplo de un CLI para procesar archivos de datos:

import argparse

def crear_parser():
    parser = argparse.ArgumentParser(
        description='Procesa archivos de datos en distintos formatos'
    )
    parser.add_argument(
        'operacion',
        type=str,
        choices=['convertir', 'analizar', 'exportar'],
        help='Acción principal que ejecutará el programa'
    )
    parser.add_argument(
        '--formato',
        type=str,
        choices=['json', 'csv', 'xml'],
        default='json',
        help='Formato de salida deseado'
    )
    parser.add_argument(
        '--verbose',
        action='store_true',
        help='Muestra información detallada durante la ejecución'
    )
    return parser.parse_args()

if __name__ == '__main__':
    args = crear_parser()
    print(args)

En este caso, operacion es un argumento posicional obligatorio, mientras que --formato y --verbose son opcionales. La validación de valores permitidos se realiza automáticamente.

Gestión de logs con logging

Un buen sistema de logging debe permitir distintos niveles de severidad, salida múltiple y formato configurable. La siguiente utilidad crea un logger que escribe tanto en consola como en archivo:

import logging
import sys

def crear_logger(nombre, ruta_log=None, nivel='INFO'):
    logger = logging.getLogger(nombre)
    logger.setLevel(getattr(logging, nivel.upper(), logging.INFO))
    
    formato = logging.Formatter(
        '%(asctime)s | %(name)s | %(levelname)s | %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    
    consola = logging.StreamHandler(sys.stdout)
    consola.setFormatter(formato)
    logger.addHandler(consola)
    
    if ruta_log:
        archivo = logging.FileHandler(ruta_log, encoding='utf-8')
        archivo.setFormatter(formato)
        logger.addHandler(archivo)
    
    return logger

Uso típico del logger configurado:

logger = crear_logger(__name__, ruta_log='aplicacion.log', nivel='DEBUG')

logger.debug('Inicio de depuración')
logger.info('Proceso iniciado correctamente')
logger.warning('Recurso cercano al límite')
logger.error('Error al acceder a la base de datos')

Al separar la configuración del logger de la lógica de negocio se mantiene el código limpio y se facilita el mantenimiento.

Envío automatizado de correos electrónicos

Para notificaciones por correo se puede utilizar smtplib junto con los módulos de email.mime. La siguiente función soporta cuerpo en texto plano y archivos adjuntos:

import os
import smtplib
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def enviar_correo(destinatario, asunto, cuerpo, remitente, contrasena, adjunto=None):
    mensaje = MIMEMultipart()
    mensaje['From'] = remitente
    mensaje['To'] = destinatario
    mensaje['Subject'] = asunto
    
    mensaje.attach(MIMEText(cuerpo, 'plain', 'utf-8'))
    
    if adjunto and os.path.exists(adjunto):
        parte = MIMEBase('application', 'octet-stream')
        with open(adjunto, 'rb') as archivo:
            parte.set_payload(archivo.read())
        encoders.encode_base64(parte)
        parte.add_header(
            'Content-Disposition',
            f'attachment; filename={os.path.basename(adjunto)}'
        )
        mensaje.attach(parte)
    
    with smtplib.SMTP_SSL('smtp.ejemplo.com', 465) as servidor:
        servidor.login(remitente, contrasena)
        servidor.send_message(mensaje)

Para ejecutar el envío de forma periódica, se puede combinar con el módulo schedule:

import schedule
import time

def tarea_diaria():
    enviar_correo(
        destinatario='usuario@ejemplo.com',
        asunto='Reporte diario',
        cuerpo='Se adjunta el reporte correspondiente.',
        remitente='sistema@ejemplo.com',
        contrasena='secreto',
        adjunto='reporte.xlsx'
    )

schedule.every().day.at('09:00').do(tarea_diaria)

while True:
    schedule.run_pending()
    time.sleep(60)

Etiquetas: Python argparse logging smtplib schedule

Publicado el 6-25 04:03