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