importlib.metadata en Python: paquetes

Publicado el: 14/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

    Código en ejecución que representa módulos y rutas ejecutados con runpy en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    runpy en Python: ejecuta módulos

    Aprende runpy en Python para ejecutar módulos, scripts, directorios y archivos ZIP, controlar namespaces y evitar problemas de seguridad y

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026
    Paquete de software que representa descubrimiento de módulos con pkgutil en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pkgutil en Python: descubre paquetes

    Aprende pkgutil en Python para descubrir módulos, recorrer paquetes, resolver objetos, extender rutas y acceder a recursos con seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    13/08/2026
    Red de código binario que representa el grafo de imports analizado con modulefinder en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    modulefinder en Python: analiza imports

    Aprende modulefinder en Python para mapear imports, detectar módulos ausentes, personalizar rutas y auditar dependencias con límites claros.

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026
    Archivadores organizados que representan aplicaciones empaquetadas en archivos .pyz con zipapp en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    zipapp en Python: crea ejecutables .pyz

    Aprende zipapp en Python para empaquetar aplicaciones en archivos .pyz, definir entry points, incluir dependencias y distribuir con seguridad.

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026
    Editor de código que representa autocompletado de REPL con rlcompleter en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    rlcompleter en Python: autocompletar REPL

    Aprende rlcompleter en Python para añadir autocompletado a REPLs, consolas y editores, controlar namespaces y evitar efectos secundarios.

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026
    Ventana de terminal que representa una consola interactiva creada con cmd en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    cmd en Python: crea consolas interactivas

    Aprende cmd en Python para crear consolas interactivas con comandos, ayuda, historial, autocompletado, pruebas y control seguro de acciones.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026