El módulo modulefinder analiza un script Python e intenta descubrir los módulos importados directa y transitivamente. Inspecciona code objects, sigue instrucciones de importación, consulta paths configurados y construye un inventario útil para packagers, auditorías, herramientas de build, informes de dependencias y diagnóstico de imports ausentes.
El análisis no es completo. Python permite imports dinámicos, plugins, ejecución condicional, cambios de sys.path y nombres construidos en runtime. Trata el resultado como una aproximación estática basada en el código disponible, no como prueba de todo lo que la aplicación cargará.
Crea un ModuleFinder
La clase principal es modulefinder.ModuleFinder.
from modulefinder import ModuleFinder
finder = ModuleFinder()
finder.run_script("app.py")
Después del análisis, el objeto contiene módulos encontrados, referencias ausentes y datos para informes.
Lista los módulos encontrados
El atributo modules mapea nombres a objetos analizados.
for nombre in sorted(finder.modules):
modulo = finder.modules[nombre]
print(nombre, modulo.__file__)
No todos poseen archivo normal. Builtins, extensiones, namespaces y loaders especiales pueden usar representaciones diferentes.
Usa report
report() imprime un resumen legible.
finder.report()
Es cómodo para investigación manual. En automatización, recorre atributos y genera JSON u otro formato estructurado.
Imports directos y transitivos
Al analizar un script, modulefinder sigue imports de los módulos descubiertos. El inventario incluye dependencias transitivas, no solo líneas del entry point.
Un import aparentemente pequeño puede traer un árbol grande.
Configura el path
El constructor acepta un path con directorios de búsqueda.
import sys
from modulefinder import ModuleFinder
finder = ModuleFinder(path=["src", *sys.path])
finder.run_script("src/app.py")
Usa el mismo entorno y layout de runtime. Un path distinto puede elegir otro paquete con el mismo nombre.
Entornos virtuales
Ejecuta dentro del venv con las dependencias reales. Mezclar paths globales y del proyecto produce resultados engañosos.
Registra sys.executable, versión y paths utilizados.
Layout src
Los proyectos con paquetes bajo src/ necesitan incluir esa raíz o instalar el paquete.
Analizar la distribución instalada reproduce mejor namespaces, metadatos y comportamiento de importación.
Imports relativos
Los imports relativos dependen del contexto del paquete. Ejecutar un módulo interno como script puede cambiar el significado o fallar.
Analiza el entry point real y la estructura correcta.
Imports condicionales
Un import dentro de un if puede detectarse aunque la condición no sea verdadera en la plataforma actual.
if sys.platform == "win32":
import winreg
El informe puede incluir dependencias opcionales de otros sistemas. Clasifícalas en lugar de eliminarlas ciegamente.
Imports opcionales con try/except
Las bibliotecas suelen intentar un acelerador y usar fallback.
try:
import acelerador
except ImportError:
import implementacion_python
El análisis puede listar ambos o marcar uno ausente. No significa automáticamente que la aplicación esté rota.
Imports dinámicos
importlib.import_module(nombre) puede recibir un valor conocido solo en runtime.
backend = importlib.import_module(config["backend"])
Las herramientas estáticas quizá no determinen el nombre. Los packagers suelen requerir hidden imports explícitos.
El builtin __import__
__import__() también puede cargar nombres calculados.
Revisa configuración, registries y convenciones de plugins además del informe.
Sistemas de plugins
Los plugins pueden descubrirse mediante entry points, directorios, bases o configuración, sin import directo.
Combina modulefinder con importlib.metadata.entry_points(), tema posterior de este lote.
Namespace packages
Un namespace package puede abarcar varios directorios y distribuciones. Ejecuta la herramienta en el entorno instalado completo.
No supongas que un único __file__ representa todo el namespace.
Extensiones nativas
Los módulos compilados pueden aparecer como .so, .pyd o equivalentes.
Modulefinder identifica el módulo, pero no enumera automáticamente bibliotecas nativas cargadas por él.
Módulos built-in
Los módulos integrados en el intérprete no tienen archivo Python común.
Un packager debe clasificarlos como parte del runtime.
Módulos frozen
Los ejecutables congelados pueden incluir módulos internamente. La representación depende del runtime y packager.
Prueba el artefacto final porque el análisis de desarrollo puede diferir.
badmodules
El finder mantiene nombres que no pudieron localizarse en ciertos contextos.
Un informe útil muestra qué módulos intentaron cada import. Un nombre ausente puede ser opcional para un paquete y obligatorio para otro.
any_missing
Métodos de conveniencia devuelven nombres considerados ausentes.
faltantes = finder.any_missing()
print(faltantes)
Revisa cada nombre antes de fallar el build, especialmente imports opcionales y de plataforma.
Ausentes posibles y definidos
Versiones compatibles pueden separar faltantes definitivos y posibles.
La clasificación ayuda a priorizar, pero sigue siendo heurística.
Excludes
El constructor acepta una lista de exclusión.
finder = ModuleFinder(
excludes=["tkinter", "tests"],
)
Excluir indica que el análisis debe ignorar el módulo; no prueba que la aplicación nunca lo solicite.
Documenta exclusiones
Explica si cada módulo pertenece a otra plataforma, feature desactivada, herramienta de desarrollo o implementación alternativa.
Añade un test que confirme que el camino excluido no se alcanza.
replace_paths
replace_paths reemplaza prefijos en filenames registrados.
Esto hace informes reproducibles y evita paths temporales de CI.
Privacidad de paths
Los inventarios pueden revelar usernames, home directories y estructura interna.
Normaliza paths antes de compartir y restringe acceso.
Debug
El argumento debug aumenta logging interno.
finder = ModuleFinder(debug=2)
Úsalo localmente. Logs verbosos de CI pueden exponer paths y dificultar búsquedas.
run_script y load_file
run_script() analiza un script ejecutable; APIs relacionadas pueden cargar archivos en otros contextos.
Elige la operación que represente si el target es entry point o módulo de paquete.
Análisis basado en bytecode
Modulefinder examina code objects e instrucciones de importación, por lo que depende de detalles del compilador.
Ejecuta con la misma versión de Python del runtime objetivo.
Inspecciona con dis
Si un import se clasifica de forma inesperada, dis muestra las instrucciones generadas.
Consulta dis en Python.
Código no alcanzable
El análisis puede encontrar imports en funciones nunca llamadas, branches muertos y compatibilidad opcional.
Describe dependencias sintácticas posibles, no frecuencia ni reachability.
Combina análisis estático y dinámico
Registra módulos cargados durante tests representativos y compáralos con el inventario.
Los tests dinámicos omiten features no ejecutadas; el análisis estático omite nombres calculados. Juntos reducen huecos.
Auditoría de dependencias
El inventario revela módulos transitivos, pero no ofrece automáticamente distribución, versión, licencia o vulnerabilidad.
Mapea módulos a distribuciones con importlib.metadata.packages_distributions().
Standard library y terceros
Clasifica por origen: builtin, biblioteca estándar, proyecto y site-packages.
Usa sysconfig para ubicar la standard library. Consulta sysconfig en Python.
Shadowing
Varios directorios pueden proporcionar el mismo nombre. El orden define cuál se selecciona.
Registra el archivo elegido. Un json.py local puede ocultar la biblioteca estándar.
Imports desde ZIP
Las dependencias pueden venir de ZIP en sys.path. Confirma soporte del loader.
No supongas que cada módulo corresponde a un path normal.
Varios entry points
Un proyecto puede tener CLI, servidor web, worker y tareas con árboles diferentes.
Analiza cada entry point y une resultados conservando qué target requiere cada módulo.
Perfiles opcionales
Crea perfiles mínimo, GUI, cloud, base específica o datos.
Una lista global puede añadir dependencias grandes a artefactos que no las usan.
Salida estructurada
Convierte el resultado en una representación estable.
resultado = {
nombre: {"archivo": modulo.__file__}
for nombre, modulo in finder.modules.items()
}
Ordena claves para diffs reproducibles.
Grafos de dependencias
El mapping no siempre expone todas las aristas listo para visualizar.
Instrumenta la herramienta o combina AST. Usa graphlib en Python para orden topológico cuando corresponda.
Ciclos de import
Python permite algunos ciclos, pero el orden puede exponer módulos parcialmente inicializados.
Usa el inventario como señal y prueba imports en un proceso limpio.
Import hooks personalizados
Loaders e hooks pueden tener comportamiento especial.
Ejecuta el análisis en entorno aislado para proyectos que no controlas.
Límites de recursos
Árboles grandes consumen tiempo y memoria. Limita archivos, tamaño y duración.
Cachea por hash del entorno y entry point cuando el análisis se repite.
Proyectos subidos
Un servicio debería usar worker separado, filesystem temporal y permisos reducidos.
Valida archives antes de extraer e impide paths que escapen de la raíz.
Comparaciones en CI
Una pipeline puede comparar el inventario con una baseline revisada.
finder = ModuleFinder(path=paths)
finder.run_script(entrypoint)
nombres = sorted(finder.modules)
Solicita revisión para cambios significativos, no por cada diferencia de plataforma.
Pruebas
Cubre imports absolutos, relativos, condicionales, opcionales, dinámicos, namespace packages, extensiones, ZIP, faltantes, shadowing y varios entry points.
Ejecuta en todos los sistemas soportados.
Errores comunes
Los fallos frecuentes son tratar el resultado como completo, ignorar plugins dinámicos, usar el venv equivocado, analizar un módulo interno como script, fallar por opcionales, excluir sin tests, confundir módulo con distribución y no probar el artefacto.
Conclusión
modulefinder construye un inventario útil de imports directos y transitivos. Configura el path correcto, analiza cada entry point, revisa faltantes y añade información de plugins y runtime.
Trata la salida como aproximación y prueba la aplicación empaquetada. Consulta la documentación oficial de modulefinder y symtable en Python para análisis estático de nombres.







