importlib.metadata: consulta versiones y dependencias

Actualizado el: 20/08/2026
Tempo de leitura: 6 minutos
Paquete de software que representa metadatos consultados con importlib.metadata en Python

El módulo importlib.metadata en Python permite consultar información de paquetes de distribución instalados en el entorno. Puede devolver versiones, metadatos, dependencias declaradas, archivos instalados, entry points y la relación entre nombres usados en import y nombres utilizados por herramientas como pip.

La distinción es importante. La distribución PyYAML proporciona el módulo importable yaml. Una distribución puede ofrecer varios paquetes importables y un namespace package puede estar formado por varias distribuciones. No presupongas una correspondencia uno a uno.

Distribución frente a paquete importable

Una distribución es la unidad instalada por herramientas de packaging y suele incluir metadatos .dist-info o .egg-info. Un import package es el nombre utilizado en el código.

from importlib.metadata import packages_distributions

mapa = packages_distributions()
print(mapa.get('yaml'))
# normalmente ['PyYAML']

El mapping ayuda en auditorías y mensajes de soporte. Algunas instalaciones editables no proporcionan todos los nombres de nivel superior, así que puede faltar información.

Consultar la versión instalada

version() devuelve la versión de la distribución como texto.

from importlib.metadata import version

print(version('pip'))

No conviertas el resultado a float. Las versiones pueden contener varios componentes, pre-releases e identificadores locales. Para comparar, usa una implementación compatible con PEP 440.

Tratar PackageNotFoundError

Las consultas a una distribución no instalada generan PackageNotFoundError.

from importlib.metadata import PackageNotFoundError, version

try:
    actual = version('mi-plugin')
except PackageNotFoundError:
    actual = None

Distingue una distribución ausente de un import roto. Los metadatos pueden existir aunque el módulo falle por una biblioteca nativa o configuración.

Leer metadatos completos

metadata() devuelve un objeto parecido a mapping con campos de Core Metadata.

from importlib.metadata import metadata

meta = metadata('pip')
print(meta['Name'])
print(meta['Version'])
print(meta.get('Requires-Python'))
print(meta.get_all('Project-URL'))

Campos como Classifier, Project-URL y Requires-Dist pueden repetirse. Usa get_all() cuando necesites todos los valores.

Metadatos compatibles con JSON

La propiedad json presenta una forma compatible con PEP 566.

datos = metadata('pip').json
print(datos.get('requires_python'))

Los valores siguen procediendo del paquete instalado. Valida campos y tipos antes de enviarlos a APIs o informes externos.

Consultar dependencias declaradas

requires() devuelve los requisitos declarados por una distribución.

from importlib.metadata import requires

requisitos = requires('mi-paquete') or []
for requisito in requisitos:
    print(requisito)

Las cadenas pueden incluir markers de plataforma, versión de Python y extras. Describen requisitos declarados, no confirman que el entorno sea consistente.

Listar archivos instalados

files() devuelve objetos PackagePath con tamaño, hash y distribución cuando esos datos existen.

from importlib.metadata import files

items = files('pip')
if items is not None:
    for item in list(items)[:10]:
        print(item, item.size, item.hash)

La función puede devolver None si la instalación no incluye el archivo que registra la lista. Protege siempre la iteración.

Localizar un archivo físico

PackagePath.locate() resuelve la ubicación instalada.

for item in files('pip') or []:
    if str(item).endswith('__init__.py'):
        print(item.locate())
        break

No muestres rutas absolutas sin necesidad: pueden revelar usuarios, entornos virtuales y estructura del servidor.

Hashes registrados

Cuando RECORD contiene hash y tamaño, PackagePath los expone. Puedes comparar el contenido instalado con el valor registrado.

No todos los archivos tienen hash y los metadatos locales no equivalen a una firma externa. Quien pueda alterar archivo y RECORD puede modificar ambos.

Entry points instalados

entry_points() devuelve objetos EntryPoint. Selecciona por grupo y opcionalmente por nombre.

from importlib.metadata import entry_points

plugins = entry_points(group='mi_app.plugins')
for plugin in plugins:
    print(plugin.name, plugin.value, plugin.dist.name)

Los grupos son convenciones definidas por autores. console_scripts es un ejemplo común; los sistemas propios deberían usar un nombre claro.

Cargar un entry point

EntryPoint.load() importa el módulo y resuelve el objeto configurado.

(plugin,) = entry_points(
    group='mi_app.plugins',
    name='csv',
)

clase = plugin.load()

Cargar ejecuta imports y puede producir efectos. Inspecciona y valida metadatos antes de cargar plugins aprobados.

Inspeccionar sin cargar

Las propiedades module, attr, extras, name, group, value y dist permiten auditar sin importar el destino.

for ep in entry_points(group='console_scripts'):
    print(ep.name, ep.module, ep.attr)

Los metadatos siguen siendo suministrados por paquetes instalados y no deben considerarse confiables solo por existir.

Cambios de API

Versiones antiguas devolvían estructuras diferentes. En Python moderno, entry_points() devuelve una colección EntryPoints seleccionable. Desde Python 3.13, EntryPoint ya no tiene interfaz de tupla.

Las bibliotecas que soportan versiones antiguas deben probar compatibilidad o usar el backport importlib_metadata con una versión controlada.

Obtener una Distribution

distribution() devuelve un objeto con versión, metadatos, archivos, requisitos y entry points.

from importlib.metadata import distribution

dist = distribution('pip')
print(dist.version)
print(dist.metadata.get('License'))
print(len(dist.entry_points))

Instancias distintas no comparan necesariamente como iguales aunque representen la misma instalación. Compara nombre normalizado y versión.

Origen de instalaciones editables

Desde Python 3.13, Distribution.origin puede mostrar información PEP 610 de paquetes editables.

dist = distribution('mi-paquete')
if dist.origin is not None:
    print(dist.origin.url)

El origen puede contener rutas locales. Normaliza o elimina valores sensibles en informes compartidos.

Mapear imports a distribuciones

packages_distributions() devuelve listas porque un namespace package puede estar formado por varias distribuciones.

mapa = packages_distributions()
for paquete, distribuciones in sorted(mapa.items()):
    if len(distribuciones) > 1:
        print(paquete, distribuciones)

Esto complementa modulefinder en Python, que sigue imports desde un script, y pkgutil, que lista módulos disponibles.

Auditar el entorno

distributions() recorre las distribuciones instaladas.

from importlib.metadata import distributions

for dist in sorted(
    distributions(),
    key=lambda d: d.metadata['Name'].lower(),
):
    print(dist.metadata['Name'], dist.version)

Los entornos grandes pueden incluir instalaciones editables, metadatos incompletos y duplicados aparentes. Registra versión de Python y ubicación del entorno.

Generar inventario JSON

import json
from importlib.metadata import distributions

inventario = []
for dist in distributions():
    inventario.append({
        'name': dist.metadata['Name'],
        'version': dist.version,
        'requires_python': dist.metadata.get('Requires-Python'),
    })

print(json.dumps(inventario, ensure_ascii=False, indent=2))

No incluyas descripciones largas ni rutas absolutas por defecto. Un SBOM completo requiere otros campos y formatos.

Comparar versiones mínimas

Usa un parser correcto en lugar de comparación textual.

from importlib.metadata import version
from packaging.version import Version

if Version(version('mi-plugin')) < Version('2.0'):
    raise RuntimeError('Actualiza mi-plugin')

packaging es una dependencia externa. Comparaciones como '10' < '2' son incorrectas.

Política de confianza para plugins

Cualquier distribución instalada puede registrar un entry point. Verifica proveedor, versión, configuración y permisos.

APROBADOS = {'plugin-oficial', 'plugin-interno'}

for ep in entry_points(group='mi_app.plugins'):
    if ep.dist.name not in APROBADOS:
        continue
    cargar_plugin(ep)

En sistemas sensibles, instala plugins desde un repositorio controlado y con hashes fijados.

Los metadatos no prueban integridad

Nombre, versión, licencia y URLs son declaraciones del paquete. No garantizan autenticidad, seguridad ni compatibilidad. Combina metadatos con fuente confiable, hashes, firmas y pruebas.

Distribuciones ZIP y providers personalizados

Por defecto, los metadatos pueden estar en el sistema de archivos o en ZIPs de sys.path. Importers personalizados pueden implementar find_distributions() y devolver objetos Distribution.

Un provider debe respetar filtros de nombre y ruta. Prueba cuidadosamente el descubrimiento personalizado.

Diferencias en sys.path

El descubrimiento de metadatos no interpreta todos los valores de sys.path igual que el import normal. Bytes se ignoran y objetos pathlib.Path pueden aceptarse incidentalmente.

Mantén sys.path convencional y usa sysconfig en Python para rutas explícitas.

Cambios del entorno

Instalar o eliminar paquetes dentro de un proceso activo puede dejar observaciones obsoletas. En producción, prepara el entorno antes de iniciar workers y reinícialos después de actualizar.

Probar código basado en metadatos

Evita depender de todos los paquetes instalados en la máquina del desarrollador. Abstrae las funciones e inyecta dobles.

def version_instalada(nombre, obtener_version=version):
    try:
        return obtener_version(nombre)
    except PackageNotFoundError:
        return None

Prueba distribuciones ausentes, versiones extrañas, listas de archivos vacías y entry points no aprobados.

Errores frecuentes

  • Confundir distribución con import.
  • Comparar versiones como cadenas simples.
  • Cargar todos los entry points automáticamente.
  • Suponer que files() nunca devuelve None.
  • Exponer rutas de instalaciones editables.
  • Tratar metadatos como prueba de integridad.
  • Depender de la API antigua de entry points.

Buenas prácticas

  • Consulta mediante nombres de distribución.
  • Trata PackageNotFoundError.
  • Usa get_all() para campos repetidos.
  • Valida entry points antes de cargar.
  • Oculta rutas y orígenes en informes.
  • Compara versiones con un parser adecuado.
  • Reinicia procesos después de cambios.

Conclusión

importlib.metadata en Python proporciona una vista estructurada de las distribuciones instaladas: versiones, requisitos, archivos, metadatos, entry points y relación con paquetes importables.

Usa estos datos para diagnóstico, plugins e inventarios, pero no confundas declaración con confianza. Consulta la documentación oficial de importlib.metadata y las especificaciones de Core Metadata de PyPA.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Desarrollador configurando un servidor HTTPS y certificado TLS con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crea un servidor HTTPS local en Python

    Aprende HTTPSServer en Python para crear servicios HTTPS locales, configurar certificados, usar hilos y comprender sus límites.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026
    Archivos protegidos que representan extracción segura de TAR con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extrae TAR con seguridad

    Aprende tarfile extraction_filter en Python para extraer archivos TAR con validación, seguridad y control de rutas.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026
    Código Python mostrando avisos controlados con catch_warnings
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    catch_warnings: captura warnings en pruebas Python

    Aprende catch_warnings en Python para capturar, probar y controlar avisos con filtros específicos y alcance seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código Python que representa referencias persistentes de pickle
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pickle persistent_id: serializa referencias externas

    Aprende pickle persistent_id en Python para referencias externas estables, validación, seguridad, rendimiento y compatibilidad.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código binario que representa buffers y vistas de memoria en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    memoryview.count: cuenta valores sin copiar buffers

    Aprende memoryview.count en Python para contar bytes y valores en buffers sin copias, con formatos, límites y buenas prácticas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python y anotaciones de tipos
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evita imports circulares en anotaciones

    Aprende annotationlib en Python para inspeccionar anotaciones diferidas, evitar imports circulares y crear herramientas seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026