Volver al inicio

Cargando configuración TOML con Pydantic en Python

Módulo carga settings.toml vía tomllib, almacena en caché con lru_cache y valida modelos Pydantic. Soporta tipado TypeVar para cualquier clase de configuración. Ideal para aplicaciones de producción con separación de lógica y parámetros.

Parseo de settings.toml y validación Pydantic en Python
Advertisement 728x90

Lectura y validación de settings.toml con Pydantic en apps de Python

Este módulo se encarga de leer settings.toml, analizarlo con tomllib, almacenar el resultado en caché mediante lru_cache y validar las secciones usando Pydantic. Mantiene la lógica de configuración separada de los parámetros de tu app, reduce lecturas repetidas al disco y garantiza seguridad de tipos.

from functools import lru_cache
from pathlib import Path
from tomllib import load
from typing import Any, Type, TypeVar

from pydantic import BaseModel, SecretStr

ConfigType = TypeVar("ConfigType", bound=BaseModel)

class BotConfig(BaseModel):
    token: SecretStr

@lru_cache
def parse_config_file() -> dict[str, Any]:
    config_path = Path(__file__).resolve().parent.parent.joinpath("settings.toml")

    if not config_path.exists():
        error = "No se pudo encontrar el archivo de configuración"
        raise ValueError(error)

    with open(config_path, "rb") as file:
        config_data = load(file)

    return config_data

def get_config(model: Type[ConfigType], root_key: str) -> ConfigType:
    config_dict = parse_config_file()

    if root_key not in config_dict:
        error = f"La clave {root_key} no se encontró"
        raise ValueError(error)

    return model.model_validate(config_dict[root_key])

Por qué usar TOML y Pydantic para la configuración

Los archivos TOML son legibles por humanos y se parsean de forma limpia en diccionarios de Python. Las secciones como [bot] se convierten en diccionarios anidados. Pydantic valida la estructura, maneja conversiones de tipos y oculta secretos con SecretStr.

Ejemplo de TOML:

Google AdInline article slot
[bot]
token = "123456:ABCDEF"

El análisis produce {"bot": {"token": "123456:ABCDEF"}}. La validación crea un objeto BotConfig.

El caché con @lru_cache evita lecturas repetidas: la primera llamada parsea, las siguientes usan el caché. Recarga con parse_config_file.cache_clear().

Manejo de rutas con pathlib

Path(__file__).resolve().parent.parent.joinpath("settings.toml") construye una ruta absoluta al archivo en el directorio padre de tu proyecto. exists() verifica la existencia y las propiedades parent simplifican la validación.

Google AdInline article slot
  • Path.joinpath(): añade segmentos de ruta de forma multiplataforma.
  • resolve(): resuelve enlaces simbólicos a rutas absolutas.
  • Abrir en "rb": requerido por tomllib.load() para lectura binaria.

Indicadores de tipo con TypeVar y Pydantic

ConfigType = TypeVar("ConfigType", bound=BaseModel) permite que get_config funcione con cualquier modelo Pydantic, devolviendo una instancia del tipo pasado.

  • Type[ConfigType]: espera una clase de modelo, no una instancia.
  • model_validate(): convierte un diccionario en un objeto validado, lanzando ValidationError en fallos.
  • Any para diccionarios: TOML mezcla tipos (str, int, bool, dict).

Extiéndelo para otras secciones:

class DatabaseConfig(BaseModel):
    host: str
    port: int
    user: str

config = get_config(DatabaseConfig, "database")

Caché y decoradores

@lru_cache almacena resultados por argumentos (ninguno aquí, así que es simple). LRU elimina entradas antiguas al alcanzar el límite, pero una sola ranura basta para la configuración.

Google AdInline article slot

Ventajas:

  • Reduce E/S: lectura al disco solo una vez.
  • Idempotente: múltiples llamadas a get_config comparten un solo análisis.
  • Seguro para hilos: el decorador de la stdlib lo maneja.

Desventajas: Cambios en disco al TOML se ignoran hasta cache_clear().

Estructura del módulo

  • Modelos (BotConfig): independientes de los cargadores.
  • parse_config_file(): analiza el TOML completo.
  • get_config(): extrae y valida una sección.

Esta separación de responsabilidades mejora la testabilidad: simula rutas o cadenas TOML.

Consejos clave:

  • Usa tomllib (Python 3.11+), retrocompatible con tomli para versiones antiguas.
  • Valida siempre la configuración con Pydantic antes de usarla.
  • Almacena el análisis en caché, pero añade soporte para recarga.
  • Guarda secretos en SecretStr para ocultarlos en logs/debug.
  • Construye rutas con pathlib para compatibilidad multiplataforma.

— Editorial Team

Advertisement 728x90

Leer después