pkgutil no Python: descubra pacotes

Publicado em: 27/08/2026
Tempo de leitura: 7 minutos
A laptop screen showing a code editor with visible programming code in a dimly lit environment.

O módulo pkgutil oferece utilitários para trabalhar com o sistema de importação do Python. Ele pode listar módulos disponíveis em um conjunto de paths, percorrer subpacotes, localizar importers, ler recursos por meio de loaders e dar suporte a formas legadas de pacotes de namespace. É útil em descoberta de plugins, ferramentas de inspeção, registries automáticos, CLIs extensíveis e diagnósticos de importação.

Como a importação do Python é dinâmica, a descoberta precisa ser tratada com cuidado. Percorrer pacotes pode executar código de inicialização, loaders personalizados podem ter efeitos próprios e um nome encontrado não significa que o módulo seja seguro ou compatível. Prefira APIs modernas de importlib quando elas cobrirem o caso, mas entenda pkgutil porque ele ainda aparece em muitas bibliotecas.

Liste módulos com iter_modules

pkgutil.iter_modules() produz informações sobre módulos encontrados em paths.

import pkgutil

for info in pkgutil.iter_modules():
    print(info.name, info.ispkg)

Sem um path explícito, a função considera a busca de módulos de nível superior no ambiente atual.

ModuleInfo

Cada resultado contém o finder, o nome do módulo e um indicador de pacote.

for info in pkgutil.iter_modules():
    print(info.module_finder)
    print(info.name)
    print(info.ispkg)

O finder pode ser um objeto do sistema de importação com comportamento específico para diretórios, ZIPs ou loaders customizados.

Descubra dentro de um pacote

Para listar filhos, passe o __path__ do pacote e um prefixo.

import meu_pacote
import pkgutil

for info in pkgutil.iter_modules(
    meu_pacote.__path__,
    meu_pacote.__name__ + ".",
):
    print(info.name)

O prefixo produz nomes importáveis completos.

Nem todo módulo é pacote

O campo ispkg ajuda a distinguir um pacote que pode conter filhos de um módulo simples.

Não use apenas a extensão do arquivo. Loaders e módulos frozen podem não corresponder a um arquivo Python normal.

walk_packages

walk_packages() percorre recursivamente os pacotes encontrados.

for info in pkgutil.walk_packages(
    meu_pacote.__path__,
    meu_pacote.__name__ + ".",
):
    print(info.name)

Essa operação é mais poderosa e mais arriscada que iter_modules().

walk_packages pode importar pacotes

Para obter o __path__ de subpacotes, a função pode importá-los. O código de __init__.py pode executar registros, abrir conexões, ler variáveis e produzir outros side effects.

Não percorra uma árvore não confiável dentro de um processo privilegiado.

O parâmetro onerror

walk_packages() aceita uma função chamada quando um import falha.

def ao_erro(nome):
    erros.append(nome)

for info in pkgutil.walk_packages(
    pacote.__path__,
    pacote.__name__ + ".",
    onerror=ao_erro,
):
    processar(info)

A função recebe o nome do pacote problemático. Registre contexto e decida se a descoberta deve continuar.

Não esconda erros importantes

Uma falha de import pode significar dependência ausente, incompatibilidade de plataforma ou bug de inicialização.

Classifique plugins opcionais separadamente de componentes obrigatórios.

Descoberta de plugins

Um padrão simples procura módulos com um prefixo.

plugins = [
    info.name
    for info in pkgutil.iter_modules()
    if info.name.startswith("minhaapp_plugin_")
]

Descobrir um nome não deve importá-lo automaticamente sem validação e política.

Prefira entry points para plugins instalados

Entry points permitem que distribuições declarem plugins sem varrer todo o ambiente.

Use importlib.metadata.entry_points() para ecossistemas modernos. A varredura por nome ainda pode ser útil em sistemas simples ou legados.

Importe somente depois de selecionar

Depois de descobrir candidatos, filtre allowlists, configuração e versão antes de importar.

import importlib

modulo = importlib.import_module(nome_plugin)

Faça a importação em um boundary onde erros e side effects possam ser tratados.

get_importer

pkgutil.get_importer(path_item) retorna o finder/importer associado a uma entrada de path.

importer = pkgutil.get_importer("/opt/app/plugins")
print(importer)

Isso ajuda a diagnosticar por que um path é interpretado por um diretório, ZIP ou hook personalizado.

Cache de importers

O sistema de importação mantém caches relacionados a entradas de sys.path. Mudanças em diretórios e hooks podem exigir invalidação por APIs de importlib.

Não modifique caches internos diretamente.

iter_importers

iter_importers(fullname="") percorre finders que podem participar da busca por um módulo.

for finder in pkgutil.iter_importers("meu_pacote.modulo"):
    print(finder)

Em alguns casos, determinar importers de submódulos exige importar o pacote pai.

Meta path e path hooks

O sistema de importação usa sys.meta_path, sys.path_hooks e caches. pkgutil oferece uma visão conveniente sobre parte dessa infraestrutura.

Para implementar um loader moderno, use as abstrações de importlib.abc e importlib.machinery.

get_data

pkgutil.get_data(package, resource) solicita bytes de um recurso por meio do loader do pacote.

dados = pkgutil.get_data(
    "meu_pacote",
    "dados/config.json",
)

O retorno pode ser None quando o recurso não está disponível.

Recursos são bytes

Decodifique texto explicitamente.

if dados is None:
    raise FileNotFoundError("recurso ausente")
texto = dados.decode("utf-8")

Valide formato e tamanho antes de processar.

Prefira importlib.resources

Para código novo, importlib.resources possui uma API mais expressiva e funciona bem com recursos que não são arquivos físicos.

Esse módulo será o penúltimo tema deste lote.

Não monte paths com __file__

Um pacote pode estar em ZIP, frozen ou sob loader virtual. Construir Path(__file__).parent / recurso nem sempre funciona.

Use APIs de recursos para abstrair a origem.

extend_path

extend_path(path, name) suporta um modelo legado de pacotes distribuídos por vários diretórios.

from pkgutil import extend_path

__path__ = extend_path(__path__, __name__)

Esse padrão aparece em pacotes antigos de namespace.

Namespace packages modernos

PEP 420 permite namespace packages sem __init__.py. Para projetos novos, prefira o mecanismo moderno e uma configuração de packaging adequada.

Não adicione extend_path apenas por hábito.

Arquivos .pkg

O mecanismo legado pode considerar arquivos de configuração com extensão .pkg para estender paths.

Trate essas entradas como configuração sensível. Paths adicionais podem alterar quais módulos são importados.

Path hijacking

Adicionar diretórios graváveis por usuários ao início de sys.path permite que um módulo mal posicionado oculte dependências legítimas.

Valide roots de plugin, ownership e permissões antes da descoberta.

Nomes não são identidades

O mesmo nome pode ser encontrado em locais diferentes conforme a ordem de busca.

Registre origem, distribuição e versão antes de ativar um plugin.

Distribuição versus módulo

Um pacote importável não é necessariamente o nome da distribuição instalada.

Use importlib.metadata.packages_distributions() para mapear módulos de topo a distribuições.

Ambientes virtuais

Execute a descoberta dentro do venv correto. A lista de módulos do Python global pode ser completamente diferente.

Registre sys.executable e sys.path em diagnósticos.

ZIP e zipapp

iter_modules() pode cooperar com importers que implementam a extensão necessária. Nem todo finder customizado oferece listagem.

Teste descoberta em arquivos .pyz. Veja zipapp no Python.

Finders customizados

Para que iter_modules() funcione com um finder não padrão, ele precisa fornecer o protocolo esperado.

Documente limites do loader e não presuma que todos os módulos virtuais podem ser enumerados.

Descoberta não valida compatibilidade

Um módulo encontrado pode exigir outra versão, sistema, dependência nativa ou configuração.

Leia metadados e execute uma validação controlada antes de habilitar.

Importação preguiçosa

Guardar apenas nomes permite adiar imports até que o recurso seja necessário.

Isso reduz startup, mas desloca falhas para mais tarde. Ofereça uma etapa de health check que valide plugins obrigatórios.

Ordem determinística

A ordem retornada pode depender de filesystem e finder. Ordene por nome quando precisar de comportamento reproduzível.

infos = sorted(
    pkgutil.iter_modules(paths),
    key=lambda item: item.name,
)

Se prioridade fizer parte da política, declare-a em metadados em vez de depender da ordem de descoberta.

Duplicatas

Vários paths podem conter o mesmo nome. Deduplicate cuidadosamente e registre conflitos.

Falhar com uma mensagem clara é melhor que escolher silenciosamente quando a origem importa.

Escaneamento amplo

Varrer todo o sys.path pode ser lento e revelar módulos sem relação com a aplicação.

Restrinja a paths de plugin ou namespaces específicos.

Limites

Defina quantidade máxima de entradas, profundidade, tempo e tamanho dos recursos lidos.

Não faça descoberta recursiva ilimitada em diretórios enviados por usuários.

Isolamento

Como walk_packages() pode importar pacotes, execute descoberta de terceiros em processo separado com permissões reduzidas.

Um timeout protege contra inicializadores que travam.

Integração com modulefinder

modulefinder tenta descobrir dependências a partir do código; pkgutil enumera módulos oferecidos por importers.

Veja modulefinder no Python.

Integração com importlib.metadata

Depois de descobrir um nome, obtenha distribuição, versão e entry points com metadados instalados.

Não importe um plugin apenas para perguntar sua versão.

Testes

Teste diretórios, ZIPs, namespace packages, módulos simples, pacotes, duplicatas, loaders customizados, recursos ausentes, erro durante import e diferentes venvs.

Use pacotes de fixture pequenos e restaure sys.path depois de cada teste.

Erros comuns

Os erros mais frequentes são percorrer pacotes sem considerar side effects, varrer todo o ambiente, confiar na ordem do filesystem, usar extend_path em projetos novos, confundir módulo e distribuição, construir recurso com __file__ e importar todo candidato automaticamente.

Conclusão

pkgutil reúne ferramentas práticas para enumerar módulos, percorrer pacotes, localizar importers e ler recursos por loaders. Use iter_modules() para descoberta limitada e walk_packages() apenas quando aceitar as importações necessárias.

Prefira entry points e APIs modernas de importlib em novos sistemas, restrinja paths e isole plugins. Consulte a documentação oficial de pkgutil e symtable no Python para análise de nomes sem importar módulos.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    modulefinder no Python: descubra imports

    Aprenda modulefinder no Python para descobrir imports, dependências transitivas, módulos ausentes, paths, plugins e limitações da análise estática.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026
    Vivid close-up of code on a computer screen showcasing programming details.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    py_compile no Python: compile um arquivo

    Aprenda py_compile no Python para compilar um arquivo, controlar .pyc, dfile, otimização, invalidação por hash e erros de build.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    Detailed view of programming code in a dark theme on a computer screen.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    compileall no Python: gere bytecode .pyc

    Aprenda compileall no Python para gerar .pyc, validar sintaxe, compilar em paralelo, controlar otimização, paths e builds reproduzíveis.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026
    A classic MS-DOS terminal screen displayed on a laptop keyboard with vivid illumination.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    codeop no Python: compile comandos interativos

    Aprenda codeop no Python para detectar comandos completos, incompletos ou inválidos, criar REPLs e preservar flags de __future__ com segurança.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    Detailed view of programming code in a dark theme on a computer screen.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    linecache no Python: leia linhas do código

    Aprenda linecache no Python para recuperar linhas de código, atualizar cache, integrar tracebacks, lidar com loaders e proteger caminhos.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    faulthandler no Python: diagnostique crashes

    Aprenda faulthandler no Python para diagnosticar crashes, deadlocks, timeouts, sinais fatais e travamentos com dumps de todas as threads.

    Ler mais

    Tempo de leitura: 10 minutos
    27/08/2026