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

    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
    Código Python em tela representando inspeção de módulos e pacotes
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    inspect.ispackage: identifique pacotes Python

    Aprenda inspect.ispackage no Python para identificar pacotes, explorar módulos e criar ferramentas de introspecção seguras.

    Ler mais

    Tempo de leitura: 5 minutos
    05/10/2026