modulefinder en Python: analiza imports

Publicado el: 13/08/2026
Tempo de leitura: 6 minutos
Red de código binario que representa el grafo de imports analizado con modulefinder en Python

El módulo modulefinder en Python analiza un script e intenta determinar qué módulos importa. El resultado puede ayudar en auditorías de dependencias, preparación de paquetes, diagnóstico de errores de import y generación de informes para herramientas internas.

La herramienta examina el código y sigue imports encontrados durante el análisis. Esto no equivale a ejecutar todas las rutas posibles de la aplicación. Imports construidos dinámicamente, plugins descubiertos por configuración, llamadas a importlib.import_module() y hooks personalizados pueden no aparecer. El informe es evidencia útil, no un inventario perfecto.

Primer informe con ModuleFinder

La clase principal es modulefinder.ModuleFinder. run_script() recibe un archivo Python y report() imprime un resumen.

from modulefinder import ModuleFinder

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

El informe contiene módulos descubiertos, rutas e imports ausentes o aparentemente ausentes. En automatizaciones, conviene acceder a los mappings y generar JSON.

Leer el mapping modules

finder.modules asocia nombres con objetos que representan los módulos analizados.

from modulefinder import ModuleFinder

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

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

Los módulos built-in o internos pueden no tener archivo físico. Trata None como un caso válido. Para comprender rutas de instalación, consulta sysconfig en Python.

Detectar módulos ausentes

Los elementos problemáticos aparecen en badmodules. Pueden ser fallos reales, imports opcionales protegidos por try/except ImportError, módulos específicos de plataforma o falsos positivos.

for nombre in sorted(finder.badmodules):
    print('Posiblemente ausente:', nombre)

No hagas fallar el build automáticamente por cualquier entrada. Clasifica dependencias obligatorias y opcionales, considera la plataforma y verifica en un entorno limpio.

Imports opcionales

Muchas bibliotecas intentan cargar aceleradores, backends o integraciones específicas.

try:
    import uvloop
except ImportError:
    uvloop = None

El analizador puede marcar uvloop como ausente aunque exista un fallback válido. Mantén una lista documentada de excepciones en lugar de ignorar todos los avisos.

Personalizar rutas de búsqueda

El constructor acepta una lista path. Si se omite, utiliza sys.path.

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

Usa rutas absolutas y controladas. Añadir indiscriminadamente el directorio actual puede hacer que archivos locales oculten dependencias legítimas.

Excluir módulos conocidos

El argumento excludes evita analizar nombres seleccionados.

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

Las exclusiones pueden acelerar el proceso y eliminar árboles opcionales conocidos, pero una lista excesiva oculta dependencias reales. Registra una justificación por elemento.

Normalizar rutas del informe

replace_paths recibe pares (antigua, nueva).

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

La normalización facilita comparar máquinas y evita filtrar nombres de usuario o estructuras internas.

Añadir una ruta de paquete

AddPackagePath() registra otra ubicación para un paquete.

import modulefinder

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

Úsalo solo para layouts conocidos. Si la ruta procede de configuración, resuélvela y limítala a una raíz aprobada.

Reemplazar módulo por paquete

ReplacePackage(oldname, newname) indica que un nombre debe tratarse como otro paquete. Es una función especializada para compatibilidad y estructuras inusuales.

Documenta cada reemplazo. Los informes se vuelven confusos cuando quien los lee no conoce la regla. Si controlas el código, prefiere corregir la estructura.

Usar la línea de comandos

El módulo también puede ejecutarse como script y recibir un archivo Python. La API suele ser mejor en pipelines porque permite filtrar, normalizar y estructurar la salida.

Guarda el informe como artefacto y compáralo entre releases. Una dependencia inesperada puede revelar crecimiento arquitectónico, un import accidental o un cambio de empaquetado.

Generar JSON

import json
from modulefinder import ModuleFinder

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

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

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

Normaliza rutas sensibles antes de escribir y limita el tamaño en grafos enormes.

Comparar versiones

antes = set(informe_anterior['modules'])
despues = set(informe_nuevo['modules'])

print('Añadidos:', sorted(despues - antes))
print('Eliminados:', sorted(antes - despues))

La diferencia refleja alcanzabilidad estática desde el entry point. No prueba que todos los módulos se utilicen en cada ejecución.

Imports dinámicos

from importlib import import_module

nombre = configuracion['backend']
backend = import_module(f'mi_app.backends.{nombre}')

El nombre final no aparece como import literal. Mantén un manifiesto de plugins o combina modulefinder con pruebas de configuraciones soportadas. importlib.resources resuelve recursos empaquetados, no descubrimiento dinámico.

Entry points y plugins

Los plugins instalados pueden descubrirse por metadatos de distribución sin imports literales en el código principal. Modulefinder probablemente no los incluirá.

Consulta entry points instalados y añade los paquetes esperados al inventario. importlib.metadata es la herramienta estándar adecuada.

Imports condicionales por plataforma

import sys

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

El informe depende del entorno de análisis. Ejecuta la herramienta en cada plataforma soportada o mantén una matriz documentada.

Entornos virtuales

El analizador utiliza las rutas del proceso actual. Ejecútalo en el mismo entorno virtual usado para pruebas o empaquetado.

Registra versión de Python, sys.path normalizado y conjunto de dependencias. Sin contexto, dos informes pueden diferir por motivos externos al código.

Integración con zipapp

Antes de crear un artefacto con zipapp en Python, el informe puede sugerir dependencias puramente Python que deben copiarse al directorio de build.

No copies automáticamente todo lo encontrado. Filtra biblioteca estándar, extensiones nativas, rutas externas, datos y licencias. El informe es un punto de partida.

Integración con compileall

compileall en Python verifica sintaxis y genera bytecode; modulefinder mapea imports. Cubren fallos distintos.

Un proyecto puede compilar y fallar por dependencia ausente. También puede importar correctamente y contener un error sintáctico en un archivo no alcanzado.

Salida de debug

El parámetro debug aumenta los mensajes internos.

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

Los niveles altos pueden producir logs extensos con rutas locales. Guárdalos en ubicaciones protegidas y con retención corta.

Rendimiento y aislamiento

Grafos grandes consumen tiempo y memoria. Aplica timeout externo, limita tamaño del repositorio y usa un worker aislado para proyectos de terceros.

Aunque la herramienta no ejecuta normalmente toda la aplicación, código desconocido puede estresar parsers y lógica de análisis. No uses privilegios elevados.

Probar la capa de informes

Crea fixtures con imports obligatorios, opcionales, relativos, condicionales y dinámicos.

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

Prueba módulos relevantes al proyecto y evita depender del grafo completo de la biblioteca estándar.

Errores frecuentes

  • Tratar el informe como inventario perfecto.
  • Ignorar imports dinámicos y entry points.
  • Fallar por cualquier módulo opcional ausente.
  • Analizar en un entorno diferente al build.
  • Filtrar rutas locales en informes.
  • Copiar automáticamente todo lo descubierto.
  • Probar una sola plataforma.

Buenas prácticas

  • Usa entornos reproducibles.
  • Normaliza rutas antes de guardar.
  • Clasifica dependencias obligatorias y opcionales.
  • Combina análisis estático con pruebas runtime.
  • Mantén manifiestos para plugins dinámicos.
  • Compara informes entre releases.
  • Aísla código de terceros.

Conclusión

modulefinder en Python revela el grafo de imports alcanzable desde un script, incluyendo rutas descubiertas y módulos potencialmente ausentes. Es útil para auditorías, diagnóstico y preparación de paquetes.

Interpreta la salida con contexto. Imports dinámicos, plugins y condiciones de plataforma requieren comprobaciones adicionales. Consulta la documentación oficial de modulefinder y la referencia del sistema de imports.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Archivadores organizados que representan aplicaciones empaquetadas en archivos .pyz con zipapp en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    zipapp en Python: crea ejecutables .pyz

    Aprende zipapp en Python para empaquetar aplicaciones en archivos .pyz, definir entry points, incluir dependencias y distribuir con seguridad.

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026
    Editor de código que representa autocompletado de REPL con rlcompleter en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    rlcompleter en Python: autocompletar REPL

    Aprende rlcompleter en Python para añadir autocompletado a REPLs, consolas y editores, controlar namespaces y evitar efectos secundarios.

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026
    Ventana de terminal que representa una consola interactiva creada con cmd en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    cmd en Python: crea consolas interactivas

    Aprende cmd en Python para crear consolas interactivas con comandos, ayuda, historial, autocompletado, pruebas y control seguro de acciones.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Terminal interactivo que representa un REPL personalizado creado con el módulo code en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    code en Python: crea un REPL personalizado

    Aprende el módulo code en Python para crear REPLs personalizados, controlar namespaces, prompts, salida, bloques incompletos y cierre local.

    Ler mais

    Tempo de leitura: 6 minutos
    12/08/2026
    Código de aplicación web que representa WSGI con wsgiref en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    wsgiref en Python: aplicaciones WSGI

    Aprende wsgiref en Python para crear y validar aplicaciones WSGI, probar environ y headers, enrutar solicitudes y ejecutar un servidor

    Ler mais

    Tempo de leitura: 4 minutos
    12/08/2026
    Protocolo seguro de Internet que representa preparación Unicode con stringprep en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    stringprep en Python: prepara Unicode

    Aprende stringprep en Python para aplicar tablas RFC 3454, mapear Unicode, rechazar caracteres prohibidos y validar reglas bidireccionales.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026