Los archivos de configuración permiten cambiar el comportamiento de una aplicación sin modificar el código fuente cada vez que cambia un puerto, una ruta, una opción o un entorno. TOML se ha convertido en un formato popular porque es legible, conserva tipos claros y se transforma de forma natural en diccionarios. Desde Python 3.11, la biblioteca estándar incluye tomllib, un módulo capaz de leer TOML sin instalar dependencias adicionales.
En esta guía aprenderás a usar tomllib en Python para cargar archivos, acceder a tablas anidadas, interpretar fechas, personalizar números decimales, validar campos obligatorios y manejar documentos inválidos. También veremos su relación con pyproject.toml, utilizado por herramientas modernas de empaquetado, lint, formato y pruebas. Para completar el contexto, consulta la guía sobre Poetry y dependencias en Python y el tutorial para crear un paquete instalable.
Qué es TOML
TOML significa “Tom’s Obvious, Minimal Language”. Su objetivo es ofrecer un formato de configuración fácil de leer para las personas y sencillo de convertir a estructuras de datos. Un documento TOML contiene pares clave-valor, tablas, arrays y tipos como enteros, decimales, booleanos, fechas y horas.
app_name = "Panel de ventas"
debug = false
port = 8080
[database]
host = "localhost"
name = "ventas"
timeout = 5.5
[features]
reports = true
exports = ["csv", "xlsx"]Al cargar este archivo, Python genera un diccionario anidado. La especificación oficial de TOML 1.0 explica las reglas para cadenas, tablas, arrays, fechas y nombres de claves.
Cuándo usar tomllib
Utiliza tomllib cuando tu aplicación necesita leer TOML. El módulo no escribe ni edita documentos. Es una buena opción para servicios que cargan configuraciones al iniciar, herramientas de terminal que inspeccionan metadatos y scripts que leen opciones de otras herramientas. Si necesitas conservar comentarios y formato al editar, debes usar una biblioteca diseñada para escritura.
El módulo está disponible desde Python 3.11. Los proyectos compatibles con versiones anteriores suelen usar tomli, cuya API es similar. La versión mínima de Python puede declararse en pyproject.toml. El artículo sobre Ruff en Python muestra otro uso práctico de ese archivo para centralizar configuraciones.
Cómo leer un archivo TOML
Crea un archivo llamado config.toml con el ejemplo anterior. Ábrelo en modo binario y llama a tomllib.load:
import tomllib
with open("config.toml", "rb") as archivo:
config = tomllib.load(archivo)
print(config["app_name"])
print(config["database"]["host"])
print(config["features"]["exports"])El modo rb es obligatorio para load. Evita ambigüedades de codificación y coincide con la API documentada. La documentación oficial de tomllib detalla funciones, excepciones y conversiones de tipos.
El resultado es un diccionario normal. Las cadenas TOML se convierten en str, los enteros en int, los decimales en float, los arrays en listas y las tablas en diccionarios. Por eso puedes aplicar técnicas habituales de acceso y validación.
Leer TOML desde una cadena
Cuando el contenido ya está en memoria, usa tomllib.loads. A diferencia de load, esta función recibe una cadena:
import tomllib
texto = """
name = "worker"
workers = 4
active = true
"""
config = tomllib.loads(texto)
print(config)Esta opción resulta útil en pruebas, configuraciones recibidas desde otro servicio o contenidos leídos por un componente distinto. Aun así, limita el tamaño de entradas no confiables, porque un documento malicioso puede consumir demasiados recursos durante el análisis.
Acceder a valores de forma segura
Usa corchetes para claves obligatorias. Si una clave no existe, Python genera KeyError, algo útil cuando la aplicación no debe arrancar con una configuración incompleta. Para opciones realmente opcionales, utiliza get con un valor predeterminado explícito:
debug = config.get("debug", False)
log_level = config.get("log_level", "INFO")
timeout = config.get("database", {}).get("timeout", 10)No ocultes errores importantes con demasiados valores predeterminados. Un host de base de datos, un entorno o una opción de seguridad debería fallar claramente cuando falta. Separa los campos obligatorios de los opcionales y documenta el esquema.
Validar la configuración
tomllib valida la sintaxis TOML, pero no conoce las reglas de tu aplicación. Un puerto negativo, un host vacío o un entorno desconocido pueden ser TOML válido. Añade validación de dominio después de cargar los datos:
def validar_config(config: dict) -> None:
obligatorias = ["app_name", "database"]
ausentes = [clave for clave in obligatorias if clave not in config]
if ausentes:
raise ValueError(f"Claves ausentes: {', '.join(ausentes)}")
puerto = config.get("port", 8080)
if not 1 <= puerto <= 65535:
raise ValueError("El puerto debe estar entre 1 y 65535")
if not config["database"].get("host"):
raise ValueError("database.host es obligatorio")Los proyectos grandes pueden usar modelos tipados, pero funciones pequeñas y pruebas específicas ya evitan que valores incorrectos lleguen a producción.
Manejar errores de sintaxis
Un documento inválido genera tomllib.TOMLDecodeError. Captura esta excepción cerca del punto donde se lee la configuración y muestra un mensaje útil:
import tomllib
from pathlib import Path
ruta = Path("config.toml")
try:
with ruta.open("rb") as archivo:
config = tomllib.load(archivo)
except FileNotFoundError:
raise SystemExit(f"Archivo no encontrado: {ruta}")
except tomllib.TOMLDecodeError as error:
raise SystemExit(f"TOML inválido en {ruta}: {error}")Evita un except Exception que continúe en silencio. Los errores de configuración suelen requerir un fallo temprano. Registra la ruta y la causa, pero nunca muestres contraseñas, tokens ni todo el diccionario.
Fechas y horas
TOML tiene tipos nativos para fecha, hora y fecha-hora. tomllib los convierte en clases del módulo datetime:
release_date = 2026-07-23
maintenance = 2026-07-23T22:00:00-03:00fecha = config["release_date"]
mantenimiento = config["maintenance"]
print(type(fecha))
print(type(mantenimiento))
print(mantenimiento.tzinfo)Una fecha-hora con desplazamiento contiene información de zona. Una fecha-hora local sin desplazamiento no identifica un instante universal. Si la aplicación programa tareas o compara eventos, define explícitamente la zona horaria esperada.
Usar Decimal en lugar de float
De forma predeterminada, los números decimales TOML se convierten en float. Para importes financieros o valores sensibles a precisión, utiliza el argumento parse_float:
import tomllib
from decimal import Decimal
with open("config.toml", "rb") as archivo:
config = tomllib.load(archivo, parse_float=Decimal)
print(type(config["database"]["timeout"]))La función indicada se ejecuta para cada literal decimal. No puede devolver una lista ni un diccionario. Este mecanismo evita problemas de representación binaria cuando la precisión es importante.
Leer pyproject.toml
pyproject.toml centraliza metadatos y configuraciones de numerosas herramientas Python. Puedes leer campos controlados por tu proyecto:
import tomllib
with open("pyproject.toml", "rb") as archivo:
proyecto = tomllib.load(archivo)
nombre = proyecto["project"]["name"]
version = proyecto["project"]["version"]
print(f"{nombre} {version}")No todos los proyectos usan las mismas tablas. Los estándares modernos suelen utilizar [project], mientras cada herramienta guarda opciones bajo su propio espacio. Lee únicamente los campos que tu programa entiende. Para la distribución, consulta cómo publicar un paquete en PyPI.
Separar entornos y secretos
Una estrategia práctica consiste en guardar valores no secretos en TOML e inyectar credenciales mediante variables de entorno o un gestor de secretos. TOML puede definir comportamiento para desarrollo, pruebas y producción sin almacenar contraseñas reales:
[environments.development]
debug = true
log_level = "DEBUG"
[environments.production]
debug = false
log_level = "WARNING"entorno = "production"
opciones = config["environments"][entorno]No subas credenciales de producción al repositorio. Si el equipo necesita un archivo local, ignóralo en Git y proporciona un ejemplo seguro con marcadores.
Probar la lectura de configuración
Como loads acepta texto, las pruebas unitarias pueden evitar archivos temporales:
import tomllib
def test_config_minima():
texto = """
app_name = "prueba"
port = 9000
[database]
host = "localhost"
"""
config = tomllib.loads(texto)
validar_config(config)
assert config["port"] == 9000Añade casos para claves ausentes, tipos incorrectos, puertos inválidos, entornos no admitidos y TOML malformado. Así, los cambios del esquema no rompen el sistema de forma silenciosa.
Buenas prácticas
- Abre archivos en modo binario al usar
load. - Usa
loadspara cadenas y pruebas. - Valida reglas de negocio después de analizar la sintaxis.
- No registres secretos ni la configuración completa.
- Define valores predeterminados solo para opciones opcionales.
- Limita el tamaño de entradas no confiables.
- Documenta el esquema con un archivo de ejemplo seguro.
- Centraliza configuraciones compatibles en
pyproject.toml.
Conclusión
tomllib en Python proporciona una forma directa de leer TOML con la biblioteca estándar. Convierte tablas, arrays, números, booleanos y fechas en tipos normales de Python, genera una excepción específica ante sintaxis inválida y permite personalizar la conversión decimal.
El análisis es solo la primera capa. Una configuración fiable también necesita validación, errores claros, protección de secretos, control de zonas horarias y pruebas. Con estas prácticas, TOML se convierte en una interfaz limpia entre el código y los entornos donde se ejecuta.







