modulefinder no Python: analise imports

Publicado em: 13/08/2026
Tempo de leitura: 7 minutos
Rede de código binário representando o grafo de imports analisado com modulefinder no Python

O módulo modulefinder no Python analisa um script e tenta descobrir quais módulos ele importa. O resultado pode ajudar na auditoria de dependências, na preparação de pacotes, na investigação de erros de import e na geração de relatórios para ferramentas internas.

Ele trabalha examinando o código e seguindo imports encontrados durante a análise. Isso é diferente de executar toda a aplicação em produção. Imports construídos dinamicamente, plugins descobertos por configuração, chamadas a importlib.import_module() e módulos carregados por caminhos especiais podem não aparecer. Portanto, o relatório deve ser tratado como evidência útil, não como inventário absoluto.

Primeiro relatório com ModuleFinder

A classe principal é modulefinder.ModuleFinder. O método run_script() recebe o caminho de um arquivo Python, e report() imprime os módulos encontrados.

from modulefinder import ModuleFinder

finder = ModuleFinder()
finder.run_script('aplicacao.py')
finder.report()

O relatório inclui módulos encontrados, caminhos e itens ausentes ou aparentemente ausentes. Em automações maiores, você pode preferir acessar os dicionários internos e gerar JSON.

Ler o dicionário modules

finder.modules mapeia nomes para objetos que representam os módulos analisados.

from modulefinder import ModuleFinder

finder = ModuleFinder()
finder.run_script('aplicacao.py')

for nome, modulo in sorted(finder.modules.items()):
    print(nome, modulo.__file__)

Alguns módulos internos ou built-ins podem não possuir arquivo físico. Trate None como um caso legítimo. Para entender caminhos de instalação e bibliotecas, consulte sysconfig no Python.

Detectar módulos ausentes

Itens problemáticos aparecem em badmodules. Eles podem representar erros reais, imports opcionais protegidos por try/except ImportError, dependências específicas de plataforma ou falsos positivos.

ausentes = sorted(finder.badmodules)
for nome in ausentes:
    print('Possivelmente ausente:', nome)

Não falhe o build automaticamente por qualquer entrada. Classifique dependências obrigatórias e opcionais, considere sistema operacional e confirme o resultado em um ambiente limpo.

Analisar imports opcionais

Bibliotecas frequentemente tentam importar aceleradores, backends ou módulos exclusivos de uma plataforma.

try:
    import uvloop
except ImportError:
    uvloop = None

O analisador pode registrar o módulo como ausente mesmo quando a aplicação possui um fallback válido. Mantenha uma política documentada de exceções, em vez de simplesmente esconder todos os avisos.

Definir caminhos de busca

O construtor aceita uma lista path. Quando omitida, usa sys.path.

from modulefinder import ModuleFinder

finder = ModuleFinder(path=[
    '/projeto/src',
    '/projeto/vendor',
])
finder.run_script('/projeto/src/app.py')

Use caminhos absolutos e controlados. Incluir o diretório atual de forma indiscriminada pode fazer a análise encontrar módulos errados com o mesmo nome de dependências legítimas.

Excluir módulos conhecidos

O parâmetro excludes evita a análise de nomes específicos.

finder = ModuleFinder(
    excludes=['tkinter', 'tests', 'devtools'],
)

Exclusões podem acelerar o processo e remover dependências opcionais conhecidas. Porém, uma lista excessiva pode esconder uma dependência real. Registre a justificativa de cada item.

Substituir caminhos em relatórios

replace_paths recebe pares de caminho antigo e novo. Isso é útil para remover caminhos locais de relatórios e criar resultados reprodutíveis.

finder = ModuleFinder(
    replace_paths=[
        ('/home/ana/projeto', '<PROJECT>'),
        ('/opt/build/venv', '<VENV>'),
    ]
)

Além de melhorar comparação entre builds, a substituição evita vazar nomes de usuários e estrutura interna em logs compartilhados.

Adicionar caminho a um pacote

AddPackagePath() informa que um pacote pode ser localizado em outro diretório.

import modulefinder

modulefinder.AddPackagePath(
    'meu_plugin',
    '/opt/plugins/meu_plugin',
)

Use isso apenas para layouts conhecidos. Se o caminho vier de entrada externa, valide e restrinja a uma raiz aprovada.

Substituir um módulo por pacote

ReplacePackage(oldname, newname) informa que um nome deve ser tratado como outro pacote. É uma ferramenta especializada para compatibilidade e layouts incomuns.

Documente a substituição, porque o relatório pode se tornar confuso para quem não conhece a regra. Prefira corrigir a estrutura de pacotes quando você controla o código.

Executar modulefinder pela linha de comando

O próprio arquivo pode ser usado como script para produzir um relatório de imports. A API costuma ser melhor para automações, pois permite filtrar e estruturar a saída.

Em um pipeline, salve o relatório como artefato e compare mudanças entre versões. Uma dependência nova inesperada pode indicar crescimento do pacote, mudança arquitetural ou import acidental.

Gerar JSON estruturado

import json
from modulefinder import ModuleFinder

finder = ModuleFinder()
finder.run_script('app.py')

dados = {
    'modules': {
        nome: getattr(modulo, '__file__', None)
        for nome, modulo in sorted(finder.modules.items())
    },
    'missing': sorted(finder.badmodules),
}

with open('imports.json', 'w', encoding='utf-8') as arquivo:
    json.dump(dados, arquivo, ensure_ascii=False, indent=2)

Não inclua caminhos sensíveis sem normalização. Também limite o tamanho do relatório em repositórios muito grandes.

Comparar duas versões

Um caso prático é identificar módulos adicionados ou removidos.

antes = set(relatorio_antigo['modules'])
depois = set(relatorio_novo['modules'])

print('Adicionados:', sorted(depois - antes))
print('Removidos:', sorted(antes - depois))

A diferença não prova que o código executa esses módulos em todas as rotas. Ela mostra mudanças na análise estática do script e seus imports alcançáveis.

Imports dinâmicos escapam

O analisador não pode prever todos os nomes construídos em runtime.

from importlib import import_module

nome = configuracao['backend']
backend = import_module(f'meu_app.backends.{nome}')

Para esse padrão, mantenha um manifesto explícito de plugins ou combine a análise com testes que exercitam configurações suportadas. O guia de importlib.resources ajuda com recursos, mas descoberta dinâmica de módulos exige uma estratégia própria.

Entry points e plugins

Plugins distribuídos por metadados podem ser descobertos sem imports literais no código principal. Uma análise de modulefinder provavelmente não os incluirá.

Consulte os entry points instalados e adicione os pacotes esperados ao inventário. Mais adiante neste lote, o módulo importlib.metadata é uma ferramenta adequada para essa tarefa.

Dependências condicionais por plataforma

import sys

if sys.platform == 'win32':
    import winreg
else:
    import pwd

O resultado pode variar conforme o ambiente de análise. Execute a ferramenta em cada plataforma suportada ou mantenha uma matriz de dependências condicionais.

Ambientes virtuais

A análise usa os caminhos disponíveis no processo. Rode-a no mesmo ambiente virtual usado pelo build ou teste.

Registre a versão de Python, sys.path normalizado e dependências instaladas. Sem esse contexto, dois relatórios podem divergir por razões externas ao código.

Integração com zipapp

Antes de criar um arquivo com zipapp no Python, um relatório pode ajudar a identificar dependências puramente Python que precisam ser copiadas para o diretório de build.

Não use o resultado automaticamente para copiar qualquer arquivo encontrado. Filtre bibliotecas padrão, pacotes nativos, arquivos externos e licenças. A lista é ponto de partida, não uma receita segura de empacotamento.

Integração com compileall

compileall verifica sintaxe e gera bytecode; modulefinder mapeia imports. Usados juntos, eles cobrem problemas diferentes.

Um projeto pode compilar perfeitamente e ainda falhar por módulo ausente. Também pode importar tudo corretamente e conter erro sintático em um arquivo nunca alcançado pela análise.

Nível de debug

O parâmetro debug aumenta mensagens internas.

finder = ModuleFinder(debug=2)
finder.run_script('app.py')

Use níveis altos apenas em diagnóstico. A saída pode ser extensa e conter caminhos locais. Redirecione para um arquivo protegido e aplique retenção curta.

Desempenho e limites

Projetos com muitos imports podem exigir tempo e memória consideráveis. Defina timeout no processo externo, limite o tamanho dos scripts e execute em worker isolado quando analisar código recebido de terceiros.

Embora a ferramenta não execute a aplicação normalmente, analisar arquivos desconhecidos ainda pode expor o pipeline a consumo excessivo ou bugs no parser. Não processe repositórios arbitrários com privilégios elevados.

Teste do relatório

Crie fixtures pequenas com import obrigatório, opcional, relativo, condicional e dinâmico. Verifique o que aparece em modules e badmodules.

def test_dependencia_basica(tmp_path):
    script = tmp_path / 'app.py'
    script.write_text('import json\n', encoding='utf-8')

    finder = ModuleFinder()
    finder.run_script(str(script))
    assert 'json' in finder.modules

Não escreva testes dependentes de toda a biblioteca padrão do sistema; foque nos módulos relevantes ao seu projeto.

Erros frequentes

  • Tratar o relatório como inventário perfeito.
  • Ignorar imports dinâmicos e entry points.
  • Falhar por qualquer import opcional ausente.
  • Executar a análise em ambiente diferente do build.
  • Vazar caminhos locais em relatórios.
  • Copiar automaticamente todos os módulos encontrados.
  • Não testar plataformas diferentes.

Boas práticas

  • Use post_status any e ambientes reproduzíveis nas automações do site.
  • Normalize caminhos antes de salvar relatórios.
  • Classifique dependências obrigatórias e opcionais.
  • Combine análise estática com testes de execução.
  • Mantenha manifesto para plugins dinâmicos.
  • Compare relatórios entre releases.
  • Execute código de terceiros em ambiente isolado.

Conclusão

O modulefinder no Python ajuda a enxergar a rede de imports alcançável a partir de um script. Ele identifica módulos carregáveis, caminhos e itens ausentes, oferecendo dados úteis para auditoria, diagnóstico e empacotamento.

Use o resultado com contexto. Imports dinâmicos, plugins e condições de plataforma exigem verificações adicionais. Consulte a documentação oficial do modulefinder e a referência do sistema de imports.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    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
    Terminal interativo representando um REPL customizado com o módulo code no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    code no Python: crie um REPL customizado

    Aprenda o módulo code no Python para criar REPLs customizados, controlar namespaces, prompts, saída, blocos incompletos e encerramento seguro.

    Ler mais

    Tempo de leitura: 6 minutos
    12/08/2026
    Código de aplicação web representando WSGI com wsgiref no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    wsgiref no Python: aplicações WSGI

    Aprenda wsgiref no Python para criar e validar aplicações WSGI, testar environ, headers, rotas e servidores locais sem usar em

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Protocolo seguro na internet representando preparação Unicode com stringprep no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    stringprep no Python: prepare Unicode

    Aprenda stringprep no Python para aplicar tabelas do RFC 3454, mapear Unicode, bloquear caracteres proibidos e validar regras bidirecionais.

    Ler mais

    Tempo de leitura: 7 minutos
    12/08/2026