El módulo importlib.metadata lee metadatos de distribuciones Python instaladas sin importar sus paquetes. Permite consultar versiones, nombres, autores, requisitos, archivos instalados, entry points y relaciones entre distribuciones y módulos importables. Es útil en CLIs de diagnóstico, sistemas de plugins, informes de soporte, comprobaciones de compatibilidad, inventarios y observabilidad.
Una distribución instalada no es lo mismo que un módulo importable. Un nombre usado con pip install puede exponer un paquete con otro nombre en import. La API trabaja con metadatos de instalación, normalmente almacenados en directorios .dist-info o, en instalaciones antiguas, .egg-info.
Consulta una versión instalada
La función version() devuelve la versión declarada por una distribución.
from importlib.metadata import version
print(version("requests"))
Usa el nombre de la distribución, que puede ser diferente del nombre importado.
Maneja PackageNotFoundError
Cuando la distribución no está instalada, la API lanza PackageNotFoundError.
from importlib.metadata import PackageNotFoundError, version
try:
version_plugin = version("mi-plugin")
except PackageNotFoundError:
version_plugin = None
Distingue paquete ausente, metadatos dañados, entorno incorrecto y consulta realizada con otro intérprete.
No importes solo para obtener la versión
Muchas bibliotecas exponen __version__, pero importarlas puede ser lento o producir side effects.
importlib.metadata.version() lee la información instalada sin ejecutar código del paquete.
Normalización de nombres
Las herramientas de packaging normalizan nombres siguiendo reglas del ecosistema. Guiones, underscores, mayúsculas y separadores repetidos pueden considerarse equivalentes.
Usa el nombre canónico almacenado en los metadatos para informes y no implementes una normalización propia incompleta.
Lee campos con metadata
metadata(name) devuelve una estructura parecida a headers de e-mail.
from importlib.metadata import metadata
meta = metadata("requests")
print(meta["Name"])
print(meta["Version"])
print(meta.get("Summary"))
No todos los campos son obligatorios ni están completos en todas las distribuciones.
Campos repetidos
Classifiers, requisitos y project URLs pueden aparecer varias veces.
Utiliza los métodos de acceso múltiple de la estructura en vez de suponer que una sola string contiene todos los valores.
Descripciones largas
Los metadatos pueden incluir una descripción completa o README.
No registres el objeto entero en producción. Selecciona los campos necesarios y limita tamaño.
Consulta requisitos declarados
requires(name) devuelve strings de requisitos de la distribución.
from importlib.metadata import requires
for requisito in requires("requests") or []:
print(requisito)
Las strings pueden incluir versiones, extras, referencias directas y environment markers.
Analiza requisitos con packaging
No dividas las strings manualmente. Usa packaging.requirements.Requirement.
from packaging.requirements import Requirement
req = Requirement('urllib3<3,>=1.21.1')
print(req.name, req.specifier)
Evalúa los markers en el entorno objetivo, no necesariamente en la máquina que genera el informe.
Declarado no significa importado
Un requisito puede ser opcional, específico de plataforma, activado por un extra o utilizado por una feature concreta.
Combina metadatos con tests y análisis de imports para saber qué módulos se cargan realmente.
Lista archivos instalados
files(name) devuelve archivos registrados por la distribución.
from importlib.metadata import files
for archivo in files("requests") or []:
print(archivo)
El resultado puede ser None si la instalación no posee un registro completo.
Objetos PackagePath
Los elementos devueltos pueden localizar su ruta instalada.
for item in files("mi-paquete") or []:
ruta = item.locate()
print(ruta)
Comprueba que la ruta exista. Instalaciones editables o modificadas pueden apuntar a lugares inesperados.
Hashes y tamaños
Los registros pueden incluir hash y tamaño, según cómo se instaló la distribución.
Sirven para auditoría, pero no sustituyen firmas, procedencia ni una política completa de integridad.
Usa distribution para detalles
distribution(name) devuelve un objeto Distribution.
from importlib.metadata import distribution
dist = distribution("requests")
print(dist.version)
print(dist.metadata["Name"])
El objeto centraliza metadatos, requisitos, archivos y entry points.
Localiza un archivo instalado
Un Distribution puede localizar un path relativo.
ruta = dist.locate_file("requests/__init__.py")
Valida el resultado. Editable installs y layouts especiales pueden resolver fuera de site-packages.
Enumera distribuciones
distributions() recorre las distribuciones visibles para el intérprete actual.
from importlib.metadata import distributions
for dist in distributions():
print(dist.metadata.get("Name"), dist.version)
Ordena la salida y selecciona campos estables para crear inventarios reproducibles.
Inventario del entorno
Un inventario útil incluye nombre canónico, versión, origen y, cuando corresponda, hashes de archivos críticos.
No publiques todo el inventario por defecto. Revela componentes internos y ayuda a identificar dependencias vulnerables.
Usa el entorno virtual correcto
La API ve paquetes disponibles para el intérprete actual.
Ejecuta el diagnóstico con el mismo sys.executable de la aplicación. El Python global y el venv pueden tener inventarios distintos.
Instalaciones editables
Una editable install posee metadatos, pero el código puede estar en un checkout fuera de site-packages.
Los informes deberían distinguir artefactos de release y entornos de desarrollo.
Mapea paquetes importables a distribuciones
packages_distributions() relaciona nombres top-level de importación con distribuciones.
from importlib.metadata import packages_distributions
mapa = packages_distributions()
print(mapa.get("bs4"))
Un módulo puede ser proporcionado por más de una distribución, especialmente en namespace packages.
Nombre de módulo y distribución
Este mapping ayuda a relacionar los resultados de modulefinder en Python con versiones instaladas.
No deduzcas la distribución cambiando mayúsculas o reemplazando underscores.
Descubre entry points
Los entry points declaran extensiones, comandos y plugins instalados.
from importlib.metadata import entry_points
plugins = entry_points(group="miapp.plugins")
for ep in plugins:
print(ep.name, ep.value)
La API de selección evolucionó entre versiones. Usa la interfaz compatible con la versión mínima del proyecto.
Grupos de entry points
Un grupo crea un namespace lógico como console_scripts o miempresa.miapp.plugins.
Elige un nombre específico controlado por el proyecto para evitar conflictos.
Objetos EntryPoint
Cada entry point posee nombre, grupo y valor. El valor suele indicar módulo y objeto.
for ep in plugins:
print(ep.group, ep.name, ep.value)
Puedes inspeccionar estos datos sin importar el plugin.
Carga un entry point
EntryPoint.load() importa el módulo y devuelve el objeto declarado.
factory = ep.load()
plugin = factory()
Esta operación ejecuta código de importación y puede fallar o producir side effects.
No cargues todos los plugins automáticamente
Filtra por configuración, autorización, compatibilidad, distribución y versión antes de llamar load().
Plugins de terceros pueden necesitar proceso separado y privilegios reducidos.
Entry points duplicados
Dos distribuciones pueden declarar el mismo nombre dentro del mismo grupo.
Define una política: error, prioridad configurada o selección explícita por distribución. No dependas del orden del entorno.
Compatibilidad de la API
Versiones anteriores devolvían colecciones diferentes y usaban otros métodos de selección.
Centraliza la compatibilidad y prueba cada Python soportado.
Console scripts
El grupo console_scripts declara comandos creados por herramientas de packaging.
Inspeccionarlos ayuda a diagnosticar por qué una CLI no fue instalada o qué callable debería ejecutar.
No trates console_scripts como plugins comunes
Un entry point de consola está diseñado para ejecutarse como comando con argumentos y exit status.
Para comportamiento fiel, usa el ejecutable instalado o un subprocess.
Compara versiones correctamente
Usa packaging.version.Version, no comparación de strings.
from packaging.version import Version
if Version(version("mi-plugin")) < Version("2.0"):
raise RuntimeError("plugin antiguo")
La comparación lexicográfica interpreta versiones como 10 y 2 de forma incorrecta.
Environment markers
Los markers pueden depender de versión de Python, sistema, implementación, arquitectura y extras.
Evalúalos con la biblioteca packaging y el entorno donde se ejecutará el software.
Extras
Los extras representan grupos opcionales como paquete[postgres].
Los metadatos muestran requisitos declarados y distribuciones instaladas, pero no siempre prueban qué extra pretendió instalar el usuario.
Metadatos de licencia
Campos y classifiers de licencia ayudan en inventarios, pero pueden faltar o estar desactualizados.
Para compliance, usa herramientas dedicadas y revisa los textos reales.
URLs del proyecto
Los metadatos pueden incluir homepage, repositorio, documentación e issue tracker.
No confíes automáticamente en URLs de distribuciones desconocidas.
Cache de aplicación
Las consultas repetidas pueden cachearse cuando el entorno es inmutable.
Instalar o eliminar paquetes durante el proceso vuelve antiguo el cache. Las imágenes de producción inmutables simplifican la política.
Rendimiento
Consultar una versión es barato, pero enumerar todas las distribuciones y archivos puede ser costoso.
Genera inventarios grandes al startup, durante diagnósticos o bajo demanda, no en cada request.
No dependas del orden
El orden de distribuciones, archivos y entry points no debería definir comportamiento.
Ordena explícitamente y resuelve conflictos mediante una política documentada.
Metadatos incompletos o dañados
Instalaciones antiguas, manuales o corruptas pueden carecer de registros esperados.
Usa fallbacks claros y marca el entorno como no verificable si faltan campos críticos.
Biblioteca estándar
La mayoría de módulos standard library no corresponden a distribuciones instaladas independientes.
Usa la versión de Python y paths de sysconfig para identificarlos.
Dependencias vendorizadas
Un proyecto puede copiar código de terceros dentro de su paquete sin metadatos separados.
importlib.metadata no detecta automáticamente esos componentes como distribuciones independientes.
Containers
Genera el inventario desde la imagen final de runtime. Un multi-stage build puede instalar paquetes en una etapa diferente.
Valida el manifiesto y el entorno que realmente se inicia.
SBOM
Los metadatos son una entrada valiosa para una Software Bill of Materials, pero una SBOM completa también incluye bibliotecas nativas, paquetes del sistema, código vendorizado e integridad.
Usa formatos y herramientas de SBOM adecuados.
Seguridad de endpoints de diagnóstico
Las versiones ayudan a operadores, pero también revelan el stack a atacantes.
Protege endpoints con autenticación y autorización, y no publiques inventarios completos.
Metadatos no son confianza
Nombre, autor, versión y URLs son declaraciones del paquete instalado.
Verifica origen, hashes, firmas e índices según la política de supply chain.
Aislamiento de plugins
Los entry points facilitan discovery, pero load() ejecuta código.
Carga solo plugins aprobados y considera procesos separados para extensiones de riesgo.
Observabilidad
Registra versiones de un conjunto pequeño de componentes críticos en logs de startup o métricas con cardinalidad controlada.
No añadas todas las distribuciones como labels.
Informes de soporte
Un comando de diagnóstico puede mostrar Python, plataforma, versión de aplicación y dependencias seleccionadas.
Ofrece redacción de paths, nombres internos y detalles del sistema antes de compartir.
Integración con pkgutil
pkgutil descubre módulos ofrecidos por importers, mientras importlib.metadata describe distribuciones y plugins declarados.
Consulta pkgutil en Python.
Integración con importlib.resources
Después de identificar un plugin, accede a sus recursos mediante el anchor de su paquete.
Consulta importlib.resources en Python.
Pruebas
Crea distribuciones fixture o instala wheels de test. Cubre paquete ausente, versión, requisitos, files inexistente, entry points duplicados, editable install y namespace packages.
No dependas de lo instalado en la máquina del desarrollador.
Compatibilidad con backport
En Pythons antiguos, el paquete externo importlib_metadata proporciona la API y muchas mejoras recientes.
Centraliza imports y diferencias en un módulo de compatibilidad.
Errores comunes
Los fallos frecuentes son usar nombre de importación en vez de distribución, importar para leer versión, comparar versiones como strings, cargar todos los plugins, depender del orden de entry points, asumir metadatos completos, enumerar todo por request y exponer inventarios públicamente.
Conclusión
importlib.metadata consulta versiones, requisitos, archivos, distribuciones y entry points sin importar el código correspondiente. Usa version() para comprobaciones simples, distribution() para detalles y entry_points() para plugins declarados.
Trata los metadatos como información y no como prueba de confianza, relaciona correctamente módulos y distribuciones y carga plugins solo después de validar. Consulta la documentación oficial de importlib.metadata y modulefinder en Python.







