Estándares de Estructura de Proyectos en Python

Estructura de Directorios Recomendada

Para proyectos Python, se aconseja organizar el código de la siguiente manera:


mi_proyecto/
├── bin/                        # Ejecutables
│   ├── __init__.py
│   └── iniciar.py             # Punto de entrada principal
├── config/                    # Archivos de configuración
│   ├── conf.ini               # Configuración en formato INI
│   ├── __init__.py
│   ├── logging_cfg.py         # Configuración de logs
│   └── parametros.py          # Definiciones globales
├── nucleo/                    # Lógica central
│   ├── procesamiento.py       # Funcionalidades clave
│   └── __init__.py
├── datos/                     # Almacenamiento de datos
├── utilidades/                # Bibliotecas auxiliares
│   ├── __init__.py
│   └── lector_ini.py          # Herramienta para leer INI
└── logs/                      # Registros de ejecución
    └── app.log               # Archivo de log

Script de Inicio

El archivo iniciar.py configura el entorno y ejecuta la alpicación:


import sys, os

raiz = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(raiz)

from nucleo import procesamiento
from config import logging_cfg

if __name__ == '__main__':
    logging_cfg.configurar_logs()
    procesamiento.ejecutar()

Configuración INI

Ejemplo de archivo conf.ini para parámetros de la aplicación:


[DEFAULT]
tiempo_sesion = 3600

[usuario1]
clave = secreta123
saldo = 50000

Gestión de Logs

El módulo logging_cfg.py define formatos y hendlers para el registro de eventos:


import os, logging.config

formato_estandar = '[%(asctime)s][%(process)d][%(name)s][%(levelname)s]: %(message)s'
formato_simple = '[%(levelname)s] %(asctime)s - %(message)s'

directorio_logs = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'logs')
os.makedirs(directorio_logs, exist_ok=True)

ruta_log = os.path.join(directorio_logs, 'app.log')

CONFIG_LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'detallado': {'format': formato_estandar},
        'breve': {'format': formato_simple},
    },
    'handlers': {
        'consola': {
            'class': 'logging.StreamHandler',
            'formatter': 'breve',
            'level': 'DEBUG',
        },
        'archivo': {
            'class': 'logging.FileHandler',
            'filename': ruta_log,
            'formatter': 'detallado',
            'level': 'INFO',
            'encoding': 'utf-8',
        },
    },
    'root': {
        'handlers': ['consola', 'archivo'],
        'level': 'DEBUG',
    },
}

def configurar_logs():
    logging.config.dictConfig(CONFIG_LOGGING)
    logger = logging.getLogger(__name__)
    logger.info('Sistema de logs inicializado')

Parámetros Globales

El archivo parametros.py centraliza rutas y constantes:


import os

RUTA_CONF = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf.ini')
RUTA_DATOS = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'datos')
TIEMPO_SESION = 1800  # en segundos

Lógica Principal

En procesamiento.py, se implementa la autenticación y funcionalidades de negocio:


import time, logging
from config import parametros
from utilidades import lector_ini

datos_config = lector_ini.leer_archivo(parametros.RUTA_CONF)
logger = logging.getLogger(__name__)

sesion_actual = {'usuario': None, 'timestamp': None, 'limite': parametros.TIEMPO_SESION}

def requiere_autenticacion(funcion):
    def envoltura(*args, **kwargs):
        if sesion_actual['usuario']:
            if time.time() - sesion_actual['timestamp'] < sesion_actual['limite']:
                return funcion(*args, **kwargs)
        usuario = input('Nombre de usuario: ')
        contrasena = input('Contraseña: ')
        if datos_config.has_section(usuario):
            if contrasena == datos_config.get(usuario, 'clave'):
                logger.info(f'Autenticación exitosa para {usuario}')
                sesion_actual['usuario'] = usuario
                sesion_actual['timestamp'] = time.time()
                return funcion(*args, **kwargs)
        logger.error('Credenciales inválidas')
    return envoltura

@requiere_autenticacion
def realizar_compra():
    print('Procesando compra...')

@requiere_autenticacion
def ejecutar():
    opciones = '''
    1. Comprar
    2. Consultar saldo
    3. Transferir
    '''
    print(opciones)
    while True:
        seleccion = input('Seleccione opción: ').strip()
        if seleccion == '1':
            realizar_compra()
            break

Utilidad para Lectura de INI

El módulo lector_ini.py ecnapsula la lectura de archivos de configuración:


import configparser
import logging

logger = logging.getLogger(__name__)

def leer_archivo(ruta):
    parser = configparser.ConfigParser()
    try:
        parser.read(ruta)
        logger.debug(f'Configuración cargada desde {ruta}')
        return parser
    except Exception as e:
        logger.error(f'Error al leer {ruta}: {e}')
        raise

Etiquetas: Python estructura de proyecto logging configparser decoradores

Publicado el 7-15 17:50