importlib.metadata: consulte versões e dependências

Atualizado em: 20/08/2026
Tempo de leitura: 7 minutos
Caixa de software representando metadados de pacotes consultados com importlib.metadata no Python

O módulo importlib.metadata no Python acessa informações de pacotes de distribuição instalados no ambiente. Ele permite consultar versão, metadados, dependências declaradas, arquivos instalados, entry points e a relação entre nomes usados em import e nomes usados por ferramentas como pip.

Essa distinção é importante. O pacote instalado chamado PyYAML, por exemplo, fornece o módulo importável yaml. Uma distribuição pode oferecer vários pacotes importáveis, e um namespace package pode ser fornecido por várias distribuições. Portanto, não presuma uma relação 1:1.

Distribuição não é módulo importável

Uma distribuição é a unidade instalada por ferramentas de empacotamento, normalmente acompanhada de diretórios .dist-info ou .egg-info. Um import package é o nome utilizado no código.

from importlib.metadata import packages_distributions

mapa = packages_distributions()
print(mapa.get('yaml'))
# ['PyYAML'] em um ambiente típico

O mapeamento é especialmente útil em auditorias e mensagens de erro. Instalações editáveis podem não fornecer todos os nomes de topo, então trate ausências como resultado possível.

Consultar a versão instalada

version() devolve a versão da distribuição como string.

from importlib.metadata import version

print(version('pip'))

Não converta versões com float. Versões podem conter múltiplos componentes, pré-releases e identificadores locais. Quando precisar comparar, use uma implementação compatível com as regras de versionamento da PyPA.

Tratar PackageNotFoundError

Consultas a uma distribuição não instalada levantam PackageNotFoundError.

from importlib.metadata import PackageNotFoundError, version

try:
    atual = version('meu-plugin')
except PackageNotFoundError:
    atual = None

Diferencie pacote ausente de import quebrado. A distribuição pode estar instalada, mas seu módulo pode falhar por dependência nativa ou configuração.

Ler metadados completos

metadata() retorna um objeto semelhante a mapping, com campos definidos pelas especificações 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'))

Alguns campos podem ocorrer várias vezes, como Classifier, Project-URL e Requires-Dist. Use get_all() quando a multiplicidade importa.

Metadados em JSON

A propriedade json apresenta os metadados em forma compatível com PEP 566.

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

O conteúdo ainda vem do pacote instalado. Valide tipos e campos antes de enviar a APIs ou relatórios externos.

Consultar dependências declaradas

requires() devolve os requisitos declarados pela distribuição.

from importlib.metadata import requires

requisitos = requires('meu-pacote') or []
for requisito in requisitos:
    print(requisito)

As strings podem conter markers de plataforma, versão de Python e extras. Elas descrevem requisitos declarados, não confirmam que o ambiente está consistente. Uma dependência pode estar ausente ou possuir versão incompatível.

Listar arquivos instalados

files() retorna objetos PackagePath com informações de tamanho, hash e distribuição.

from importlib.metadata import files

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

A função pode retornar None quando a instalação não contém o arquivo de metadados que registra a lista. Sempre proteja a iteração.

Localizar um arquivo físico

PackagePath.locate() resolve a localização instalada.

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

Não exponha caminhos absolutos sem necessidade, pois podem revelar usuários, ambientes virtuais e estrutura de servidores.

Verificar hashes registrados

Quando o arquivo RECORD contém hash e tamanho, PackagePath expõe essas informações. É possível comparar o conteúdo instalado com o valor registrado.

Nem todos os arquivos possuem hash, e os metadados locais não substituem uma assinatura externa confiável. Um invasor com permissão para alterar pacote e RECORD pode modificar ambos.

Entry points instalados

entry_points() retorna objetos EntryPoint. Selecione por grupo e, opcionalmente, nome.

from importlib.metadata import entry_points

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

Grupos são nomes convencionados pelos autores. console_scripts é um exemplo comum, mas sistemas próprios devem usar um namespace claro.

Carregar um entry point

EntryPoint.load() importa o módulo e resolve o objeto indicado.

plugins = entry_points(
    group='meu_app.plugins',
    name='csv',
)

(plugin,) = plugins
classe = plugin.load()

Carregar executa imports e pode produzir efeitos colaterais. Descubra e valide metadados primeiro; carregue somente plugins aprovados.

Inspecionar sem carregar

As propriedades module, attr, extras, name, group e value permitem analisar um entry point sem importar.

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

Essa fase é adequada para auditoria e allowlists. Mesmo assim, os metadados foram instalados por um pacote e não devem ser considerados confiáveis apenas por estarem presentes.

Mudanças da API de entry_points()

Versões antigas retornavam estruturas diferentes. Em Python moderno, entry_points() retorna um objeto EntryPoints selecionável. Desde Python 3.13, EntryPoint não oferece mais comportamento de tupla.

Bibliotecas que suportam versões antigas devem testar compatibilidade ou usar o backport importlib_metadata com uma faixa conhecida.

Obter uma Distribution

distribution() retorna um objeto com versão, metadados, entry points, arquivos e requisitos.

from importlib.metadata import distribution

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

Instâncias distintas de Distribution não comparam necessariamente como iguais, mesmo representando a mesma instalação. Compare atributos relevantes, como nome normalizado e versão.

Origem de instalações editáveis

Desde Python 3.13, a propriedade origin pode apresentar informações PEP 610 sobre a origem de pacotes editáveis.

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

Essas URLs podem conter caminhos locais. Remova ou normalize informações sensíveis em relatórios compartilhados.

Mapear imports para distribuições

packages_distributions() devolve listas porque namespace packages podem reunir partes de várias distribuições.

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

Esse mapeamento complementa modulefinder no Python, que segue imports a partir de um script, e pkgutil, que descobre módulos disponíveis.

Auditar o ambiente

Uma ferramenta pode listar distribuições e campos básicos.

from importlib.metadata import distributions

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

Ambientes grandes podem conter duplicatas aparentes, instalações editáveis e metadados incompletos. Limite a saída e registre a versão do Python e o ambiente virtual.

Gerar um inventário 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))

Não inclua descrições extensas e caminhos por padrão. Um Software Bill of Materials completo exige formatos e campos adicionais.

Verificar versão mínima

Uma aplicação pode confirmar que uma distribuição compatível está instalada, mas a comparação deve respeitar versionamento adequado.

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

if Version(version('meu-plugin')) < Version('2.0'):
    raise RuntimeError('Atualize meu-plugin')

packaging é uma dependência externa comum. Evite comparações lexicográficas como '10' < '2'.

Plugins com política de confiança

Descobrir entry points é conveniente, mas qualquer pacote instalado pode registrar um nome no grupo. A aplicação deve verificar distribuição fornecedora, versão, configuração e permissões.

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

for ep in entry_points(group='meu_app.plugins'):
    if ep.dist.name not in APROVADOS:
        continue
    carregar_plugin(ep)

Em ambientes sensíveis, fixe hashes e instale plugins em um ambiente controlado.

Metadados não provam integridade

Nome, versão e licença são declarações do pacote. Eles não garantem segurança, autenticidade ou compatibilidade. Combine metadados com fonte de instalação confiável, assinaturas, hashes e testes.

Distribuições em ZIP e providers customizados

Por padrão, o módulo encontra metadados em sistema de arquivos e ZIPs presentes em sys.path. Importers personalizados podem implementar find_distributions() e fornecer objetos Distribution.

Isso permite metadados em bancos ou sistemas virtuais, mas o provider precisa respeitar filtros de nome e caminho. Teste cuidadosamente a integração.

importlib.metadata e sys.path

A interpretação de sys.path não é idêntica à do import normal. Bytes são ignorados, enquanto objetos pathlib.Path podem ser aceitos incidentalmente.

Mantenha sys.path com strings normais e evite depender dessas diferenças. O artigo sobre sysconfig ajuda a construir caminhos de forma explícita.

Cache e mudanças no ambiente

Após instalar ou remover pacotes dentro de um processo ativo, resultados podem não refletir imediatamente todas as mudanças. Em produção, prefira criar o ambiente antes de iniciar os workers e reiniciá-los após atualizações.

Testar código baseado em metadados

Evite depender de todos os pacotes instalados na máquina do desenvolvedor. Use uma distribuição conhecida do ambiente de teste ou abstraia as funções.

def versao_instalada(nome, obter_versao=version):
    try:
        return obter_versao(nome)
    except PackageNotFoundError:
        return None

Injete uma função falsa para testar ausências, versões e formatos incomuns.

Erros frequentes

  • Confundir nome da distribuição com nome do import.
  • Comparar versões como strings simples.
  • Carregar todos os entry points sem validação.
  • Presumir que files() nunca retorna None.
  • Expor caminhos de instalações editáveis.
  • Tratar metadados como prova de integridade.
  • Depender da API antiga de entry points.

Boas práticas

  • Use nomes de distribuição nas consultas.
  • Trate PackageNotFoundError.
  • Use get_all() para campos repetidos.
  • Valide entry points antes de carregar.
  • Proteja caminhos e origens em relatórios.
  • Compare versões com ferramenta adequada.
  • Reinicie processos após mudanças no ambiente.

Conclusão

O importlib.metadata no Python oferece uma visão estruturada das distribuições instaladas: versões, requisitos, arquivos, metadados, entry points e relação com pacotes importáveis.

Use esses dados para diagnóstico, plugins e inventários, mas não confunda declaração com confiança. Consulte a documentação oficial do importlib.metadata e as especificações de Core Metadata da PyPA.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Desenvolvedor configurando servidor HTTPS e certificado TLS com Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crie servidor HTTPS local no Python

    Aprenda HTTPSServer no Python para servir HTTPS localmente, configurar certificados, usar threads e entender limites de segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    08/10/2026
    Arquivos protegidos representando extração segura de TAR com Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extraia TAR com segurança

    Aprenda tarfile extraction_filter no Python para extrair arquivos TAR com validação, segurança e controle de caminhos.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026
    Código Python exibindo avisos controlados com catch_warnings
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    catch_warnings: capture warnings em testes Python

    Aprenda catch_warnings no Python para capturar, testar e controlar avisos com filtros específicos e segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código Python representando referências persistentes do pickle
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pickle persistent_id: serialize referências externas

    Aprenda pickle persistent_id no Python para serializar referências externas com IDs estáveis, validação, segurança e compatibilidade.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código binário representando buffers e memória no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    memoryview.count: conte valores sem copiar buffers

    Aprenda memoryview.count no Python para contar bytes e valores em buffers sem cópias, com formatos, limites e boas práticas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python com anotações de tipos
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evite imports circulares em anotações

    Aprenda annotationlib no Python para ler anotações adiadas, evitar imports circulares e criar ferramentas de introspecção seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026