importlib.metadata no Python: pacotes

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

    Código em execução representando módulos e caminhos executados com runpy no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    runpy no Python: execute módulos

    Aprenda runpy no Python para executar módulos, scripts, diretórios e arquivos ZIP, controlar namespaces e evitar problemas de segurança e

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026
    Pacote de software representando descoberta de módulos com pkgutil no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pkgutil no Python: descubra pacotes

    Aprenda pkgutil no Python para descobrir módulos, percorrer pacotes, resolver objetos, estender caminhos e acessar recursos com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026
    Rede de código binário representando o grafo de imports analisado com modulefinder no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    modulefinder no Python: analise imports

    Aprenda modulefinder no Python para mapear imports, detectar módulos ausentes, personalizar caminhos e auditar dependências com limites claros.

    Ler mais

    Tempo de leitura: 7 minutos
    13/08/2026
    Pastas organizadas representando aplicações empacotadas em arquivos .pyz com zipapp no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    zipapp no Python: crie executáveis .pyz

    Aprenda zipapp no Python para empacotar aplicações em arquivos .pyz, definir entry points, incluir dependências e distribuir com segurança.

    Ler mais

    Tempo de leitura: 7 minutos
    13/08/2026
    Editor de código representando autocompletar em REPL com rlcompleter no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    rlcompleter no Python: autocompletar REPL

    Aprenda rlcompleter no Python para adicionar autocompletar a REPLs, consoles e editores, controlar namespaces e evitar efeitos colaterais.

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026
    Janela de terminal representando console interativo criado com cmd no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    cmd no Python: crie consoles interativos

    Aprenda cmd no Python para criar consoles interativos com comandos, ajuda, histórico, autocompletar, testes e controle seguro de ações.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026